]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #100030 - WaffleLapkin:nice_pointer_sis, r=scottmcm
authorDylan DPC <99973273+Dylan-DPC@users.noreply.github.com>
Fri, 12 Aug 2022 15:09:10 +0000 (20:39 +0530)
committerGitHub <noreply@github.com>
Fri, 12 Aug 2022 15:09:10 +0000 (20:39 +0530)
cleanup code w/ pointers in std a little

Use pointer methods (`byte_add`, `null_mut`, etc) to make code in std a little nicer.

1439 files changed:
.github/workflows/ci.yml
.gitmodules
Cargo.lock
README.md
RELEASES.md
compiler/rustc_apfloat/src/ppc.rs
compiler/rustc_arena/src/lib.rs
compiler/rustc_ast/src/ast.rs
compiler/rustc_ast/src/mut_visit.rs
compiler/rustc_ast/src/util/comments.rs
compiler/rustc_ast/src/util/parser.rs
compiler/rustc_ast/src/visit.rs
compiler/rustc_ast_lowering/src/expr.rs
compiler/rustc_ast_lowering/src/index.rs
compiler/rustc_ast_lowering/src/item.rs
compiler/rustc_ast_lowering/src/lib.rs
compiler/rustc_ast_lowering/src/lifetime_collector.rs [new file with mode: 0644]
compiler/rustc_ast_passes/src/ast_validation.rs
compiler/rustc_ast_passes/src/feature_gate.rs
compiler/rustc_ast_passes/src/node_count.rs
compiler/rustc_ast_pretty/src/pprust/state.rs
compiler/rustc_ast_pretty/src/pprust/state/expr.rs
compiler/rustc_ast_pretty/src/pprust/state/item.rs
compiler/rustc_attr/src/builtin.rs
compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
compiler/rustc_borrowck/src/diagnostics/mod.rs
compiler/rustc_borrowck/src/diagnostics/move_errors.rs
compiler/rustc_borrowck/src/diagnostics/region_errors.rs
compiler/rustc_borrowck/src/diagnostics/region_name.rs
compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
compiler/rustc_borrowck/src/type_check/free_region_relations.rs
compiler/rustc_borrowck/src/type_check/mod.rs
compiler/rustc_borrowck/src/type_check/relate_tys.rs
compiler/rustc_builtin_macros/src/asm.rs
compiler/rustc_builtin_macros/src/assert/context.rs
compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
compiler/rustc_builtin_macros/src/format.rs
compiler/rustc_codegen_cranelift/Cargo.lock
compiler/rustc_codegen_llvm/src/llvm_util.rs
compiler/rustc_codegen_ssa/src/back/link.rs
compiler/rustc_codegen_ssa/src/back/write.rs
compiler/rustc_const_eval/src/const_eval/eval_queries.rs
compiler/rustc_const_eval/src/interpret/memory.rs
compiler/rustc_const_eval/src/interpret/operand.rs
compiler/rustc_const_eval/src/interpret/place.rs
compiler/rustc_const_eval/src/transform/check_consts/check.rs
compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
compiler/rustc_const_eval/src/util/alignment.rs
compiler/rustc_const_eval/src/util/call_kind.rs
compiler/rustc_driver/src/lib.rs
compiler/rustc_error_messages/locales/en-US/passes.ftl
compiler/rustc_errors/Cargo.toml
compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
compiler/rustc_errors/src/diagnostic.rs
compiler/rustc_errors/src/lib.rs
compiler/rustc_expand/src/base.rs
compiler/rustc_expand/src/mbe/macro_rules.rs
compiler/rustc_feature/src/builtin_attrs.rs
compiler/rustc_hir/src/definitions.rs
compiler/rustc_hir/src/hir.rs
compiler/rustc_hir/src/intravisit.rs
compiler/rustc_hir/src/lang_items.rs
compiler/rustc_hir/src/target.rs
compiler/rustc_incremental/src/persist/dirty_clean.rs
compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
compiler/rustc_infer/src/infer/canonical/mod.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
compiler/rustc_infer/src/infer/higher_ranked/mod.rs
compiler/rustc_infer/src/infer/mod.rs
compiler/rustc_infer/src/infer/region_constraints/mod.rs
compiler/rustc_lexer/src/cursor.rs
compiler/rustc_lexer/src/lib.rs
compiler/rustc_lexer/src/tests.rs
compiler/rustc_lint/src/builtin.rs
compiler/rustc_lint/src/context.rs
compiler/rustc_lint/src/early.rs
compiler/rustc_lint/src/late.rs
compiler/rustc_lint/src/levels.rs
compiler/rustc_lint/src/nonstandard_style.rs
compiler/rustc_lint/src/passes.rs
compiler/rustc_lint/src/unused.rs
compiler/rustc_lint_defs/src/builtin.rs
compiler/rustc_lint_defs/src/lib.rs
compiler/rustc_llvm/build.rs
compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
compiler/rustc_macros/Cargo.toml
compiler/rustc_metadata/src/native_libs.rs
compiler/rustc_metadata/src/rmeta/decoder.rs
compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
compiler/rustc_metadata/src/rmeta/encoder.rs
compiler/rustc_metadata/src/rmeta/mod.rs
compiler/rustc_middle/src/infer/canonical.rs
compiler/rustc_middle/src/lib.rs
compiler/rustc_middle/src/middle/stability.rs
compiler/rustc_middle/src/mir/mod.rs
compiler/rustc_middle/src/mir/patch.rs
compiler/rustc_middle/src/mir/syntax.rs
compiler/rustc_middle/src/mir/visit.rs
compiler/rustc_middle/src/query/mod.rs
compiler/rustc_middle/src/thir.rs
compiler/rustc_middle/src/traits/select.rs
compiler/rustc_middle/src/traits/specialization_graph.rs
compiler/rustc_middle/src/ty/adt.rs
compiler/rustc_middle/src/ty/assoc.rs
compiler/rustc_middle/src/ty/context.rs
compiler/rustc_middle/src/ty/error.rs
compiler/rustc_middle/src/ty/instance.rs
compiler/rustc_middle/src/ty/layout.rs
compiler/rustc_middle/src/ty/layout_sanity_check.rs [new file with mode: 0644]
compiler/rustc_middle/src/ty/mod.rs
compiler/rustc_middle/src/ty/parameterized.rs
compiler/rustc_middle/src/ty/print/pretty.rs
compiler/rustc_middle/src/ty/sty.rs
compiler/rustc_middle/src/ty/util.rs
compiler/rustc_mir_build/src/build/matches/mod.rs
compiler/rustc_mir_build/src/lints.rs
compiler/rustc_mir_build/src/thir/pattern/check_match.rs
compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
compiler/rustc_mir_dataflow/src/impls/liveness.rs
compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
compiler/rustc_mir_transform/src/const_prop.rs
compiler/rustc_mir_transform/src/const_prop_lint.rs
compiler/rustc_mir_transform/src/deref_separator.rs
compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
compiler/rustc_mir_transform/src/lib.rs
compiler/rustc_mir_transform/src/nrvo.rs
compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
compiler/rustc_mir_transform/src/reveal_all.rs
compiler/rustc_mir_transform/src/simplify.rs
compiler/rustc_parse/src/lexer/mod.rs
compiler/rustc_parse/src/lexer/tokentrees.rs
compiler/rustc_parse/src/parser/diagnostics.rs
compiler/rustc_parse/src/parser/expr.rs
compiler/rustc_parse/src/parser/item.rs
compiler/rustc_parse/src/parser/mod.rs
compiler/rustc_parse_format/src/lib.rs
compiler/rustc_parse_format/src/tests.rs
compiler/rustc_passes/src/check_attr.rs
compiler/rustc_passes/src/check_const.rs
compiler/rustc_passes/src/dead.rs
compiler/rustc_passes/src/errors.rs
compiler/rustc_passes/src/hir_stats.rs
compiler/rustc_passes/src/lib_features.rs
compiler/rustc_passes/src/naked_functions.rs
compiler/rustc_passes/src/stability.rs
compiler/rustc_privacy/src/errors.rs
compiler/rustc_privacy/src/lib.rs
compiler/rustc_query_system/src/query/job.rs
compiler/rustc_resolve/src/diagnostics.rs
compiler/rustc_resolve/src/late.rs
compiler/rustc_resolve/src/late/diagnostics.rs
compiler/rustc_resolve/src/lib.rs
compiler/rustc_save_analysis/src/lib.rs
compiler/rustc_span/src/symbol.rs
compiler/rustc_target/src/abi/call/mod.rs
compiler/rustc_target/src/abi/call/nvptx.rs [deleted file]
compiler/rustc_target/src/abi/call/x86.rs
compiler/rustc_target/src/abi/mod.rs
compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs
compiler/rustc_target/src/spec/android_base.rs
compiler/rustc_target/src/spec/apple_base.rs
compiler/rustc_target/src/spec/apple_sdk_base.rs
compiler/rustc_target/src/spec/armv4t_none_eabi.rs [new file with mode: 0644]
compiler/rustc_target/src/spec/fuchsia_base.rs
compiler/rustc_target/src/spec/i686_apple_darwin.rs
compiler/rustc_target/src/spec/tests/tests_impl.rs
compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs
compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs
compiler/rustc_trait_selection/Cargo.toml
compiler/rustc_trait_selection/src/traits/auto_trait.rs
compiler/rustc_trait_selection/src/traits/codegen.rs
compiler/rustc_trait_selection/src/traits/coherence.rs
compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
compiler/rustc_trait_selection/src/traits/misc.rs
compiler/rustc_trait_selection/src/traits/mod.rs
compiler/rustc_trait_selection/src/traits/object_safety.rs
compiler/rustc_trait_selection/src/traits/on_unimplemented.rs
compiler/rustc_trait_selection/src/traits/project.rs
compiler/rustc_trait_selection/src/traits/query/normalize.rs
compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
compiler/rustc_trait_selection/src/traits/select/confirmation.rs
compiler/rustc_trait_selection/src/traits/select/mod.rs
compiler/rustc_trait_selection/src/traits/specialize/mod.rs
compiler/rustc_trait_selection/src/traits/structural_match.rs
compiler/rustc_trait_selection/src/traits/util.rs
compiler/rustc_traits/src/chalk/db.rs
compiler/rustc_traits/src/chalk/mod.rs
compiler/rustc_traits/src/implied_outlives_bounds.rs
compiler/rustc_transmute/Cargo.toml [new file with mode: 0644]
compiler/rustc_transmute/src/layout/dfa.rs [new file with mode: 0644]
compiler/rustc_transmute/src/layout/mod.rs [new file with mode: 0644]
compiler/rustc_transmute/src/layout/nfa.rs [new file with mode: 0644]
compiler/rustc_transmute/src/layout/tree.rs [new file with mode: 0644]
compiler/rustc_transmute/src/layout/tree/tests.rs [new file with mode: 0644]
compiler/rustc_transmute/src/lib.rs [new file with mode: 0644]
compiler/rustc_transmute/src/maybe_transmutable/mod.rs [new file with mode: 0644]
compiler/rustc_transmute/src/maybe_transmutable/query_context.rs [new file with mode: 0644]
compiler/rustc_transmute/src/maybe_transmutable/tests.rs [new file with mode: 0644]
compiler/rustc_ty_utils/src/assoc.rs
compiler/rustc_ty_utils/src/instance.rs
compiler/rustc_ty_utils/src/ty.rs
compiler/rustc_typeck/Cargo.toml
compiler/rustc_typeck/src/astconv/errors.rs
compiler/rustc_typeck/src/astconv/mod.rs
compiler/rustc_typeck/src/check/_match.rs
compiler/rustc_typeck/src/check/cast.rs
compiler/rustc_typeck/src/check/check.rs
compiler/rustc_typeck/src/check/coercion.rs
compiler/rustc_typeck/src/check/compare_method.rs
compiler/rustc_typeck/src/check/demand.rs
compiler/rustc_typeck/src/check/expr.rs
compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
compiler/rustc_typeck/src/check/method/confirm.rs
compiler/rustc_typeck/src/check/method/mod.rs
compiler/rustc_typeck/src/check/method/prelude2021.rs
compiler/rustc_typeck/src/check/method/probe.rs
compiler/rustc_typeck/src/check/method/suggest.rs
compiler/rustc_typeck/src/check/mod.rs
compiler/rustc_typeck/src/check/op.rs
compiler/rustc_typeck/src/check/pat.rs
compiler/rustc_typeck/src/check/wfcheck.rs
compiler/rustc_typeck/src/coherence/builtin.rs
compiler/rustc_typeck/src/collect.rs
compiler/rustc_typeck/src/collect/item_bounds.rs
compiler/rustc_typeck/src/collect/type_of.rs
compiler/rustc_typeck/src/hir_wf_check.rs
compiler/rustc_typeck/src/impl_wf_check.rs
compiler/rustc_typeck/src/lib.rs
compiler/rustc_typeck/src/outlives/implicit_infer.rs
compiler/rustc_typeck/src/outlives/outlives_bounds.rs
config.toml.example
library/core/benches/num/int_log/mod.rs
library/core/src/alloc/layout.rs
library/core/src/array/equality.rs
library/core/src/char/methods.rs
library/core/src/ffi/c_str.rs
library/core/src/intrinsics.rs
library/core/src/mem/mod.rs
library/core/src/mem/transmutability.rs [new file with mode: 0644]
library/core/src/mem/valid_align.rs
library/core/src/num/bignum.rs
library/core/src/num/int_macros.rs
library/core/src/num/nonzero.rs
library/core/src/num/uint_macros.rs
library/core/src/ptr/const_ptr.rs
library/core/src/ptr/mut_ptr.rs
library/core/src/slice/iter.rs
library/core/src/str/mod.rs
library/core/src/time.rs
library/core/tests/alloc.rs
library/core/tests/num/int_log.rs
library/core/tests/slice.rs
library/std/src/backtrace.rs
library/std/src/error.rs
library/std/src/error/tests.rs
library/std/src/lib.rs
library/std/src/sys/solid/fs.rs
library/std/src/sys/solid/net.rs
library/std/src/sys/unix/fs.rs
library/std/src/sys/unix/locks/pthread_condvar.rs
library/std/src/sys/unix/mod.rs
library/std/src/sys/unix/rand.rs
library/std/src/sys/unix/thread.rs
library/std/src/sys/unsupported/process.rs
library/std/src/sys/wasm/mod.rs
library/std/src/sys/windows/c.rs
library/std/src/sys/windows/compat.rs
library/std/src/sys/windows/rand.rs
library/std/src/sys/windows/thread_parker.rs
library/std/src/thread/mod.rs
library/test/src/term/terminfo/mod.rs
library/unwind/build.rs
library/unwind/src/lib.rs
src/bootstrap/builder/tests.rs
src/bootstrap/check.rs
src/bootstrap/flags.rs
src/bootstrap/lib.rs
src/bootstrap/mk/Makefile.in
src/bootstrap/native.rs
src/bootstrap/test.rs
src/bootstrap/tool.rs
src/ci/docker/README.md
src/ci/docker/host-x86_64/arm-android/Dockerfile
src/ci/docker/host-x86_64/dist-aarch64-linux/Dockerfile
src/ci/docker/host-x86_64/dist-aarch64-linux/aarch64-linux-gnu.config
src/ci/docker/host-x86_64/dist-android/Dockerfile
src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile
src/ci/docker/host-x86_64/dist-armhf-linux/Dockerfile
src/ci/docker/host-x86_64/dist-armv7-linux/Dockerfile
src/ci/docker/host-x86_64/dist-i586-gnu-i586-i686-musl/Dockerfile
src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile
src/ci/docker/host-x86_64/dist-mips-linux/Dockerfile
src/ci/docker/host-x86_64/dist-mips64-linux/Dockerfile
src/ci/docker/host-x86_64/dist-mips64el-linux/Dockerfile
src/ci/docker/host-x86_64/dist-mipsel-linux/Dockerfile
src/ci/docker/host-x86_64/dist-powerpc-linux/Dockerfile
src/ci/docker/host-x86_64/dist-powerpc-linux/patches/glibc/2.11.1/001-PowerPC-Remove-unnecessary-mnew-mnemonics.patch [deleted file]
src/ci/docker/host-x86_64/dist-powerpc-linux/patches/glibc/2.11.1/002-newer-gcc.patch [deleted file]
src/ci/docker/host-x86_64/dist-powerpc-linux/powerpc-linux-gnu.config
src/ci/docker/host-x86_64/dist-powerpc64-linux/Dockerfile
src/ci/docker/host-x86_64/dist-powerpc64-linux/build-powerpc64-toolchain.sh
src/ci/docker/host-x86_64/dist-powerpc64-linux/patches/glibc/2.11.1/001-PowerPC-Remove-unnecessary-mnew-mnemonics.patch [deleted file]
src/ci/docker/host-x86_64/dist-powerpc64-linux/patches/glibc/2.11.1/002-Prevent-inlining-in-PPC64-initfini.s.patch [deleted file]
src/ci/docker/host-x86_64/dist-powerpc64-linux/patches/glibc/2.11.1/003-newer-gcc.patch [deleted file]
src/ci/docker/host-x86_64/dist-powerpc64-linux/powerpc64-linux-gnu.config
src/ci/docker/host-x86_64/dist-powerpc64le-linux/Dockerfile
src/ci/docker/host-x86_64/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh
src/ci/docker/host-x86_64/dist-riscv64-linux/Dockerfile
src/ci/docker/host-x86_64/dist-riscv64-linux/crosstool-ng.sh [deleted file]
src/ci/docker/host-x86_64/dist-s390x-linux/Dockerfile
src/ci/docker/host-x86_64/dist-s390x-linux/patches/glibc/2.12.1/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch [deleted file]
src/ci/docker/host-x86_64/dist-s390x-linux/s390x-linux-gnu.config
src/ci/docker/host-x86_64/dist-various-2/Dockerfile
src/ci/docker/host-x86_64/dist-various-2/build-fuchsia-toolchain.sh
src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
src/ci/docker/host-x86_64/dist-x86_64-linux/build-binutils.sh [deleted file]
src/ci/docker/host-x86_64/dist-x86_64-linux/build-cmake.sh [deleted file]
src/ci/docker/host-x86_64/dist-x86_64-linux/build-curl.sh [deleted file]
src/ci/docker/host-x86_64/dist-x86_64-linux/build-gcc.sh
src/ci/docker/host-x86_64/dist-x86_64-linux/build-openssl.sh [deleted file]
src/ci/docker/host-x86_64/dist-x86_64-linux/build-python.sh [deleted file]
src/ci/docker/host-x86_64/dist-x86_64-linux/download-openssl-curl.sh [deleted file]
src/ci/docker/host-x86_64/dist-x86_64-linux/llvm-project-centos.patch [deleted file]
src/ci/docker/host-x86_64/dist-x86_64-netbsd/Dockerfile
src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile
src/ci/docker/host-x86_64/i686-gnu/Dockerfile
src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile
src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile
src/ci/docker/host-x86_64/x86_64-gnu-llvm-12/Dockerfile
src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
src/ci/github-actions/ci.yml
src/ci/scripts/checkout-submodules.sh
src/doc/embedded-book
src/doc/man/rustc.1
src/doc/reference
src/doc/rust-by-example
src/doc/rustc-dev-guide
src/doc/rustc/src/SUMMARY.md
src/doc/rustc/src/command-line-arguments.md
src/doc/rustc/src/linker-plugin-lto.md
src/doc/rustc/src/platform-support.md
src/doc/rustc/src/platform-support/armv4t_none_eabi.md [new file with mode: 0644]
src/etc/check_missing_items.py
src/librustdoc/clean/auto_trait.rs
src/librustdoc/clean/blanket_impl.rs
src/librustdoc/clean/inline.rs
src/librustdoc/clean/mod.rs
src/librustdoc/clean/types.rs
src/librustdoc/clean/utils.rs
src/librustdoc/doctest.rs
src/librustdoc/html/format.rs
src/librustdoc/html/highlight.rs
src/librustdoc/html/highlight/tests.rs
src/librustdoc/html/markdown.rs
src/librustdoc/html/render/mod.rs
src/librustdoc/html/render/print_item.rs
src/librustdoc/html/render/write_shared.rs
src/librustdoc/html/sources.rs
src/librustdoc/html/static/css/rustdoc.css
src/librustdoc/html/static/css/themes/ayu.css
src/librustdoc/html/static/css/themes/dark.css
src/librustdoc/html/static/css/themes/light.css
src/librustdoc/html/static/images/down-arrow.svg
src/librustdoc/html/static/js/main.js
src/librustdoc/html/static/js/search.js
src/librustdoc/html/static/js/source-script.js
src/librustdoc/json/conversions.rs
src/librustdoc/passes/collect_intra_doc_links.rs
src/librustdoc/passes/strip_hidden.rs
src/librustdoc/passes/strip_private.rs
src/librustdoc/passes/stripper.rs
src/librustdoc/scrape_examples.rs
src/llvm-project
src/rustdoc-json-types/lib.rs
src/test/assembly/asm/riscv-types.rs
src/test/codegen-units/item-collection/generic-drop-glue.rs
src/test/codegen-units/item-collection/transitive-drop-glue.rs
src/test/codegen-units/item-collection/unsizing.rs
src/test/codegen/layout-size-checks.rs [new file with mode: 0644]
src/test/codegen/merge-functions.rs
src/test/debuginfo/no_mangle-info.rs [new file with mode: 0644]
src/test/incremental/hashes/inherent_impls.rs
src/test/incremental/hashes/trait_defs.rs
src/test/incremental/hashes/trait_impls.rs
src/test/mir-opt/README.md
src/test/mir-opt/bool_compare.rs
src/test/mir-opt/combine_array_len.norm2.InstCombine.32bit.diff [deleted file]
src/test/mir-opt/combine_array_len.norm2.InstCombine.64bit.diff [deleted file]
src/test/mir-opt/combine_array_len.norm2.InstCombine.diff [new file with mode: 0644]
src/test/mir-opt/combine_array_len.rs
src/test/mir-opt/const_goto.rs
src/test/mir-opt/const_goto_storage.match_nested_if.ConstGoto.diff
src/test/mir-opt/const_goto_storage.rs
src/test/mir-opt/const_prop/boxes.main.ConstProp.diff
src/test/mir-opt/deaggregator_test.rs
src/test/mir-opt/deaggregator_test_enum.rs
src/test/mir-opt/deaggregator_test_enum_2.rs
src/test/mir-opt/deaggregator_test_multiple.rs
src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff
src/test/mir-opt/deduplicate_blocks.rs
src/test/mir-opt/derefer_complex_case.main.Derefer.diff
src/test/mir-opt/derefer_complex_case.rs
src/test/mir-opt/derefer_inline_test.main.Derefer.diff
src/test/mir-opt/derefer_inline_test.rs
src/test/mir-opt/derefer_terminator_test.main.Derefer.diff
src/test/mir-opt/derefer_terminator_test.rs
src/test/mir-opt/derefer_test.main.Derefer.diff
src/test/mir-opt/derefer_test.rs
src/test/mir-opt/derefer_test_multiple.main.Derefer.diff
src/test/mir-opt/derefer_test_multiple.rs
src/test/mir-opt/equal_true.rs
src/test/mir-opt/inline/dyn_trait.get_query.Inline.diff
src/test/mir-opt/inline/dyn_trait.try_execute_query.Inline.diff
src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir
src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir
src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir
src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir
src/test/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.diff
src/test/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.diff
src/test/mir-opt/inline/inline_cycle.one.Inline.diff
src/test/mir-opt/inline/inline_cycle.two.Inline.diff
src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff
src/test/mir-opt/inline/inline_diverging.f.Inline.diff
src/test/mir-opt/inline/inline_diverging.g.Inline.diff
src/test/mir-opt/inline/inline_diverging.h.Inline.diff
src/test/mir-opt/inline/inline_instruction_set.default.Inline.diff
src/test/mir-opt/inline/inline_instruction_set.t32.Inline.diff
src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff
src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff
src/test/mir-opt/inline/inline_options.main.Inline.after.mir
src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir
src/test/mir-opt/inline/inline_shims.clone.Inline.diff
src/test/mir-opt/inline/inline_shims.drop.Inline.diff
src/test/mir-opt/inline/inline_specialization.main.Inline.diff
src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir
src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.a.Inline.after.mir
src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir
src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.c.Inline.after.mir
src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir
src/test/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir
src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff
src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff
src/test/mir-opt/instrument_coverage.rs
src/test/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.diff
src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff
src/test/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff
src/test/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.diff
src/test/mir-opt/lower_intrinsics.size_of.LowerIntrinsics.diff
src/test/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff
src/test/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff
src/test/mir-opt/not_equal_false.rs
src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff
src/test/mir-opt/remove_storage_markers.rs
src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff
src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff
src/test/mir-opt/remove_zsts_dont_touch_unions.rs
src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir
src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir
src/test/mir-opt/retag.rs
src/test/mir-opt/retag.{impl#0}-foo.SimplifyCfg-elaborate-drops.after.mir
src/test/mir-opt/retag.{impl#0}-foo_shr.SimplifyCfg-elaborate-drops.after.mir
src/test/mir-opt/simplify-locals-removes-unused-consts.rs
src/test/mir-opt/simplify-locals.rs
src/test/mir-opt/simplify_arm.id_try.SimplifyArmIdentity.diff
src/test/mir-opt/simplify_arm.id_try.SimplifyBranchSame.diff
src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff
src/test/run-make-fulldeps/issue-47551/eh_frame-terminator.rs
src/test/run-make-fulldeps/issues-41478-43796/a.rs
src/test/run-make-fulldeps/save-analysis-fail/foo.rs
src/test/run-make-fulldeps/save-analysis/foo.rs
src/test/run-make/coverage-llvmir/filecheck.testprog.txt
src/test/run-make/native-link-modifier-whole-archive/Makefile
src/test/run-make/native-link-modifier-whole-archive/directly_linked_test_minus_whole_archive.rs [new file with mode: 0644]
src/test/run-make/native-link-modifier-whole-archive/directly_linked_test_plus_whole_archive.rs [new file with mode: 0644]
src/test/run-make/raw-dylib-alt-calling-convention/Makefile
src/test/run-make/raw-dylib-alt-calling-convention/driver.rs
src/test/run-make/raw-dylib-alt-calling-convention/extern.c
src/test/run-make/raw-dylib-alt-calling-convention/lib.rs
src/test/run-make/raw-dylib-alt-calling-convention/output.msvc.txt [new file with mode: 0644]
src/test/run-make/raw-dylib-c/extern_1.c
src/test/run-make/raw-dylib-c/lib.rs
src/test/run-make/raw-dylib-c/output.txt
src/test/run-make/raw-dylib-link-ordinal/exporter.c
src/test/run-make/raw-dylib-link-ordinal/exporter.def
src/test/run-make/raw-dylib-link-ordinal/lib.rs
src/test/run-make/raw-dylib-link-ordinal/output.txt
src/test/run-pass-valgrind/cleanup-auto-borrow-obj.rs
src/test/run-pass-valgrind/coerce-match.rs
src/test/rustdoc-gui/item-info-width.goml [deleted file]
src/test/rustdoc-gui/item-info.goml [new file with mode: 0644]
src/test/rustdoc-gui/label-next-to-symbol.goml
src/test/rustdoc-gui/pocket-menu.goml
src/test/rustdoc-gui/search-filter.goml
src/test/rustdoc-gui/search-result-display.goml
src/test/rustdoc-gui/sidebar-mobile-scroll.goml [new file with mode: 0644]
src/test/rustdoc-gui/sidebar-source-code-display.goml
src/test/rustdoc-gui/src/lib2/lib.rs
src/test/rustdoc-json/primitive.rs
src/test/rustdoc-json/type/dyn.rs
src/test/rustdoc-json/type/hrtb.rs [new file with mode: 0644]
src/test/rustdoc-ui/check-doc-alias-attr-location.stderr
src/test/rustdoc-ui/rustc-check-passes.rs
src/test/rustdoc-ui/rustc-check-passes.stderr
src/test/rustdoc-ui/scrape-examples-fail-if-type-error.rs [new file with mode: 0644]
src/test/rustdoc-ui/scrape-examples-fail-if-type-error.stderr [new file with mode: 0644]
src/test/rustdoc/auxiliary/issue-100204-aux.rs [new file with mode: 0644]
src/test/rustdoc/auxiliary/issue-99734-aux.rs [new file with mode: 0644]
src/test/rustdoc/empty-impl-block-private-with-doc.rs [new file with mode: 0644]
src/test/rustdoc/empty-impl-block-private.rs [new file with mode: 0644]
src/test/rustdoc/fn-bound.rs [new file with mode: 0644]
src/test/rustdoc/impossible-default.rs [new file with mode: 0644]
src/test/rustdoc/intra-doc/assoc-reexport-super.rs [new file with mode: 0644]
src/test/rustdoc/issue-100204-inline-impl-through-glob-import.rs [new file with mode: 0644]
src/test/rustdoc/issue-99734-multiple-foreigns-w-same-name.rs [new file with mode: 0644]
src/test/rustdoc/issue-99734-multiple-mods-w-same-name.rs [new file with mode: 0644]
src/test/ui-fulldeps/pprust-expr-roundtrip.rs
src/test/ui/align-with-extern-c-fn.rs
src/test/ui/allocator/no_std-alloc-error-handler-custom.rs
src/test/ui/allocator/no_std-alloc-error-handler-default.rs
src/test/ui/argument-suggestions/issue-100154.rs [new file with mode: 0644]
src/test/ui/argument-suggestions/issue-100154.stderr [new file with mode: 0644]
src/test/ui/array-slice-vec/show-boxed-slice.rs
src/test/ui/asm/aarch64/bad-options.stderr
src/test/ui/asm/aarch64/parse-error.stderr
src/test/ui/asm/naked-functions.stderr
src/test/ui/asm/x86_64/bad-options.stderr
src/test/ui/asm/x86_64/parse-error.stderr
src/test/ui/associated-consts/associated-const-type-parameters.rs
src/test/ui/associated-type-bounds/enum-bounds.rs
src/test/ui/associated-types/associated-types-method.rs
src/test/ui/associated-types/associated-types-overridden-binding-2.rs
src/test/ui/associated-types/associated-types-overridden-binding-2.stderr
src/test/ui/associated-types/associated-types-struct-field-numbered.rs
src/test/ui/associated-types/issue-59324.rs
src/test/ui/associated-types/issue-59324.stderr
src/test/ui/async-await/async-block-control-flow-static-semantics.rs
src/test/ui/async-await/async-block-control-flow-static-semantics.stderr
src/test/ui/async-await/async-fn-size-moved-locals.rs
src/test/ui/async-await/async-fn-size-uninit-locals.rs
src/test/ui/async-await/no-const-async.stderr
src/test/ui/attributes/issue-90873.stderr
src/test/ui/auto-traits/auto-traits.rs
src/test/ui/backtrace-apple-no-dsymutil.rs
src/test/ui/bench/issue-32062.rs
src/test/ui/binding/match-tag.rs
src/test/ui/binding/or-pattern.rs
src/test/ui/binding/simple-generic-match.rs
src/test/ui/borrowck/access-mode-in-closures.stderr
src/test/ui/borrowck/borrowck-for-loop-uninitialized-binding.stderr
src/test/ui/borrowck/borrowck-move-error-with-note.stderr
src/test/ui/builtin-superkinds/builtin-superkinds-in-metadata2.rs
src/test/ui/cfg/cfg-method-receiver.rs [new file with mode: 0644]
src/test/ui/cfg/cfg-method-receiver.stderr [new file with mode: 0644]
src/test/ui/chalkify/builtin-copy-clone.rs
src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed
src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs
src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.fixed
src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs
src/test/ui/closures/issue-10398.rs
src/test/ui/closures/issue-10398.stderr
src/test/ui/closures/issue-6801.rs
src/test/ui/closures/issue-84128.stderr
src/test/ui/closures/issue-90871.rs [new file with mode: 0644]
src/test/ui/closures/issue-90871.stderr [new file with mode: 0644]
src/test/ui/codegen/issue-16602-3.rs
src/test/ui/coercion/issue-14589.rs
src/test/ui/const-generics/conservative_is_privately_uninhabited_uses_correct_param_env-1.rs
src/test/ui/const-generics/conservative_is_privately_uninhabited_uses_correct_param_env-2.rs
src/test/ui/const-generics/const-argument-cross-crate.rs
src/test/ui/const-generics/generic_const_exprs/associated-consts.rs
src/test/ui/const-generics/generic_const_exprs/issue-100217.rs [new file with mode: 0644]
src/test/ui/const-generics/generic_const_exprs/issue-73298.rs [new file with mode: 0644]
src/test/ui/const-generics/generic_const_exprs/issue-82268.rs [new file with mode: 0644]
src/test/ui/const-generics/generic_const_exprs/issue-83972.rs [new file with mode: 0644]
src/test/ui/const-generics/generic_const_exprs/issue-84669.rs [new file with mode: 0644]
src/test/ui/const-generics/generic_const_exprs/issue-86710.rs [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-100313.rs [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-100313.stderr [new file with mode: 0644]
src/test/ui/consts/assoc-const.rs
src/test/ui/consts/const-needs_drop.rs
src/test/ui/consts/const-size_of_val-align_of_val.rs
src/test/ui/consts/const_in_pattern/incomplete-slice.rs [new file with mode: 0644]
src/test/ui/consts/const_in_pattern/incomplete-slice.stderr [new file with mode: 0644]
src/test/ui/consts/const_in_pattern/warn_corner_cases.rs
src/test/ui/consts/issue-44415.stderr
src/test/ui/consts/issue-70773-mir-typeck-lt-norm.rs
src/test/ui/consts/rvalue-static-promotion.rs
src/test/ui/consts/transmute-const.rs
src/test/ui/copy-a-resource.stderr
src/test/ui/cycle-trait/cycle-trait-default-type-trait.stderr
src/test/ui/cycle-trait/cycle-trait-supertrait-direct.stderr
src/test/ui/deriving/deriving-clone-generic-tuple-struct.rs
src/test/ui/deriving/deriving-copyclone.rs
src/test/ui/deriving/issue-58319.rs
src/test/ui/did_you_mean/use_instead_of_import.fixed
src/test/ui/did_you_mean/use_instead_of_import.rs
src/test/ui/did_you_mean/use_instead_of_import.stderr
src/test/ui/drop/dropck-eyepatch-reorder.rs
src/test/ui/drop/dropck-eyepatch.rs
src/test/ui/drop/dynamic-drop.rs
src/test/ui/dropck/issue-28498-ugeh-with-passed-to-fn.rs
src/test/ui/dst/dst-rvalue.rs
src/test/ui/dst/dst-rvalue.stderr
src/test/ui/dynamically-sized-types/dst-struct.rs
src/test/ui/dynamically-sized-types/dst-trait.rs
src/test/ui/enum-discriminant/discriminant_value-wrapper.rs
src/test/ui/enum-discriminant/discriminant_value.rs
src/test/ui/enum/enum-discrim-autosizing.rs
src/test/ui/enum/enum-discrim-autosizing.stderr
src/test/ui/error-codes/E0081.rs
src/test/ui/error-codes/E0081.stderr
src/test/ui/expr/if/if-branch-types.stderr
src/test/ui/expr/if/if-else-type-mismatch.stderr
src/test/ui/feature-gates/feature-gate-raw-dylib-2.rs
src/test/ui/feature-gates/feature-gate-raw-dylib-2.stderr
src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr
src/test/ui/fmt/struct-field-as-captured-argument.fixed [new file with mode: 0644]
src/test/ui/fmt/struct-field-as-captured-argument.rs [new file with mode: 0644]
src/test/ui/fmt/struct-field-as-captured-argument.stderr [new file with mode: 0644]
src/test/ui/fn/implied-bounds-unnorm-associated-type-2.rs
src/test/ui/fn/implied-bounds-unnorm-associated-type-2.stderr [new file with mode: 0644]
src/test/ui/fn/implied-bounds-unnorm-associated-type-3.rs
src/test/ui/fn/implied-bounds-unnorm-associated-type-3.stderr [deleted file]
src/test/ui/fn/implied-bounds-unnorm-associated-type-4.rs [new file with mode: 0644]
src/test/ui/fn/implied-bounds-unnorm-associated-type-4.stderr [new file with mode: 0644]
src/test/ui/fn/implied-bounds-unnorm-associated-type-5.rs [new file with mode: 0644]
src/test/ui/fn/implied-bounds-unnorm-associated-type-5.stderr [new file with mode: 0644]
src/test/ui/fn/implied-bounds-unnorm-associated-type.rs
src/test/ui/fn/implied-bounds-unnorm-associated-type.stderr
src/test/ui/for-loop-while/break-while-condition.stderr
src/test/ui/generator/size-moved-locals.rs
src/test/ui/generator/type-mismatch-signature-deduction.stderr
src/test/ui/generic-associated-types/bugs/issue-87748.rs [deleted file]
src/test/ui/generic-associated-types/bugs/issue-87748.stderr [deleted file]
src/test/ui/generic-associated-types/issue-87748.rs [new file with mode: 0644]
src/test/ui/generics/generic-default-type-params-cross-crate.rs
src/test/ui/generics/generic-ivec-leak.rs
src/test/ui/generics/generic-newtype-struct.rs
src/test/ui/generics/generic-no-mangle.fixed
src/test/ui/generics/generic-no-mangle.rs
src/test/ui/generics/generic-recursive-tag.rs
src/test/ui/generics/generic-tag-corruption.rs
src/test/ui/generics/generic-tag-local.rs
src/test/ui/generics/generic-tag.rs
src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs
src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr
src/test/ui/hrtb/hrtb-perfect-forwarding.stderr
src/test/ui/hrtb/issue-30786.stderr
src/test/ui/hrtb/issue-62203-hrtb-ice.rs
src/test/ui/hrtb/issue-62203-hrtb-ice.stderr
src/test/ui/impl-trait/bounds_regression.rs
src/test/ui/impl-trait/equality.stderr
src/test/ui/impl-trait/issue-100187.rs [new file with mode: 0644]
src/test/ui/impl-trait/issues/issue-78722.rs
src/test/ui/impl-trait/issues/issue-78722.stderr
src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr
src/test/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.stderr
src/test/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs [new file with mode: 0644]
src/test/ui/implied-bounds/assoc-ty-wf-used-to-get-assoc-ty.rs [new file with mode: 0644]
src/test/ui/implied-bounds/assoc-ty-wf-used-to-get-assoc-ty.stderr [new file with mode: 0644]
src/test/ui/intrinsics/const-eval-select-bad.rs
src/test/ui/intrinsics/const-eval-select-bad.stderr
src/test/ui/issues/auxiliary/issue-2380.rs
src/test/ui/issues/issue-10682.rs
src/test/ui/issues/issue-10767.rs
src/test/ui/issues/issue-10802.rs
src/test/ui/issues/issue-11192.rs
src/test/ui/issues/issue-11192.stderr
src/test/ui/issues/issue-11515.rs
src/test/ui/issues/issue-11515.stderr
src/test/ui/issues/issue-11552.rs
src/test/ui/issues/issue-11844.rs
src/test/ui/issues/issue-11844.stderr
src/test/ui/issues/issue-12127.rs
src/test/ui/issues/issue-12511.stderr
src/test/ui/issues/issue-13027.rs
src/test/ui/issues/issue-13323.rs
src/test/ui/issues/issue-14382.rs
src/test/ui/issues/issue-14399.rs
src/test/ui/issues/issue-14915.rs
src/test/ui/issues/issue-14915.stderr
src/test/ui/issues/issue-15524.rs [deleted file]
src/test/ui/issues/issue-15524.stderr [deleted file]
src/test/ui/issues/issue-15571.rs
src/test/ui/issues/issue-15763.rs
src/test/ui/issues/issue-15858.rs
src/test/ui/issues/issue-16739.rs
src/test/ui/issues/issue-16774.rs
src/test/ui/issues/issue-17322.rs
src/test/ui/issues/issue-17905.rs
src/test/ui/issues/issue-2063.rs
src/test/ui/issues/issue-21033.rs
src/test/ui/issues/issue-2288.rs
src/test/ui/issues/issue-23024.rs
src/test/ui/issues/issue-23024.stderr
src/test/ui/issues/issue-23491.rs
src/test/ui/issues/issue-24308.rs
src/test/ui/issues/issue-24805-dropck-itemless.rs
src/test/ui/issues/issue-25089.rs
src/test/ui/issues/issue-25679.rs
src/test/ui/issues/issue-25700-1.rs
src/test/ui/issues/issue-25700-2.rs
src/test/ui/issues/issue-25700.rs
src/test/ui/issues/issue-26127.rs
src/test/ui/issues/issue-26641.rs
src/test/ui/issues/issue-26709.rs
src/test/ui/issues/issue-2708.rs
src/test/ui/issues/issue-27240.rs
src/test/ui/issues/issue-2734.rs
src/test/ui/issues/issue-2735.rs
src/test/ui/issues/issue-2823.stderr
src/test/ui/issues/issue-28498-must-work-ex1.rs
src/test/ui/issues/issue-28498-must-work-ex2.rs
src/test/ui/issues/issue-28498-ugeh-ex1.rs
src/test/ui/issues/issue-29147-rpass.rs
src/test/ui/issues/issue-29147.rs
src/test/ui/issues/issue-29147.stderr
src/test/ui/issues/issue-2935.rs
src/test/ui/issues/issue-3026.rs
src/test/ui/issues/issue-31173.rs
src/test/ui/issues/issue-31173.stderr
src/test/ui/issues/issue-3121.rs
src/test/ui/issues/issue-31267-additional.rs
src/test/ui/issues/issue-31299.rs
src/test/ui/issues/issue-3290.rs
src/test/ui/issues/issue-33941.rs
src/test/ui/issues/issue-33941.stderr
src/test/ui/issues/issue-3447.rs
src/test/ui/issues/issue-34571.rs
src/test/ui/issues/issue-36053.rs
src/test/ui/issues/issue-36278-prefix-nesting.rs
src/test/ui/issues/issue-3794.rs
src/test/ui/issues/issue-3878.rs
src/test/ui/issues/issue-40003.rs
src/test/ui/issues/issue-4252.rs
src/test/ui/issues/issue-46069.rs
src/test/ui/issues/issue-4759.rs
src/test/ui/issues/issue-4972.rs
src/test/ui/issues/issue-4972.stderr
src/test/ui/issues/issue-5100.rs
src/test/ui/issues/issue-5192.rs
src/test/ui/issues/issue-5315.rs
src/test/ui/issues/issue-5439.rs
src/test/ui/issues/issue-5439.stderr
src/test/ui/issues/issue-5666.rs
src/test/ui/issues/issue-5718.rs
src/test/ui/issues/issue-5884.rs
src/test/ui/issues/issue-61894.rs
src/test/ui/issues/issue-6318.rs
src/test/ui/issues/issue-6557.rs
src/test/ui/issues/issue-69396-const-no-type-in-macro.stderr
src/test/ui/issues/issue-7013.rs
src/test/ui/issues/issue-7013.stderr
src/test/ui/issues/issue-7364.rs
src/test/ui/issues/issue-7364.stderr
src/test/ui/issues/issue-7673-cast-generically-implemented-trait.rs
src/test/ui/issues/issue-7911.rs
src/test/ui/issues/issue-9129.rs
src/test/ui/issues/issue-9382.rs
src/test/ui/issues/issue-99838.rs [new file with mode: 0644]
src/test/ui/json-and-color.rs [deleted file]
src/test/ui/json-and-color.stderr [deleted file]
src/test/ui/json-and-error-format.rs [deleted file]
src/test/ui/json-and-error-format.stderr [deleted file]
src/test/ui/json-bom-plus-crlf-multifile-aux.rs [deleted file]
src/test/ui/json-bom-plus-crlf-multifile.rs [deleted file]
src/test/ui/json-bom-plus-crlf-multifile.stderr [deleted file]
src/test/ui/json-bom-plus-crlf.rs [deleted file]
src/test/ui/json-bom-plus-crlf.stderr [deleted file]
src/test/ui/json-invalid.rs [deleted file]
src/test/ui/json-invalid.stderr [deleted file]
src/test/ui/json-multiple.polonius.stderr [deleted file]
src/test/ui/json-multiple.rs [deleted file]
src/test/ui/json-multiple.stderr [deleted file]
src/test/ui/json-options.polonius.stderr [deleted file]
src/test/ui/json-options.rs [deleted file]
src/test/ui/json-options.stderr [deleted file]
src/test/ui/json-short.rs [deleted file]
src/test/ui/json-short.stderr [deleted file]
src/test/ui/json/json-and-color.rs [new file with mode: 0644]
src/test/ui/json/json-and-color.stderr [new file with mode: 0644]
src/test/ui/json/json-and-error-format.rs [new file with mode: 0644]
src/test/ui/json/json-and-error-format.stderr [new file with mode: 0644]
src/test/ui/json/json-bom-plus-crlf-multifile-aux.rs [new file with mode: 0644]
src/test/ui/json/json-bom-plus-crlf-multifile.rs [new file with mode: 0644]
src/test/ui/json/json-bom-plus-crlf-multifile.stderr [new file with mode: 0644]
src/test/ui/json/json-bom-plus-crlf.rs [new file with mode: 0644]
src/test/ui/json/json-bom-plus-crlf.stderr [new file with mode: 0644]
src/test/ui/json/json-invalid.rs [new file with mode: 0644]
src/test/ui/json/json-invalid.stderr [new file with mode: 0644]
src/test/ui/json/json-multiple.polonius.stderr [new file with mode: 0644]
src/test/ui/json/json-multiple.rs [new file with mode: 0644]
src/test/ui/json/json-multiple.stderr [new file with mode: 0644]
src/test/ui/json/json-options.polonius.stderr [new file with mode: 0644]
src/test/ui/json/json-options.rs [new file with mode: 0644]
src/test/ui/json/json-options.stderr [new file with mode: 0644]
src/test/ui/json/json-short.rs [new file with mode: 0644]
src/test/ui/json/json-short.stderr [new file with mode: 0644]
src/test/ui/layout/unsafe-cell-hides-niche.rs
src/test/ui/let-else/issue-100103.rs [new file with mode: 0644]
src/test/ui/lifetimes/elided-lifetime-in-path-in-type-relative-expression.rs [new file with mode: 0644]
src/test/ui/lifetimes/fullwidth-ampersand.rs [new file with mode: 0644]
src/test/ui/lifetimes/fullwidth-ampersand.stderr [new file with mode: 0644]
src/test/ui/limits/issue-17913.rs
src/test/ui/lint/dead-code/tuple-struct-field.rs
src/test/ui/lint/dead-code/tuple-struct-field.stderr [new file with mode: 0644]
src/test/ui/lint/dead-code/with-impl.rs
src/test/ui/lint/issue-99387.rs [new file with mode: 0644]
src/test/ui/lint/unaligned_references.rs
src/test/ui/lint/unaligned_references.stderr
src/test/ui/lint/unreachable_pub.stderr
src/test/ui/lint/unused/issue-92751.rs [new file with mode: 0644]
src/test/ui/lint/unused/issue-92751.stderr [new file with mode: 0644]
src/test/ui/lint/unused/unused_attributes-must_use.stderr
src/test/ui/lint/unused_parens_multibyte_recovery.rs [new file with mode: 0644]
src/test/ui/lint/unused_parens_multibyte_recovery.stderr [new file with mode: 0644]
src/test/ui/list.rs
src/test/ui/lowering/issue-96847.rs [new file with mode: 0644]
src/test/ui/macros/auxiliary/issue-100199.rs [new file with mode: 0644]
src/test/ui/macros/html-literals.rs
src/test/ui/macros/issue-100199.rs [new file with mode: 0644]
src/test/ui/macros/issue-100199.stderr [new file with mode: 0644]
src/test/ui/macros/issue-98466.stderr
src/test/ui/macros/issue-99265.stderr
src/test/ui/macros/issue-99907.fixed [new file with mode: 0644]
src/test/ui/macros/issue-99907.rs [new file with mode: 0644]
src/test/ui/macros/issue-99907.stderr [new file with mode: 0644]
src/test/ui/macros/macro-tt-followed-by-seq.rs
src/test/ui/macros/stringify.rs
src/test/ui/match/issue-42679.rs
src/test/ui/methods/method-argument-inference-associated-type.rs
src/test/ui/methods/method-probe-no-guessing-dyn-trait.rs
src/test/ui/mir/mir_codegen_switch.rs
src/test/ui/mir/mir_fat_ptr.rs
src/test/ui/mir/mir_raw_fat_ptr.rs
src/test/ui/mir/mir_refs_correct.rs
src/test/ui/mismatched_types/E0409.stderr
src/test/ui/mismatched_types/do-not-suggest-boxed-trait-objects-instead-of-impl-trait.rs [new file with mode: 0644]
src/test/ui/mismatched_types/do-not-suggest-boxed-trait-objects-instead-of-impl-trait.stderr [new file with mode: 0644]
src/test/ui/mismatched_types/dont-point-return-on-E0308.rs [new file with mode: 0644]
src/test/ui/mismatched_types/dont-point-return-on-E0308.stderr [new file with mode: 0644]
src/test/ui/mismatched_types/issue-84976.stderr
src/test/ui/mismatched_types/suggest-adding-or-removing-ref-for-binding-pattern.fixed [new file with mode: 0644]
src/test/ui/mismatched_types/suggest-adding-or-removing-ref-for-binding-pattern.rs [new file with mode: 0644]
src/test/ui/mismatched_types/suggest-adding-or-removing-ref-for-binding-pattern.stderr [new file with mode: 0644]
src/test/ui/mismatched_types/suggest-boxed-trait-objects-instead-of-impl-trait.fixed [new file with mode: 0644]
src/test/ui/mismatched_types/suggest-boxed-trait-objects-instead-of-impl-trait.rs [new file with mode: 0644]
src/test/ui/mismatched_types/suggest-boxed-trait-objects-instead-of-impl-trait.stderr [new file with mode: 0644]
src/test/ui/moves/issue-99470-move-out-of-some.rs [new file with mode: 0644]
src/test/ui/moves/issue-99470-move-out-of-some.stderr [new file with mode: 0644]
src/test/ui/moves/moves-based-on-type-block-bad.stderr
src/test/ui/never_type/fallback-closure-wrap.fallback.stderr
src/test/ui/never_type/fallback-closure-wrap.rs
src/test/ui/nll/issue-98589-closures-relate-named-regions.rs [new file with mode: 0644]
src/test/ui/nll/issue-98589-closures-relate-named-regions.stderr [new file with mode: 0644]
src/test/ui/nll/move-errors.stderr
src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs
src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr
src/test/ui/noncopyable-class.stderr
src/test/ui/nullable-pointer-iotareduction.rs
src/test/ui/optimization-fuel-0.rs
src/test/ui/optimization-fuel-1.rs
src/test/ui/packed/packed-struct-drop-aligned.rs
src/test/ui/packed/packed-struct-optimized-enum.rs
src/test/ui/packed/packed-tuple-struct-layout.rs
src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.rs [new file with mode: 0644]
src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.stderr [new file with mode: 0644]
src/test/ui/parser/issue-99625-enum-struct-mutually-exclusive.fixed [new file with mode: 0644]
src/test/ui/parser/issue-99625-enum-struct-mutually-exclusive.rs [new file with mode: 0644]
src/test/ui/parser/issue-99625-enum-struct-mutually-exclusive.stderr [new file with mode: 0644]
src/test/ui/parser/issues/issue-70388-without-witness.fixed
src/test/ui/parser/issues/issue-70388-without-witness.rs
src/test/ui/parser/issues/issue-88770.rs
src/test/ui/parser/issues/issue-88770.stderr
src/test/ui/parser/issues/issue-89574.stderr
src/test/ui/parser/item-free-const-no-body-semantic-fail.stderr
src/test/ui/parser/item-free-static-no-body-semantic-fail.stderr
src/test/ui/parser/removed-syntax-static-fn.stderr
src/test/ui/parser/suggest-semi-in-array.rs [new file with mode: 0644]
src/test/ui/parser/suggest-semi-in-array.stderr [new file with mode: 0644]
src/test/ui/parser/suggest-suggest-semicolon-before-array.fixed [new file with mode: 0644]
src/test/ui/parser/suggest-suggest-semicolon-before-array.rs [new file with mode: 0644]
src/test/ui/parser/suggest-suggest-semicolon-before-array.stderr [new file with mode: 0644]
src/test/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.fixed [new file with mode: 0644]
src/test/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.rs [new file with mode: 0644]
src/test/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.stderr [new file with mode: 0644]
src/test/ui/proc-macro/auxiliary/re-export.rs [new file with mode: 0644]
src/test/ui/proc-macro/issue-79148.rs [new file with mode: 0644]
src/test/ui/proc-macro/issue-79148.stderr [new file with mode: 0644]
src/test/ui/range_inclusive.rs
src/test/ui/recursion/issue-26548-recursion-via-normalize.rs
src/test/ui/recursion/issue-26548-recursion-via-normalize.stderr
src/test/ui/reify-intrinsic.stderr
src/test/ui/resolve/issue-23305.stderr
src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr
src/test/ui/resolve/resolve-inconsistent-names.rs
src/test/ui/resolve/resolve-inconsistent-names.stderr
src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-direct-unsafe-ptr-embedded.rs
src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-direct-unsafe-ptr-param.rs
src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-indirect-unsafe-ptr-embedded.rs
src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-indirect-unsafe-ptr-param.rs
src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.rs
src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.rs
src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.rs
src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.rs
src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.rs
src/test/ui/rfc-2008-non-exhaustive/enum-as-cast.rs
src/test/ui/rfc-2008-non-exhaustive/enum-as-cast.stderr [new file with mode: 0644]
src/test/ui/rfc-2294-if-let-guard/feature-gate.rs
src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr
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-2627-raw-dylib/link-ordinal-and-name.rs
src/test/ui/rfc-2627-raw-dylib/link-ordinal-and-name.stderr
src/test/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.rs
src/test/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.stderr
src/test/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.rs
src/test/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.stderr
src/test/ui/rfc-2627-raw-dylib/link-ordinal-multiple.rs
src/test/ui/rfc-2627-raw-dylib/link-ordinal-multiple.stderr
src/test/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.rs [new file with mode: 0644]
src/test/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.stderr [new file with mode: 0644]
src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-large.rs
src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-large.stderr
src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.rs
src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.stderr
src/test/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.rs [new file with mode: 0644]
src/test/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.stderr [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/const-drop.rs
src/test/ui/rfcs/rfc-2151-raw-identifiers/attr.rs
src/test/ui/rustdoc/check-doc-alias-attr-location.rs
src/test/ui/rustdoc/check-doc-alias-attr-location.stderr
src/test/ui/specialization/issue-43037.rs [new file with mode: 0644]
src/test/ui/specialization/issue-43037.stderr [new file with mode: 0644]
src/test/ui/specialization/issue-45814.rs [new file with mode: 0644]
src/test/ui/specialization/issue-45814.stderr [new file with mode: 0644]
src/test/ui/specialization/specialization-cross-crate.rs
src/test/ui/specialization/specialization-translate-projections-with-lifetimes.rs
src/test/ui/stability-attribute/auxiliary/default_body.rs [new file with mode: 0644]
src/test/ui/stability-attribute/default-body-stability-err.rs [new file with mode: 0644]
src/test/ui/stability-attribute/default-body-stability-err.stderr [new file with mode: 0644]
src/test/ui/stability-attribute/default-body-stability-ok-enables.rs [new file with mode: 0644]
src/test/ui/stability-attribute/default-body-stability-ok-impls.rs [new file with mode: 0644]
src/test/ui/stats/hir-stats.rs [new file with mode: 0644]
src/test/ui/stats/hir-stats.stderr [new file with mode: 0644]
src/test/ui/std-backtrace.rs
src/test/ui/stdlib-unit-tests/raw-fat-ptr.rs
src/test/ui/struct-ctor-mangling.rs
src/test/ui/structs-enums/align-struct.rs
src/test/ui/structs-enums/enum-null-pointer-opt.rs
src/test/ui/structs-enums/enum-nullable-simplifycfg-misopt.rs
src/test/ui/structs-enums/resource-in-struct.rs
src/test/ui/structs-enums/tuple-struct-construct.rs
src/test/ui/structs-enums/uninstantiable-struct.rs
src/test/ui/suggestions/as-ref.rs
src/test/ui/suggestions/as-ref.stderr
src/test/ui/suggestions/const-no-type.rs
src/test/ui/suggestions/const-no-type.stderr
src/test/ui/suggestions/dont-suggest-ref/simple.stderr
src/test/ui/suggestions/field-access-considering-privacy.rs [new file with mode: 0644]
src/test/ui/suggestions/field-access-considering-privacy.stderr [new file with mode: 0644]
src/test/ui/suggestions/unnamable-types.stderr
src/test/ui/tag-variant-disr-dup.rs [deleted file]
src/test/ui/tag-variant-disr-dup.stderr [deleted file]
src/test/ui/trailing-comma.rs
src/test/ui/traits/assoc-type-in-superbad.rs
src/test/ui/traits/assoc-type-in-superbad.stderr
src/test/ui/traits/augmented-assignments-trait.rs
src/test/ui/traits/issue-91949-hangs-on-recursion.stderr
src/test/ui/traits/negative-impls/negated-auto-traits-rpass.rs
src/test/ui/traits/object/exclusion.rs
src/test/ui/traits/object/generics.rs
src/test/ui/traits/pointee-deduction.rs
src/test/ui/traits/principal-less-objects.rs
src/test/ui/traits/trait-upcasting/cyclic-trait-resolution.stderr
src/test/ui/transmutability/abstraction/abstracted_assume.rs [new file with mode: 0644]
src/test/ui/transmutability/abstraction/const_generic_fn.rs [new file with mode: 0644]
src/test/ui/transmutability/arrays/should_have_correct_length.rs [new file with mode: 0644]
src/test/ui/transmutability/arrays/should_inherit_alignment.rs [new file with mode: 0644]
src/test/ui/transmutability/arrays/should_require_well_defined_layout.rs [new file with mode: 0644]
src/test/ui/transmutability/arrays/should_require_well_defined_layout.stderr [new file with mode: 0644]
src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.rs [new file with mode: 0644]
src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.stderr [new file with mode: 0644]
src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.rs [new file with mode: 0644]
src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr [new file with mode: 0644]
src/test/ui/transmutability/enums/should_order_correctly.rs [new file with mode: 0644]
src/test/ui/transmutability/enums/should_pad_variants.rs [new file with mode: 0644]
src/test/ui/transmutability/enums/should_pad_variants.stderr [new file with mode: 0644]
src/test/ui/transmutability/enums/should_respect_endianness.rs [new file with mode: 0644]
src/test/ui/transmutability/enums/should_respect_endianness.stderr [new file with mode: 0644]
src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.rs [new file with mode: 0644]
src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.stderr [new file with mode: 0644]
src/test/ui/transmutability/malformed-program-gracefulness/unknown_dst.rs [new file with mode: 0644]
src/test/ui/transmutability/malformed-program-gracefulness/unknown_dst.stderr [new file with mode: 0644]
src/test/ui/transmutability/malformed-program-gracefulness/unknown_src.rs [new file with mode: 0644]
src/test/ui/transmutability/malformed-program-gracefulness/unknown_src.stderr [new file with mode: 0644]
src/test/ui/transmutability/malformed-program-gracefulness/unknown_src_field.rs [new file with mode: 0644]
src/test/ui/transmutability/malformed-program-gracefulness/unknown_src_field.stderr [new file with mode: 0644]
src/test/ui/transmutability/malformed-program-gracefulness/wrong-type-assume.rs [new file with mode: 0644]
src/test/ui/transmutability/malformed-program-gracefulness/wrong-type-assume.stderr [new file with mode: 0644]
src/test/ui/transmutability/primitives/bool.rs [new file with mode: 0644]
src/test/ui/transmutability/primitives/bool.stderr [new file with mode: 0644]
src/test/ui/transmutability/primitives/numbers.rs [new file with mode: 0644]
src/test/ui/transmutability/primitives/numbers.stderr [new file with mode: 0644]
src/test/ui/transmutability/primitives/unit.rs [new file with mode: 0644]
src/test/ui/transmutability/primitives/unit.stderr [new file with mode: 0644]
src/test/ui/transmutability/references.rs [new file with mode: 0644]
src/test/ui/transmutability/references.stderr [new file with mode: 0644]
src/test/ui/transmutability/structs/repr/should_handle_align.rs [new file with mode: 0644]
src/test/ui/transmutability/structs/repr/should_handle_packed.rs [new file with mode: 0644]
src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.rs [new file with mode: 0644]
src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr [new file with mode: 0644]
src/test/ui/transmutability/structs/should_order_fields_correctly.rs [new file with mode: 0644]
src/test/ui/transmutability/unions/boolish.rs [new file with mode: 0644]
src/test/ui/transmutability/unions/repr/should_handle_align.rs [new file with mode: 0644]
src/test/ui/transmutability/unions/repr/should_handle_packed.rs [new file with mode: 0644]
src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.rs [new file with mode: 0644]
src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr [new file with mode: 0644]
src/test/ui/transmutability/unions/should_pad_variants.rs [new file with mode: 0644]
src/test/ui/transmutability/unions/should_pad_variants.stderr [new file with mode: 0644]
src/test/ui/transmutability/unions/should_permit_intersecting_if_validity_is_assumed.rs [new file with mode: 0644]
src/test/ui/transmutability/unions/should_reject_contraction.rs [new file with mode: 0644]
src/test/ui/transmutability/unions/should_reject_contraction.stderr [new file with mode: 0644]
src/test/ui/transmutability/unions/should_reject_disjoint.rs [new file with mode: 0644]
src/test/ui/transmutability/unions/should_reject_disjoint.stderr [new file with mode: 0644]
src/test/ui/transmutability/unions/should_reject_intersecting.rs [new file with mode: 0644]
src/test/ui/transmutability/unions/should_reject_intersecting.stderr [new file with mode: 0644]
src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_private_field.rs [new file with mode: 0644]
src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_private_variant.rs [new file with mode: 0644]
src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_tricky_unreachable_field.rs [new file with mode: 0644]
src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_field.rs [new file with mode: 0644]
src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_field.stderr [new file with mode: 0644]
src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_ty.rs [new file with mode: 0644]
src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_ty.stderr [new file with mode: 0644]
src/test/ui/transmutability/visibility/should_accept_if_src_has_private_field.rs [new file with mode: 0644]
src/test/ui/transmutability/visibility/should_accept_if_src_has_private_variant.rs [new file with mode: 0644]
src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_field.rs [new file with mode: 0644]
src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_field.stderr [new file with mode: 0644]
src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_ty.rs [new file with mode: 0644]
src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_ty.stderr [new file with mode: 0644]
src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.rs [new file with mode: 0644]
src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.stderr [new file with mode: 0644]
src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.rs [new file with mode: 0644]
src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.stderr [new file with mode: 0644]
src/test/ui/transmutability/visibility/should_reject_if_dst_has_tricky_unreachable_field.rs [new file with mode: 0644]
src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.rs [new file with mode: 0644]
src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.stderr [new file with mode: 0644]
src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.rs [new file with mode: 0644]
src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.stderr [new file with mode: 0644]
src/test/ui/type-alias-enum-variants/enum-variant-generic-args-pass.rs
src/test/ui/type-alias-enum-variants/self-in-enum-definition.stderr
src/test/ui/type-alias-impl-trait/issue-57961.rs
src/test/ui/type-alias-impl-trait/issue-57961.stderr
src/test/ui/type-alias-impl-trait/issue-74280.stderr
src/test/ui/type-alias-impl-trait/issue-98604.rs
src/test/ui/type-alias-impl-trait/issue-98604.stderr
src/test/ui/type-alias-impl-trait/issue-98608.rs
src/test/ui/type-alias-impl-trait/issue-98608.stderr
src/test/ui/type/missing-let-in-binding.fixed [new file with mode: 0644]
src/test/ui/type/missing-let-in-binding.rs [new file with mode: 0644]
src/test/ui/type/missing-let-in-binding.stderr [new file with mode: 0644]
src/test/ui/typeck/issue-100164.fixed [new file with mode: 0644]
src/test/ui/typeck/issue-100164.rs [new file with mode: 0644]
src/test/ui/typeck/issue-100164.stderr [new file with mode: 0644]
src/test/ui/typeck/issue-100246.rs [new file with mode: 0644]
src/test/ui/typeck/issue-100246.stderr [new file with mode: 0644]
src/test/ui/typeck/issue-79040.stderr
src/test/ui/typeck/issue-91210-ptr-method.stderr
src/test/ui/typeck/issue-98982.rs [new file with mode: 0644]
src/test/ui/typeck/issue-98982.stderr [new file with mode: 0644]
src/test/ui/typeck/typeck_type_placeholder_item.stderr
src/test/ui/unboxed-closures/type-id-higher-rank.rs
src/test/ui/unsized-locals/unsized-exprs-rpass.rs
src/test/ui/unsized/unchanged-param.rs
src/tools/cargo
src/tools/clippy/CHANGELOG.md
src/tools/clippy/CONTRIBUTING.md
src/tools/clippy/Cargo.toml
src/tools/clippy/README.md
src/tools/clippy/book/src/configuration.md
src/tools/clippy/clippy_dev/src/new_lint.rs
src/tools/clippy/clippy_dev/src/update_lints.rs
src/tools/clippy/clippy_lints/Cargo.toml
src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs
src/tools/clippy/clippy_lints/src/blacklisted_name.rs [deleted file]
src/tools/clippy/clippy_lints/src/booleans.rs
src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs
src/tools/clippy/clippy_lints/src/checked_conversions.rs
src/tools/clippy/clippy_lints/src/create_dir.rs
src/tools/clippy/clippy_lints/src/default.rs
src/tools/clippy/clippy_lints/src/dereference.rs
src/tools/clippy/clippy_lints/src/disallowed_names.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/double_parens.rs
src/tools/clippy/clippy_lints/src/eta_reduction.rs
src/tools/clippy/clippy_lints/src/formatting.rs
src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
src/tools/clippy/clippy_lints/src/future_not_send.rs
src/tools/clippy/clippy_lints/src/lib.register_all.rs
src/tools/clippy/clippy_lints/src/lib.register_correctness.rs
src/tools/clippy/clippy_lints/src/lib.register_lints.rs
src/tools/clippy/clippy_lints/src/lib.register_nursery.rs
src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs
src/tools/clippy/clippy_lints/src/lib.register_restriction.rs
src/tools/clippy/clippy_lints/src/lib.register_style.rs
src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs
src/tools/clippy/clippy_lints/src/lib.rs
src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
src/tools/clippy/clippy_lints/src/manual_instant_elapsed.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/manual_ok_or.rs
src/tools/clippy/clippy_lints/src/map_err_ignore.rs
src/tools/clippy/clippy_lints/src/map_unit_fn.rs
src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs
src/tools/clippy/clippy_lints/src/matches/mod.rs
src/tools/clippy/clippy_lints/src/matches/try_err.rs
src/tools/clippy/clippy_lints/src/mem_replace.rs
src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
src/tools/clippy/clippy_lints/src/methods/expect_used.rs
src/tools/clippy/clippy_lints/src/methods/mod.rs
src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs
src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
src/tools/clippy/clippy_lints/src/missing_doc.rs
src/tools/clippy/clippy_lints/src/missing_inline.rs
src/tools/clippy/clippy_lints/src/option_env_unwrap.rs
src/tools/clippy/clippy_lints/src/partialeq_to_none.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/path_buf_push_overwrite.rs
src/tools/clippy/clippy_lints/src/precedence.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_closure_call.rs
src/tools/clippy/clippy_lints/src/regex.rs
src/tools/clippy/clippy_lints/src/renamed_lints.rs
src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
src/tools/clippy/clippy_lints/src/stable_sort_primitive.rs
src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
src/tools/clippy/clippy_lints/src/unit_types/mod.rs
src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs
src/tools/clippy/clippy_lints/src/unused_rounding.rs
src/tools/clippy/clippy_lints/src/unused_unit.rs
src/tools/clippy/clippy_lints/src/useless_conversion.rs
src/tools/clippy/clippy_lints/src/utils/conf.rs
src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
src/tools/clippy/clippy_lints/src/verbose_file_reads.rs
src/tools/clippy/clippy_lints/src/write.rs
src/tools/clippy/clippy_utils/Cargo.toml
src/tools/clippy/clippy_utils/src/ast_utils.rs
src/tools/clippy/clippy_utils/src/check_proc_macro.rs [new file with mode: 0644]
src/tools/clippy/clippy_utils/src/hir_utils.rs
src/tools/clippy/clippy_utils/src/lib.rs
src/tools/clippy/clippy_utils/src/numeric_literal.rs
src/tools/clippy/clippy_utils/src/paths.rs
src/tools/clippy/clippy_utils/src/source.rs
src/tools/clippy/clippy_utils/src/sugg.rs
src/tools/clippy/clippy_utils/src/ty.rs
src/tools/clippy/rust-toolchain
src/tools/clippy/tests/ui-internal/check_clippy_version_attribute.stderr
src/tools/clippy/tests/ui-toml/bad_toml_type/clippy.toml
src/tools/clippy/tests/ui-toml/bad_toml_type/conf_bad_type.stderr
src/tools/clippy/tests/ui-toml/blacklisted_names_append/blacklisted_names.rs [deleted file]
src/tools/clippy/tests/ui-toml/blacklisted_names_append/blacklisted_names.stderr [deleted file]
src/tools/clippy/tests/ui-toml/blacklisted_names_append/clippy.toml [deleted file]
src/tools/clippy/tests/ui-toml/blacklisted_names_replace/blacklisted_names.rs [deleted file]
src/tools/clippy/tests/ui-toml/blacklisted_names_replace/blacklisted_names.stderr [deleted file]
src/tools/clippy/tests/ui-toml/blacklisted_names_replace/clippy.toml [deleted file]
src/tools/clippy/tests/ui-toml/conf_deprecated_key/clippy.toml
src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.rs
src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr
src/tools/clippy/tests/ui-toml/disallowed_names_append/clippy.toml [new file with mode: 0644]
src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.rs [new file with mode: 0644]
src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui-toml/disallowed_names_replace/clippy.toml [new file with mode: 0644]
src/tools/clippy/tests/ui-toml/disallowed_names_replace/disallowed_names.rs [new file with mode: 0644]
src/tools/clippy/tests/ui-toml/disallowed_names_replace/disallowed_names.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui-toml/duplicated_keys/clippy.toml [new file with mode: 0644]
src/tools/clippy/tests/ui-toml/duplicated_keys/duplicated_keys.rs [new file with mode: 0644]
src/tools/clippy/tests/ui-toml/duplicated_keys/duplicated_keys.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui-toml/expect_used/expect_used.stderr
src/tools/clippy/tests/ui-toml/toml_blacklist/clippy.toml [deleted file]
src/tools/clippy/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.rs [deleted file]
src/tools/clippy/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.stderr [deleted file]
src/tools/clippy/tests/ui-toml/toml_disallow/clippy.toml [new file with mode: 0644]
src/tools/clippy/tests/ui-toml/toml_disallow/conf_french_disallowed_name.rs [new file with mode: 0644]
src/tools/clippy/tests/ui-toml/toml_disallow/conf_french_disallowed_name.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
src/tools/clippy/tests/ui/assertions_on_result_states.fixed
src/tools/clippy/tests/ui/assertions_on_result_states.rs
src/tools/clippy/tests/ui/assertions_on_result_states.stderr
src/tools/clippy/tests/ui/blacklisted_name.rs [deleted file]
src/tools/clippy/tests/ui/blacklisted_name.stderr [deleted file]
src/tools/clippy/tests/ui/borrow_box.rs
src/tools/clippy/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs
src/tools/clippy/tests/ui/box_collection.rs
src/tools/clippy/tests/ui/cast_abs_to_unsigned.fixed
src/tools/clippy/tests/ui/cast_abs_to_unsigned.rs
src/tools/clippy/tests/ui/cast_abs_to_unsigned.stderr
src/tools/clippy/tests/ui/clone_on_copy.fixed
src/tools/clippy/tests/ui/clone_on_copy.rs
src/tools/clippy/tests/ui/clone_on_copy.stderr
src/tools/clippy/tests/ui/crashes/ice-2760.rs
src/tools/clippy/tests/ui/crashes/ice-3462.rs
src/tools/clippy/tests/ui/crashes/regressions.rs
src/tools/clippy/tests/ui/def_id_nocore.rs
src/tools/clippy/tests/ui/def_id_nocore.stderr
src/tools/clippy/tests/ui/default_trait_access.fixed
src/tools/clippy/tests/ui/default_trait_access.rs
src/tools/clippy/tests/ui/default_trait_access.stderr
src/tools/clippy/tests/ui/disallowed_names.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/disallowed_names.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/diverging_sub_expression.rs
src/tools/clippy/tests/ui/empty_loop_no_std.rs
src/tools/clippy/tests/ui/empty_loop_no_std.stderr
src/tools/clippy/tests/ui/expect.stderr
src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs
src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr
src/tools/clippy/tests/ui/explicit_auto_deref.fixed
src/tools/clippy/tests/ui/explicit_auto_deref.rs
src/tools/clippy/tests/ui/explicit_auto_deref.stderr
src/tools/clippy/tests/ui/format.fixed
src/tools/clippy/tests/ui/format.rs
src/tools/clippy/tests/ui/format.stderr
src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed
src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs
src/tools/clippy/tests/ui/if_same_then_else.rs
src/tools/clippy/tests/ui/if_same_then_else2.rs
src/tools/clippy/tests/ui/ifs_same_cond.rs
src/tools/clippy/tests/ui/iter_skip_next.fixed
src/tools/clippy/tests/ui/iter_skip_next.rs
src/tools/clippy/tests/ui/let_if_seq.rs
src/tools/clippy/tests/ui/logic_bug.rs [deleted file]
src/tools/clippy/tests/ui/logic_bug.stderr [deleted file]
src/tools/clippy/tests/ui/manual_assert.edition2018.fixed
src/tools/clippy/tests/ui/manual_assert.edition2021.fixed
src/tools/clippy/tests/ui/manual_assert.fixed
src/tools/clippy/tests/ui/manual_assert.rs
src/tools/clippy/tests/ui/manual_instant_elapsed.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/manual_instant_elapsed.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/manual_instant_elapsed.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/manual_ok_or.fixed
src/tools/clippy/tests/ui/manual_ok_or.rs
src/tools/clippy/tests/ui/match_same_arms2.rs
src/tools/clippy/tests/ui/methods.rs
src/tools/clippy/tests/ui/mismatching_type_param_order.rs
src/tools/clippy/tests/ui/missing-doc-crate-missing.rs [deleted file]
src/tools/clippy/tests/ui/missing-doc-crate-missing.stderr [deleted file]
src/tools/clippy/tests/ui/missing-doc-crate.rs [deleted file]
src/tools/clippy/tests/ui/missing-doc-impl.rs [deleted file]
src/tools/clippy/tests/ui/missing-doc-impl.stderr [deleted file]
src/tools/clippy/tests/ui/missing-doc.rs [deleted file]
src/tools/clippy/tests/ui/missing-doc.stderr [deleted file]
src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs
src/tools/clippy/tests/ui/missing_doc.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/missing_doc.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/missing_doc_crate.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/missing_doc_crate_missing.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/missing_doc_crate_missing.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/missing_doc_impl.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/missing_doc_impl.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed
src/tools/clippy/tests/ui/mistyped_literal_suffix.rs
src/tools/clippy/tests/ui/mistyped_literal_suffix.stderr
src/tools/clippy/tests/ui/mixed_read_write_in_expression.rs
src/tools/clippy/tests/ui/must_use_candidates.fixed
src/tools/clippy/tests/ui/must_use_candidates.rs
src/tools/clippy/tests/ui/numbered_fields.fixed
src/tools/clippy/tests/ui/numbered_fields.rs
src/tools/clippy/tests/ui/numbered_fields.stderr
src/tools/clippy/tests/ui/op_ref.rs
src/tools/clippy/tests/ui/option_if_let_else.fixed
src/tools/clippy/tests/ui/option_if_let_else.rs
src/tools/clippy/tests/ui/option_if_let_else.stderr
src/tools/clippy/tests/ui/overly_complex_bool_expr.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/overly_complex_bool_expr.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/partialeq_to_none.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/partialeq_to_none.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/partialeq_to_none.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/rc_mutex.rs
src/tools/clippy/tests/ui/redundant_allocation.rs
src/tools/clippy/tests/ui/redundant_allocation.stderr
src/tools/clippy/tests/ui/redundant_allocation_fixable.fixed
src/tools/clippy/tests/ui/redundant_allocation_fixable.rs
src/tools/clippy/tests/ui/redundant_closure_call_fixable.fixed
src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs
src/tools/clippy/tests/ui/redundant_closure_call_fixable.stderr
src/tools/clippy/tests/ui/rename.fixed
src/tools/clippy/tests/ui/rename.rs
src/tools/clippy/tests/ui/rename.stderr
src/tools/clippy/tests/ui/same_functions_in_if_condition.rs
src/tools/clippy/tests/ui/same_functions_in_if_condition.stderr
src/tools/clippy/tests/ui/skip_while_next.rs
src/tools/clippy/tests/ui/swap.fixed
src/tools/clippy/tests/ui/swap.rs
src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs
src/tools/clippy/tests/ui/unit_arg.rs
src/tools/clippy/tests/ui/unit_arg.stderr
src/tools/clippy/tests/ui/unreadable_literal.fixed
src/tools/clippy/tests/ui/unreadable_literal.rs
src/tools/clippy/tests/ui/unreadable_literal.stderr
src/tools/clippy/tests/ui/unwrap_expect_used.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/unwrap_expect_used.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/used_underscore_binding.rs
src/tools/compiletest/Cargo.toml
src/tools/compiletest/src/common.rs
src/tools/compiletest/src/header.rs
src/tools/compiletest/src/header/tests.rs
src/tools/compiletest/src/main.rs
src/tools/compiletest/src/runtest.rs
src/tools/compiletest/src/util.rs
src/tools/compiletest/src/util/tests.rs
src/tools/html-checker/Cargo.toml
src/tools/html-checker/main.rs
src/tools/miri
src/tools/rls
src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/bug_report.md
src/tools/rust-analyzer/.github/workflows/publish.yml
src/tools/rust-analyzer/.github/workflows/release.yaml
src/tools/rust-analyzer/README.md
src/tools/rust-analyzer/crates/flycheck/src/lib.rs
src/tools/rust-analyzer/crates/hir-def/src/attr.rs
src/tools/rust-analyzer/crates/hir-def/src/generics.rs
src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
src/tools/rust-analyzer/crates/hir-def/src/visibility.rs
src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs
src/tools/rust-analyzer/crates/hir-expand/src/name.rs
src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
src/tools/rust-analyzer/crates/hir/src/lib.rs
src/tools/rust-analyzer/crates/hir/src/semantics.rs
src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_variant.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs
src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs
src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/derive.rs
src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs
src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs
src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs
src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs
src/tools/rust-analyzer/crates/ide-completion/src/completions/vis.rs
src/tools/rust-analyzer/crates/ide-completion/src/context.rs
src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs
src/tools/rust-analyzer/crates/ide-completion/src/render.rs
src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs
src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs
src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs
src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs
src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs
src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs
src/tools/rust-analyzer/crates/ide-db/src/defs.rs
src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs
src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs
src/tools/rust-analyzer/crates/ide/src/expand_macro.rs
src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs
src/tools/rust-analyzer/crates/ide/src/highlight_related.rs
src/tools/rust-analyzer/crates/ide/src/hover.rs
src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
src/tools/rust-analyzer/crates/ide/src/join_lines.rs
src/tools/rust-analyzer/crates/ide/src/matching_brace.rs
src/tools/rust-analyzer/crates/ide/src/moniker.rs
src/tools/rust-analyzer/crates/ide/src/move_item.rs
src/tools/rust-analyzer/crates/ide/src/parent_module.rs
src/tools/rust-analyzer/crates/ide/src/runnables.rs
src/tools/rust-analyzer/crates/ide/src/shuffle_crate_graph.rs
src/tools/rust-analyzer/crates/ide/src/static_index.rs
src/tools/rust-analyzer/crates/ide/src/status.rs
src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs
src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs
src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_inline.html [new file with mode: 0644]
src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_outline.html [new file with mode: 0644]
src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
src/tools/rust-analyzer/crates/ide/src/syntax_tree.rs
src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs
src/tools/rust-analyzer/crates/ide/src/view_hir.rs
src/tools/rust-analyzer/crates/ide/src/view_item_tree.rs
src/tools/rust-analyzer/crates/limit/src/lib.rs
src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs
src/tools/rust-analyzer/crates/paths/src/lib.rs
src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs
src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/mod.rs
src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs
src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/cli/load_cargo.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/handlers.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs
src/tools/rust-analyzer/crates/sourcegen/src/lib.rs
src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs
src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs
src/tools/rust-analyzer/crates/syntax/src/lib.rs
src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs
src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs
src/tools/rust-analyzer/docs/dev/README.md
src/tools/rust-analyzer/docs/dev/architecture.md
src/tools/rust-analyzer/docs/dev/guide.md
src/tools/rust-analyzer/docs/user/manual.adoc
src/tools/rust-analyzer/editors/code/package.json
src/tools/rust-analyzer/editors/code/src/config.ts
src/tools/rust-analyzer/editors/code/src/main.ts
src/tools/rust-analyzer/lib/la-arena/src/lib.rs
src/tools/rust-analyzer/lib/la-arena/src/map.rs
src/tools/rust-analyzer/xtask/src/release.rs
src/tools/rustc-workspace-hack/Cargo.toml
src/tools/rustdoc-gui/tester.js
src/tools/rustfmt/src/chains.rs
src/tools/tidy/src/bins.rs
src/tools/x/src/main.rs
src/version
x.ps1 [new file with mode: 0755]
x.py
x.sh [new file with mode: 0755]

index 1f95c1bcab4a56df72a65c8749848d77dcbf2885..ceda348025e364bff23cfdb24679939f8f7b8646 100644 (file)
@@ -79,7 +79,7 @@ jobs:
         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'"
+        if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' && github.ref != 'refs/heads/try-perf'"
       - name: collect CPU statistics
         run: src/ci/scripts/collect-cpu-stats.sh
         if: success() && !env.SKIP_JOB
@@ -389,26 +389,26 @@ jobs:
             os: windows-latest-xl
           - name: i686-mingw-1
             env:
-              RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu"
+              RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --set llvm.allow-old-toolchain"
               SCRIPT: make ci-mingw-subset-1
               CUSTOM_MINGW: 1
             os: windows-latest-xl
           - name: i686-mingw-2
             env:
-              RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu"
+              RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --set llvm.allow-old-toolchain"
               SCRIPT: make ci-mingw-subset-2
               CUSTOM_MINGW: 1
             os: windows-latest-xl
           - name: x86_64-mingw-1
             env:
               SCRIPT: make ci-mingw-subset-1
-              RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler"
+              RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler --set llvm.allow-old-toolchain"
               CUSTOM_MINGW: 1
             os: windows-latest-xl
           - name: x86_64-mingw-2
             env:
               SCRIPT: make ci-mingw-subset-2
-              RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler"
+              RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler --set llvm.allow-old-toolchain"
               CUSTOM_MINGW: 1
             os: windows-latest-xl
           - name: dist-x86_64-msvc
@@ -432,7 +432,7 @@ jobs:
             os: windows-latest-xl
           - name: dist-i686-mingw
             env:
-              RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --enable-full-tools --enable-profiler"
+              RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --enable-full-tools --enable-profiler --set llvm.allow-old-toolchain"
               SCRIPT: python x.py dist
               CUSTOM_MINGW: 1
               DIST_REQUIRE_ALL_TOOLS: 1
@@ -440,7 +440,7 @@ jobs:
           - name: dist-x86_64-mingw
             env:
               SCRIPT: python x.py dist
-              RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler"
+              RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler --set llvm.allow-old-toolchain"
               CUSTOM_MINGW: 1
               DIST_REQUIRE_ALL_TOOLS: 1
             os: windows-latest-xl
@@ -478,7 +478,7 @@ jobs:
         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'"
+        if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' && github.ref != 'refs/heads/try-perf'"
       - name: collect CPU statistics
         run: src/ci/scripts/collect-cpu-stats.sh
         if: success() && !env.SKIP_JOB
@@ -588,7 +588,7 @@ jobs:
         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'"
+        if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' && github.ref != 'refs/heads/try-perf'"
       - name: collect CPU statistics
         run: src/ci/scripts/collect-cpu-stats.sh
         if: success() && !env.SKIP_JOB
index cca60e337d2d8a4127cb6e6776ec14d6525b93d7..9a664b6509801d57df60313e0a43d01c839c97df 100644 (file)
@@ -34,7 +34,7 @@
 [submodule "src/llvm-project"]
        path = src/llvm-project
        url = https://github.com/rust-lang/llvm-project.git
-       branch = rustc/14.0-2022-06-20
+       branch = rustc/15.0-2022-08-09
 [submodule "src/doc/embedded-book"]
        path = src/doc/embedded-book
        url = https://github.com/rust-embedded/book.git
index 058b6198dc425e7d22972c14199ff86595c07049..10ebff848872f9e9d73ad56738e25c371618b4ce 100644 (file)
@@ -82,12 +82,6 @@ dependencies = [
  "url 2.2.2",
 ]
 
-[[package]]
-name = "annotate-snippets"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d78ea013094e5ea606b1c05fe35f1dd7ea1eb1ea259908d040b25bd5ec677ee5"
-
 [[package]]
 name = "annotate-snippets"
 version = "0.9.1"
@@ -109,9 +103,9 @@ dependencies = [
 
 [[package]]
 name = "anyhow"
-version = "1.0.51"
+version = "1.0.60"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8b26702f315f53b6071259e15dd9d64528213b44d61de1ec926eca7715d62203"
+checksum = "c794e162a5eff65c72ef524dfe393eb923c354e350bb78b9c7383df13f3bc142"
 
 [[package]]
 name = "array_tool"
@@ -339,7 +333,6 @@ dependencies = [
  "cargo-util",
  "clap",
  "crates-io",
- "crossbeam-utils",
  "curl",
  "curl-sys",
  "env_logger 0.9.0",
@@ -363,7 +356,6 @@ dependencies = [
  "libgit2-sys",
  "log",
  "memchr",
- "num_cpus",
  "opener",
  "openssl",
  "os_info",
@@ -423,6 +415,7 @@ dependencies = [
 name = "cargo-miri"
 version = "0.1.0"
 dependencies = [
+ "cargo_metadata 0.15.0",
  "directories",
  "rustc-workspace-hack",
  "rustc_version",
@@ -471,6 +464,7 @@ dependencies = [
  "termcolor",
  "toml_edit",
  "url 2.2.2",
+ "winapi",
 ]
 
 [[package]]
@@ -525,9 +519,9 @@ version = "0.1.0"
 
 [[package]]
 name = "cc"
-version = "1.0.69"
+version = "1.0.73"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2"
+checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
 dependencies = [
  "jobserver",
 ]
@@ -665,7 +659,7 @@ dependencies = [
 
 [[package]]
 name = "clippy"
-version = "0.1.64"
+version = "0.1.65"
 dependencies = [
  "clippy_lints",
  "clippy_utils",
@@ -708,7 +702,7 @@ dependencies = [
 
 [[package]]
 name = "clippy_lints"
-version = "0.1.64"
+version = "0.1.65"
 dependencies = [
  "cargo_metadata 0.14.0",
  "clippy_utils",
@@ -730,7 +724,7 @@ dependencies = [
 
 [[package]]
 name = "clippy_utils"
-version = "0.1.64"
+version = "0.1.65"
 dependencies = [
  "arrayvec",
  "if_chain",
@@ -805,9 +799,9 @@ dependencies = [
 
 [[package]]
 name = "compiler_builtins"
-version = "0.1.73"
+version = "0.1.78"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "71b72fde1d7792ca3bd654f7c3ea4508f9e4d0c826e24179eabb7fcc97a90bc3"
+checksum = "413b6b13f725a46cdec40364e0c1d564a22cf0aaac5f1e267a129d956478a6b4"
 dependencies = [
  "cc",
  "rustc-std-workspace-core",
@@ -822,6 +816,7 @@ dependencies = [
  "getopts",
  "glob",
  "lazy_static",
+ "lazycell",
  "libc",
  "miow",
  "regex",
@@ -1788,6 +1783,7 @@ dependencies = [
 name = "html-checker"
 version = "0.1.0"
 dependencies = [
+ "rayon",
  "walkdir",
 ]
 
@@ -2144,9 +2140,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
 
 [[package]]
 name = "libc"
-version = "0.2.126"
+version = "0.2.129"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
+checksum = "64de3cc433455c14174d42e554d4027ee631c4d046d43e3ecc6efc4636cdc7a7"
 dependencies = [
  "rustc-std-workspace-core",
 ]
@@ -2660,9 +2656,9 @@ checksum = "dd20eec3dbe4376829cb7d80ae6ac45e0a766831dca50202ff2d40db46a8a024"
 
 [[package]]
 name = "os_info"
-version = "3.4.0"
+version = "3.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0eca3ecae1481e12c3d9379ec541b238a16f0b75c9a409942daa8ec20dbfdb62"
+checksum = "5209b2162b2c140df493a93689e04f8deab3a67634f5bc7a553c0a98e5b8d399"
 dependencies = [
  "log",
  "serde",
@@ -3861,7 +3857,7 @@ dependencies = [
 name = "rustc_errors"
 version = "0.0.0"
 dependencies = [
- "annotate-snippets 0.8.0",
+ "annotate-snippets",
  "atty",
  "rustc_data_structures",
  "rustc_error_messages",
@@ -4113,7 +4109,7 @@ dependencies = [
 name = "rustc_macros"
 version = "0.1.0"
 dependencies = [
- "annotate-snippets 0.8.0",
+ "annotate-snippets",
  "fluent-bundle",
  "fluent-syntax",
  "proc-macro2",
@@ -4553,6 +4549,7 @@ dependencies = [
  "rustc_session",
  "rustc_span",
  "rustc_target",
+ "rustc_transmute",
  "smallvec",
  "tracing",
 ]
@@ -4577,6 +4574,20 @@ dependencies = [
  "tracing",
 ]
 
+[[package]]
+name = "rustc_transmute"
+version = "0.1.0"
+dependencies = [
+ "itertools",
+ "rustc_data_structures",
+ "rustc_infer",
+ "rustc_macros",
+ "rustc_middle",
+ "rustc_span",
+ "rustc_target",
+ "tracing",
+]
+
 [[package]]
 name = "rustc_ty_utils"
 version = "0.0.0"
@@ -4616,6 +4627,7 @@ dependencies = [
  "rustc_attr",
  "rustc_data_structures",
  "rustc_errors",
+ "rustc_feature",
  "rustc_graphviz",
  "rustc_hir",
  "rustc_hir_pretty",
@@ -4713,7 +4725,7 @@ dependencies = [
 name = "rustfmt-nightly"
 version = "1.5.1"
 dependencies = [
- "annotate-snippets 0.9.1",
+ "annotate-snippets",
  "anyhow",
  "bytecount",
  "cargo_metadata 0.14.0",
index 26613314a15bc2be0a74c6970ac582193fc70b1c..7f601d5ee582b622f33f6779dd2a3831d258100f 100644 (file)
--- a/README.md
+++ b/README.md
@@ -233,7 +233,7 @@ Snapshot binaries are currently built and tested on several platforms:
 | Platform / Architecture                     | x86 | x86_64 |
 |---------------------------------------------|-----|--------|
 | Windows (7, 8, 10, ...)                     | ✓   | ✓      |
-| Linux (kernel 2.6.32, glibc 2.11 or later)  | ✓   | ✓      |
+| Linux (kernel 3.2, glibc 2.17 or later)     | ✓   | ✓      |
 | macOS (10.7 Lion or later)                  | (\*) | ✓      |
 
 (\*): Apple dropped support for running 32-bit binaries starting from macOS 10.15 and iOS 11.
index 8154eab20599aa43e9a39eced4ef3e9480a50a9f..e66bf60b7f781d665679169f17a76692f9933482 100644 (file)
@@ -1,3 +1,207 @@
+Version 1.63.0 (2022-08-11)
+==========================
+
+Language
+--------
+- [Remove migrate borrowck mode for pre-NLL errors.][95565]
+- [Modify MIR building to drop repeat expressions with length zero.][95953]
+- [Remove label/lifetime shadowing warnings.][96296]
+- [Allow explicit generic arguments in the presence of `impl Trait` args.][96868]
+- [Make `cenum_impl_drop_cast` warnings deny-by-default.][97652]
+- [Prevent unwinding when `-C panic=abort` is used regardless of declared ABI.][96959]
+- [lub: don't bail out due to empty binders.][97867]
+
+Compiler
+--------
+- [Stabilize the `bundle` native library modifier,][95818] also removing the
+  deprecated `static-nobundle` linking kind.
+- [Add Apple WatchOS compile targets\*.][95243]
+- [Add a Windows application manifest to rustc-main.][96737]
+
+\* Refer to Rust's [platform support page][platform-support-doc] for more
+   information on Rust's tiered platform support.
+
+Libraries
+---------
+- [Implement `Copy`, `Clone`, `PartialEq` and `Eq` for `core::fmt::Alignment`.][94530]
+- [Extend `ptr::null` and `null_mut` to all thin (including extern) types.][94954]
+- [`impl Read and Write for VecDeque<u8>`.][95632]
+- [STD support for the Nintendo 3DS.][95897]
+- [Make write/print macros eagerly drop temporaries.][96455]
+- [Implement internal traits that enable `[OsStr]::join`.][96881]
+- [Implement `Hash` for `core::alloc::Layout`.][97034]
+- [Add capacity documentation for `OsString`.][97202]
+- [Put a bound on collection misbehavior.][97316]
+- [Make `std::mem::needs_drop` accept `?Sized`.][97675]
+- [`impl Termination for Infallible` and then make the `Result` impls of `Termination` more generic.][97803]
+- [Document Rust's stance on `/proc/self/mem`.][97837]
+
+Stabilized APIs
+---------------
+
+- [`array::from_fn`]
+- [`Box::into_pin`]
+- [`BinaryHeap::try_reserve`]
+- [`BinaryHeap::try_reserve_exact`]
+- [`OsString::try_reserve`]
+- [`OsString::try_reserve_exact`]
+- [`PathBuf::try_reserve`]
+- [`PathBuf::try_reserve_exact`]
+- [`Path::try_exists`]
+- [`Ref::filter_map`]
+- [`RefMut::filter_map`]
+- [`NonNull::<[T]>::len`][`NonNull::<slice>::len`]
+- [`ToOwned::clone_into`]
+- [`Ipv6Addr::to_ipv4_mapped`]
+- [`unix::io::AsFd`]
+- [`unix::io::BorrowedFd<'fd>`]
+- [`unix::io::OwnedFd`]
+- [`windows::io::AsHandle`]
+- [`windows::io::BorrowedHandle<'handle>`]
+- [`windows::io::OwnedHandle`]
+- [`windows::io::HandleOrInvalid`]
+- [`windows::io::HandleOrNull`]
+- [`windows::io::InvalidHandleError`]
+- [`windows::io::NullHandleError`]
+- [`windows::io::AsSocket`]
+- [`windows::io::BorrowedSocket<'handle>`]
+- [`windows::io::OwnedSocket`]
+- [`thread::scope`]
+- [`thread::Scope`]
+- [`thread::ScopedJoinHandle`]
+
+These APIs are now usable in const contexts:
+
+- [`array::from_ref`]
+- [`slice::from_ref`]
+- [`intrinsics::copy`]
+- [`intrinsics::copy_nonoverlapping`]
+- [`<*const T>::copy_to`]
+- [`<*const T>::copy_to_nonoverlapping`]
+- [`<*mut T>::copy_to`]
+- [`<*mut T>::copy_to_nonoverlapping`]
+- [`<*mut T>::copy_from`]
+- [`<*mut T>::copy_from_nonoverlapping`]
+- [`str::from_utf8`]
+- [`Utf8Error::error_len`]
+- [`Utf8Error::valid_up_to`]
+- [`Condvar::new`]
+- [`Mutex::new`]
+- [`RwLock::new`]
+
+Cargo
+-----
+- [Stabilize the `--config path` command-line argument.][cargo/10755]
+- [Expose rust-version in the environment as `CARGO_PKG_RUST_VERSION`.][cargo/10713]
+
+Compatibility Notes
+-------------------
+
+- [`#[link]` attributes are now checked more strictly,][96885] which may introduce
+  errors for invalid attribute arguments that were previously ignored.
+
+Internal Changes
+----------------
+
+These changes provide no direct user facing benefits, but represent significant
+improvements to the internals and overall performance of rustc
+and related tools.
+
+- [Prepare Rust for LLVM opaque pointers.][94214]
+
+[94214]: https://github.com/rust-lang/rust/pull/94214/
+[94530]: https://github.com/rust-lang/rust/pull/94530/
+[94954]: https://github.com/rust-lang/rust/pull/94954/
+[95243]: https://github.com/rust-lang/rust/pull/95243/
+[95565]: https://github.com/rust-lang/rust/pull/95565/
+[95632]: https://github.com/rust-lang/rust/pull/95632/
+[95818]: https://github.com/rust-lang/rust/pull/95818/
+[95897]: https://github.com/rust-lang/rust/pull/95897/
+[95953]: https://github.com/rust-lang/rust/pull/95953/
+[96296]: https://github.com/rust-lang/rust/pull/96296/
+[96455]: https://github.com/rust-lang/rust/pull/96455/
+[96737]: https://github.com/rust-lang/rust/pull/96737/
+[96868]: https://github.com/rust-lang/rust/pull/96868/
+[96881]: https://github.com/rust-lang/rust/pull/96881/
+[96885]: https://github.com/rust-lang/rust/pull/96885/
+[96959]: https://github.com/rust-lang/rust/pull/96959/
+[97034]: https://github.com/rust-lang/rust/pull/97034/
+[97202]: https://github.com/rust-lang/rust/pull/97202/
+[97316]: https://github.com/rust-lang/rust/pull/97316/
+[97652]: https://github.com/rust-lang/rust/pull/97652/
+[97675]: https://github.com/rust-lang/rust/pull/97675/
+[97803]: https://github.com/rust-lang/rust/pull/97803/
+[97837]: https://github.com/rust-lang/rust/pull/97837/
+[97867]: https://github.com/rust-lang/rust/pull/97867/
+[cargo/10713]: https://github.com/rust-lang/cargo/pull/10713/
+[cargo/10755]: https://github.com/rust-lang/cargo/pull/10755/
+
+[`array::from_fn`]: https://doc.rust-lang.org/stable/std/array/fn.from_fn.html
+[`Box::into_pin`]: https://doc.rust-lang.org/stable/std/boxed/struct.Box.html#method.into_pin
+[`BinaryHeap::try_reserve_exact`]: https://doc.rust-lang.org/stable/alloc/collections/binary_heap/struct.BinaryHeap.html#method.try_reserve_exact
+[`BinaryHeap::try_reserve`]: https://doc.rust-lang.org/stable/std/collections/struct.BinaryHeap.html#method.try_reserve
+[`OsString::try_reserve`]: https://doc.rust-lang.org/stable/std/ffi/struct.OsString.html#method.try_reserve
+[`OsString::try_reserve_exact`]: https://doc.rust-lang.org/stable/std/ffi/struct.OsString.html#method.try_reserve_exact
+[`PathBuf::try_reserve`]: https://doc.rust-lang.org/stable/std/path/struct.PathBuf.html#method.try_reserve
+[`PathBuf::try_reserve_exact`]: https://doc.rust-lang.org/stable/std/path/struct.PathBuf.html#method.try_reserve_exact
+[`Path::try_exists`]: https://doc.rust-lang.org/stable/std/path/struct.Path.html#method.try_exists
+[`Ref::filter_map`]: https://doc.rust-lang.org/stable/std/cell/struct.Ref.html#method.filter_map
+[`RefMut::filter_map`]: https://doc.rust-lang.org/stable/std/cell/struct.RefMut.html#method.filter_map
+[`NonNull::<slice>::len`]: https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html#method.len
+[`ToOwned::clone_into`]: https://doc.rust-lang.org/stable/std/borrow/trait.ToOwned.html#method.clone_into
+[`Ipv6Addr::to_ipv4_mapped`]: https://doc.rust-lang.org/stable/std/net/struct.Ipv6Addr.html#method.to_ipv4_mapped
+[`unix::io::AsFd`]: https://doc.rust-lang.org/stable/std/os/unix/io/trait.AsFd.html
+[`unix::io::BorrowedFd<'fd>`]: https://doc.rust-lang.org/stable/std/os/unix/io/struct.BorrowedFd.html
+[`unix::io::OwnedFd`]: https://doc.rust-lang.org/stable/std/os/unix/io/struct.OwnedFd.html
+[`windows::io::AsHandle`]: https://doc.rust-lang.org/stable/std/os/windows/io/trait.AsHandle.html
+[`windows::io::BorrowedHandle<'handle>`]: https://doc.rust-lang.org/stable/std/os/windows/io/struct.BorrowedHandle.html
+[`windows::io::OwnedHandle`]: https://doc.rust-lang.org/stable/std/os/windows/io/struct.OwnedHandle.html
+[`windows::io::HandleOrInvalid`]: https://doc.rust-lang.org/stable/std/os/windows/io/struct.HandleOrInvalid.html
+[`windows::io::HandleOrNull`]: https://doc.rust-lang.org/stable/std/os/windows/io/struct.HandleOrNull.html
+[`windows::io::InvalidHandleError`]: https://doc.rust-lang.org/stable/std/os/windows/io/struct.InvalidHandleError.html
+[`windows::io::NullHandleError`]: https://doc.rust-lang.org/stable/std/os/windows/io/struct.NullHandleError.html
+[`windows::io::AsSocket`]: https://doc.rust-lang.org/stable/std/os/windows/io/trait.AsSocket.html
+[`windows::io::BorrowedSocket<'handle>`]: https://doc.rust-lang.org/stable/std/os/windows/io/struct.BorrowedSocket.html
+[`windows::io::OwnedSocket`]: https://doc.rust-lang.org/stable/std/os/windows/io/struct.OwnedSocket.html
+[`thread::scope`]: https://doc.rust-lang.org/stable/std/thread/fn.scope.html
+[`thread::Scope`]: https://doc.rust-lang.org/stable/std/thread/struct.Scope.html
+[`thread::ScopedJoinHandle`]: https://doc.rust-lang.org/stable/std/thread/struct.ScopedJoinHandle.html
+
+[`array::from_ref`]: https://doc.rust-lang.org/stable/std/array/fn.from_ref.html
+[`slice::from_ref`]: https://doc.rust-lang.org/stable/std/slice/fn.from_ref.html
+[`intrinsics::copy`]: https://doc.rust-lang.org/stable/std/intrinsics/fn.copy.html
+[`intrinsics::copy_nonoverlapping`]: https://doc.rust-lang.org/stable/std/intrinsics/fn.copy_nonoverlapping.html
+[`<*const T>::copy_to`]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.copy_to
+[`<*const T>::copy_to_nonoverlapping`]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.copy_to_nonoverlapping
+[`<*mut T>::copy_to`]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.copy_to-1
+[`<*mut T>::copy_to_nonoverlapping`]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.copy_to_nonoverlapping-1
+[`<*mut T>::copy_from`]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.copy_from
+[`<*mut T>::copy_from_nonoverlapping`]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.copy_from_nonoverlapping
+[`str::from_utf8`]: https://doc.rust-lang.org/stable/std/str/fn.from_utf8.html
+[`Utf8Error::error_len`]: https://doc.rust-lang.org/stable/std/str/struct.Utf8Error.html#method.error_len
+[`Utf8Error::valid_up_to`]: https://doc.rust-lang.org/stable/std/str/struct.Utf8Error.html#method.valid_up_to
+[`Condvar::new`]: https://doc.rust-lang.org/stable/std/sync/struct.Condvar.html#method.new
+[`Mutex::new`]: https://doc.rust-lang.org/stable/std/sync/struct.Mutex.html#method.new
+[`RwLock::new`]: https://doc.rust-lang.org/stable/std/sync/struct.RwLock.html#method.new
+
+Version 1.62.1 (2022-07-19)
+==========================
+
+Rust 1.62.1 addresses a few recent regressions in the compiler and standard
+library, and also mitigates a CPU vulnerability on Intel SGX.
+
+* [The compiler fixed unsound function coercions involving `impl Trait` return types.][98608]
+* [The compiler fixed an incremental compilation bug with `async fn` lifetimes.][98890]
+* [Windows added a fallback for overlapped I/O in synchronous reads and writes.][98950]
+* [The `x86_64-fortanix-unknown-sgx` target added a mitigation for the
+  MMIO stale data vulnerability][98126], advisory [INTEL-SA-00615].
+
+[98608]: https://github.com/rust-lang/rust/issues/98608
+[98890]: https://github.com/rust-lang/rust/issues/98890
+[98950]: https://github.com/rust-lang/rust/pull/98950
+[98126]: https://github.com/rust-lang/rust/pull/98126
+[INTEL-SA-00615]: https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00615.html
+
 Version 1.62.0 (2022-06-30)
 ==========================
 
index 4ae8edf3157eb3b8665372412489778dc5288341..65a0f66645befec023eb9de8fd11e6a373033072 100644 (file)
@@ -30,7 +30,7 @@
 // FIXME: Implement all operations in DoubleDouble, and delete these
 // semantics.
 // FIXME(eddyb) This shouldn't need to be `pub`, it's only used in bounds.
-pub struct FallbackS<F>(F);
+pub struct FallbackS<F>(#[allow(unused)] F);
 type Fallback<F> = ieee::IeeeFloat<FallbackS<F>>;
 impl<F: Float> ieee::Semantics for FallbackS<F> {
     // Forbid any conversion to/from bits.
@@ -45,7 +45,7 @@ impl<F: Float> ieee::Semantics for FallbackS<F> {
 // truncate the mantissa. The result of that second conversion
 // may be inexact, but should never underflow.
 // FIXME(eddyb) This shouldn't need to be `pub`, it's only used in bounds.
-pub struct FallbackExtendedS<F>(F);
+pub struct FallbackExtendedS<F>(#[allow(unused)] F);
 type FallbackExtended<F> = ieee::IeeeFloat<FallbackExtendedS<F>>;
 impl<F: Float> ieee::Semantics for FallbackExtendedS<F> {
     // Forbid any conversion to/from bits.
index a5f1cbc96daa7ea19a1151f27924eb067290b32e..6529f11100d2d0d9417306b36c4a1ddea39b69f6 100644 (file)
@@ -19,7 +19,6 @@
 #![feature(rustc_attrs)]
 #![cfg_attr(test, feature(test))]
 #![feature(strict_provenance)]
-#![feature(ptr_const_cast)]
 
 use smallvec::SmallVec;
 
index ac2328a582418587a9cfdee68f23ad1d2ac91c0d..3f71fce0e3b318d92962a6f9e34797ba505b683c 100644 (file)
@@ -64,7 +64,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 
 /// A "Lifetime" is an annotation of the scope in which variable
 /// can be used, e.g. `'a` in `&'a i32`.
-#[derive(Clone, Encodable, Decodable, Copy)]
+#[derive(Clone, Encodable, Decodable, Copy, PartialEq, Eq)]
 pub struct Lifetime {
     pub id: NodeId,
     pub ident: Ident,
@@ -1111,10 +1111,6 @@ pub struct Expr {
     pub tokens: Option<LazyTokenStream>,
 }
 
-// `Expr` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Expr, 104);
-
 impl Expr {
     /// Returns `true` if this expression would be valid somewhere that expects a value;
     /// for example, an `if` condition.
@@ -1342,14 +1338,13 @@ pub enum ExprKind {
     ///
     /// The `PathSegment` represents the method name and its generic arguments
     /// (within the angle brackets).
-    /// The first element of the vector of an `Expr` is the expression that evaluates
-    /// to the object on which the method is being called on (the receiver),
-    /// and the remaining elements are the rest of the arguments.
-    /// Thus, `x.foo::<Bar, Baz>(a, b, c, d)` is represented as
-    /// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, [x, a, b, c, d])`.
+    /// The standalone `Expr` is the receiver expression.
+    /// The vector of `Expr` is the arguments.
+    /// `x.foo::<Bar, Baz>(a, b, c, d)` is represented as
+    /// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, x, [a, b, c, d])`.
     /// This `Span` is the span of the function, without the dot and receiver
     /// (e.g. `foo(a, b)` in `x.foo(a, b)`
-    MethodCall(PathSegment, Vec<P<Expr>>, Span),
+    MethodCall(PathSegment, P<Expr>, Vec<P<Expr>>, Span),
     /// A tuple (e.g., `(a, b, c, d)`).
     Tup(Vec<P<Expr>>),
     /// A binary operation (e.g., `a + b`, `a * b`).
@@ -2606,7 +2601,7 @@ pub struct Visibility {
 #[derive(Clone, Encodable, Decodable, Debug)]
 pub enum VisibilityKind {
     Public,
-    Restricted { path: P<Path>, id: NodeId },
+    Restricted { path: P<Path>, id: NodeId, shorthand: bool },
     Inherited,
 }
 
@@ -2883,9 +2878,6 @@ pub enum ItemKind {
     MacroDef(MacroDef),
 }
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(ItemKind, 112);
-
 impl ItemKind {
     pub fn article(&self) -> &str {
         use ItemKind::*;
@@ -2957,9 +2949,6 @@ pub enum AssocItemKind {
     MacCall(MacCall),
 }
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(AssocItemKind, 72);
-
 impl AssocItemKind {
     pub fn defaultness(&self) -> Defaultness {
         match *self {
@@ -3009,9 +2998,6 @@ pub enum ForeignItemKind {
     MacCall(MacCall),
 }
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(ForeignItemKind, 72);
-
 impl From<ForeignItemKind> for ItemKind {
     fn from(foreign_item_kind: ForeignItemKind) -> ItemKind {
         match foreign_item_kind {
@@ -3038,3 +3024,30 @@ fn try_from(item_kind: ItemKind) -> Result<ForeignItemKind, ItemKind> {
 }
 
 pub type ForeignItem = Item<ForeignItemKind>;
+
+// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+mod size_asserts {
+    use super::*;
+    use rustc_data_structures::static_assert_size;
+    // These are in alphabetical order, which is easy to maintain.
+    static_assert_size!(AssocItem, 160);
+    static_assert_size!(AssocItemKind, 72);
+    static_assert_size!(Attribute, 152);
+    static_assert_size!(Block, 48);
+    static_assert_size!(Expr, 104);
+    static_assert_size!(Fn, 192);
+    static_assert_size!(ForeignItem, 160);
+    static_assert_size!(ForeignItemKind, 72);
+    static_assert_size!(GenericBound, 88);
+    static_assert_size!(Generics, 72);
+    static_assert_size!(Impl, 200);
+    static_assert_size!(Item, 200);
+    static_assert_size!(ItemKind, 112);
+    static_assert_size!(Lit, 48);
+    static_assert_size!(Pat, 120);
+    static_assert_size!(Path, 40);
+    static_assert_size!(PathSegment, 24);
+    static_assert_size!(Stmt, 32);
+    static_assert_size!(Ty, 96);
+}
index 01bd498b377800e27e410e977889971ddf5bec94..40c05f43f686deb62c2cee456c72770d9f9c8cc2 100644 (file)
@@ -1302,10 +1302,11 @@ pub fn noop_visit_expr<T: MutVisitor>(
             vis.visit_expr(f);
             visit_exprs(args, vis);
         }
-        ExprKind::MethodCall(PathSegment { ident, id, args }, exprs, span) => {
+        ExprKind::MethodCall(PathSegment { ident, id, args }, receiver, exprs, span) => {
             vis.visit_ident(ident);
             vis.visit_id(id);
             visit_opt(args, |args| vis.visit_generic_args(args));
+            vis.visit_expr(receiver);
             visit_exprs(exprs, vis);
             vis.visit_span(span);
         }
@@ -1486,7 +1487,7 @@ pub fn noop_flat_map_stmt_kind<T: MutVisitor>(
 pub fn noop_visit_vis<T: MutVisitor>(visibility: &mut Visibility, vis: &mut T) {
     match &mut visibility.kind {
         VisibilityKind::Public | VisibilityKind::Inherited => {}
-        VisibilityKind::Restricted { path, id } => {
+        VisibilityKind::Restricted { path, id, shorthand: _ } => {
             vis.visit_path(path);
             vis.visit_id(id);
         }
index b4fff0022e29547e2cd17c2994ac09f528258456..c96474ccb428ae57e6d0ea222299e53ce20d56cd 100644 (file)
@@ -194,7 +194,7 @@ pub fn gather_comments(sm: &SourceMap, path: FileName, src: String) -> Vec<Comme
     }
 
     for token in rustc_lexer::tokenize(&text[pos..]) {
-        let token_text = &text[pos..pos + token.len];
+        let token_text = &text[pos..pos + token.len as usize];
         match token.kind {
             rustc_lexer::TokenKind::Whitespace => {
                 if let Some(mut idx) = token_text.find('\n') {
@@ -211,8 +211,10 @@ pub fn gather_comments(sm: &SourceMap, path: FileName, src: String) -> Vec<Comme
             }
             rustc_lexer::TokenKind::BlockComment { doc_style, .. } => {
                 if doc_style.is_none() {
-                    let code_to_the_right =
-                        !matches!(text[pos + token.len..].chars().next(), Some('\r' | '\n'));
+                    let code_to_the_right = !matches!(
+                        text[pos + token.len as usize..].chars().next(),
+                        Some('\r' | '\n')
+                    );
                     let style = match (code_to_the_left, code_to_the_right) {
                         (_, true) => CommentStyle::Mixed,
                         (false, false) => CommentStyle::Isolated,
@@ -246,7 +248,7 @@ pub fn gather_comments(sm: &SourceMap, path: FileName, src: String) -> Vec<Comme
                 code_to_the_left = true;
             }
         }
-        pos += token.len;
+        pos += token.len as usize;
     }
 
     comments
index 74b7fe9e249552eb3519176f0d8f7b6a045d7d61..5edeb54be5f0f7a2240f56dac26439bb0740d8a2 100644 (file)
@@ -396,9 +396,9 @@ pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
             contains_exterior_struct_lit(&x)
         }
 
-        ast::ExprKind::MethodCall(.., ref exprs, _) => {
+        ast::ExprKind::MethodCall(_, ref receiver, _, _) => {
             // X { y: 1 }.bar(...)
-            contains_exterior_struct_lit(&exprs[0])
+            contains_exterior_struct_lit(&receiver)
         }
 
         _ => false,
index d9594b323dd0d0f7c092b7126fa44134116e063f..4b485b547f49518867d0361dd63ab30b99bc497e 100644 (file)
@@ -168,8 +168,8 @@ fn visit_trait_ref(&mut self, t: &'ast TraitRef) {
     fn visit_param_bound(&mut self, bounds: &'ast GenericBound, _ctxt: BoundKind) {
         walk_param_bound(self, bounds)
     }
-    fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef, m: &'ast TraitBoundModifier) {
-        walk_poly_trait_ref(self, t, m)
+    fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef) {
+        walk_poly_trait_ref(self, t)
     }
     fn visit_variant_data(&mut self, s: &'ast VariantData) {
         walk_struct_def(self, s)
@@ -177,14 +177,8 @@ fn visit_variant_data(&mut self, s: &'ast VariantData) {
     fn visit_field_def(&mut self, s: &'ast FieldDef) {
         walk_field_def(self, s)
     }
-    fn visit_enum_def(
-        &mut self,
-        enum_definition: &'ast EnumDef,
-        generics: &'ast Generics,
-        item_id: NodeId,
-        _: Span,
-    ) {
-        walk_enum_def(self, enum_definition, generics, item_id)
+    fn visit_enum_def(&mut self, enum_definition: &'ast EnumDef) {
+        walk_enum_def(self, enum_definition)
     }
     fn visit_variant(&mut self, v: &'ast Variant) {
         walk_variant(self, v)
@@ -287,11 +281,8 @@ pub fn walk_lifetime<'a, V: Visitor<'a>>(visitor: &mut V, lifetime: &'a Lifetime
     visitor.visit_ident(lifetime.ident);
 }
 
-pub fn walk_poly_trait_ref<'a, V>(
-    visitor: &mut V,
-    trait_ref: &'a PolyTraitRef,
-    _: &TraitBoundModifier,
-) where
+pub fn walk_poly_trait_ref<'a, V>(visitor: &mut V, trait_ref: &'a PolyTraitRef)
+where
     V: Visitor<'a>,
 {
     walk_list!(visitor, visit_generic_param, &trait_ref.bound_generic_params);
@@ -334,7 +325,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
         }
         ItemKind::Enum(ref enum_definition, ref generics) => {
             visitor.visit_generics(generics);
-            visitor.visit_enum_def(enum_definition, generics, item.id, item.span)
+            visitor.visit_enum_def(enum_definition)
         }
         ItemKind::Impl(box Impl {
             defaultness: _,
@@ -377,12 +368,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
     walk_list!(visitor, visit_attribute, &item.attrs);
 }
 
-pub fn walk_enum_def<'a, V: Visitor<'a>>(
-    visitor: &mut V,
-    enum_definition: &'a EnumDef,
-    _: &'a Generics,
-    _: NodeId,
-) {
+pub fn walk_enum_def<'a, V: Visitor<'a>>(visitor: &mut V, enum_definition: &'a EnumDef) {
     walk_list!(visitor, visit_variant, &enum_definition.variants);
 }
 
@@ -598,7 +584,7 @@ pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a ForeignI
 
 pub fn walk_param_bound<'a, V: Visitor<'a>>(visitor: &mut V, bound: &'a GenericBound) {
     match *bound {
-        GenericBound::Trait(ref typ, ref modifier) => visitor.visit_poly_trait_ref(typ, modifier),
+        GenericBound::Trait(ref typ, ref _modifier) => visitor.visit_poly_trait_ref(typ),
         GenericBound::Outlives(ref lifetime) => {
             visitor.visit_lifetime(lifetime, LifetimeCtxt::Bound)
         }
@@ -813,8 +799,9 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
             visitor.visit_expr(callee_expression);
             walk_list!(visitor, visit_expr, arguments);
         }
-        ExprKind::MethodCall(ref segment, ref arguments, _span) => {
+        ExprKind::MethodCall(ref segment, ref receiver, ref arguments, _span) => {
             visitor.visit_path_segment(expression.span, segment);
+            visitor.visit_expr(receiver);
             walk_list!(visitor, visit_expr, arguments);
         }
         ExprKind::Binary(_, ref left_expression, ref right_expression) => {
@@ -935,7 +922,7 @@ pub fn walk_arm<'a, V: Visitor<'a>>(visitor: &mut V, arm: &'a Arm) {
 }
 
 pub fn walk_vis<'a, V: Visitor<'a>>(visitor: &mut V, vis: &'a Visibility) {
-    if let VisibilityKind::Restricted { ref path, id } = vis.kind {
+    if let VisibilityKind::Restricted { ref path, id, shorthand: _ } = vis.kind {
         visitor.visit_path(path, id);
     }
 }
index 983efa48a457982bf8ab37e2b9f0651c68a990a7..92e6bc6013dc2ab4ada6cbba7e0469d3b8b04308 100644 (file)
@@ -62,7 +62,7 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
                         hir::ExprKind::Call(f, self.lower_exprs(args))
                     }
                 }
-                ExprKind::MethodCall(ref seg, ref args, span) => {
+                ExprKind::MethodCall(ref seg, ref receiver, ref args, span) => {
                     let hir_seg = self.arena.alloc(self.lower_path_segment(
                         e.span,
                         seg,
@@ -70,7 +70,9 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
                         ParenthesizedGenericArgs::Err,
                         ImplTraitContext::Disallowed(ImplTraitPosition::Path),
                     ));
-                    let args = self.lower_exprs(args);
+                    let args = self.arena.alloc_from_iter(
+                        [&*receiver].into_iter().chain(args.iter()).map(|x| self.lower_expr_mut(x)),
+                    );
                     hir::ExprKind::MethodCall(hir_seg, args, self.lower_span(span))
                 }
                 ExprKind::Binary(binop, ref lhs, ref rhs) => {
@@ -864,22 +866,21 @@ fn lower_expr_closure(
             (body_id, generator_option)
         });
 
-        self.with_lifetime_binder(closure_id, generic_params, |this, bound_generic_params| {
-            // Lower outside new scope to preserve `is_in_loop_condition`.
-            let fn_decl = this.lower_fn_decl(decl, None, FnDeclKind::Closure, None);
-
-            let c = self.arena.alloc(hir::Closure {
-                binder: binder_clause,
-                capture_clause,
-                bound_generic_params,
-                fn_decl,
-                body: body_id,
-                fn_decl_span: this.lower_span(fn_decl_span),
-                movability: generator_option,
-            });
+        let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
+        // Lower outside new scope to preserve `is_in_loop_condition`.
+        let fn_decl = self.lower_fn_decl(decl, None, FnDeclKind::Closure, None);
+
+        let c = self.arena.alloc(hir::Closure {
+            binder: binder_clause,
+            capture_clause,
+            bound_generic_params,
+            fn_decl,
+            body: body_id,
+            fn_decl_span: self.lower_span(fn_decl_span),
+            movability: generator_option,
+        });
 
-            hir::ExprKind::Closure(c)
-        })
+        hir::ExprKind::Closure(c)
     }
 
     fn generator_movability_for_fn(
@@ -991,23 +992,23 @@ fn lower_expr_async_closure(
             body_id
         });
 
-        self.with_lifetime_binder(closure_id, generic_params, |this, bound_generic_params| {
-            // We need to lower the declaration outside the new scope, because we
-            // have to conserve the state of being inside a loop condition for the
-            // closure argument types.
-            let fn_decl = this.lower_fn_decl(&outer_decl, None, FnDeclKind::Closure, None);
-
-            let c = self.arena.alloc(hir::Closure {
-                binder: binder_clause,
-                capture_clause,
-                bound_generic_params,
-                fn_decl,
-                body,
-                fn_decl_span: this.lower_span(fn_decl_span),
-                movability: None,
-            });
-            hir::ExprKind::Closure(c)
-        })
+        let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
+
+        // We need to lower the declaration outside the new scope, because we
+        // have to conserve the state of being inside a loop condition for the
+        // closure argument types.
+        let fn_decl = self.lower_fn_decl(&outer_decl, None, FnDeclKind::Closure, None);
+
+        let c = self.arena.alloc(hir::Closure {
+            binder: binder_clause,
+            capture_clause,
+            bound_generic_params,
+            fn_decl,
+            body,
+            fn_decl_span: self.lower_span(fn_decl_span),
+            movability: None,
+        });
+        hir::ExprKind::Closure(c)
     }
 
     /// Destructure the LHS of complex assignments.
@@ -1535,15 +1536,13 @@ fn lower_expr_for(
             hir::MatchSource::ForLoopDesugar,
         ));
 
-        let attrs: Vec<_> = e.attrs.iter().map(|a| self.lower_attr(a)).collect();
-
         // This is effectively `{ let _result = ...; _result }`.
         // The construct was introduced in #21984 and is necessary to make sure that
         // temporaries in the `head` expression are dropped and do not leak to the
         // surrounding scope of the `match` since the `match` is not a terminating scope.
         //
         // Also, add the attributes to the outer returned expr node.
-        self.expr_drop_temps_mut(for_span, match_expr, attrs.into())
+        self.expr_drop_temps_mut(for_span, match_expr, e.attrs.clone())
     }
 
     /// Desugar `ExprKind::Try` from: `<expr>?` into:
index ddd54f7c2089dd906154b67b7bf6133a8cef3d6e..e08c1d063c10544aca6fd83785b103c4597c9d30 100644 (file)
@@ -295,14 +295,14 @@ fn visit_lifetime(&mut self, lifetime: &'hir Lifetime) {
         self.insert(lifetime.span, lifetime.hir_id, Node::Lifetime(lifetime));
     }
 
-    fn visit_variant(&mut self, v: &'hir Variant<'hir>, g: &'hir Generics<'hir>, item_id: HirId) {
+    fn visit_variant(&mut self, v: &'hir Variant<'hir>) {
         self.insert(v.span, v.id, Node::Variant(v));
         self.with_parent(v.id, |this| {
             // Register the constructor of this variant.
             if let Some(ctor_hir_id) = v.data.ctor_hir_id() {
                 this.insert(v.span, ctor_hir_id, Node::Ctor(&v.data));
             }
-            intravisit::walk_variant(this, v, g, item_id);
+            intravisit::walk_variant(this, v);
         });
     }
 
@@ -323,7 +323,7 @@ fn visit_assoc_type_binding(&mut self, type_binding: &'hir TypeBinding<'hir>) {
     fn visit_trait_item_ref(&mut self, ii: &'hir TraitItemRef) {
         // Do not visit the duplicate information in TraitItemRef. We want to
         // map the actual nodes, not the duplicate ones in the *Ref.
-        let TraitItemRef { id, ident: _, kind: _, span: _, defaultness: _ } = *ii;
+        let TraitItemRef { id, ident: _, kind: _, span: _ } = *ii;
 
         self.visit_nested_trait_item(id);
     }
@@ -331,8 +331,7 @@ fn visit_trait_item_ref(&mut self, ii: &'hir TraitItemRef) {
     fn visit_impl_item_ref(&mut self, ii: &'hir ImplItemRef) {
         // Do not visit the duplicate information in ImplItemRef. We want to
         // map the actual nodes, not the duplicate ones in the *Ref.
-        let ImplItemRef { id, ident: _, kind: _, span: _, defaultness: _, trait_item_def_id: _ } =
-            *ii;
+        let ImplItemRef { id, ident: _, kind: _, span: _, trait_item_def_id: _ } = *ii;
 
         self.visit_nested_impl_item(id);
     }
index 7da49143b461e2a785038bf64cab2ff490581b83..ee4c0036f76981a3ca444557121fa7ab4dde1e27 100644 (file)
@@ -80,7 +80,6 @@ fn with_lctx(
             generator_kind: None,
             task_context: None,
             current_item: None,
-            captured_lifetimes: None,
             impl_trait_defs: Vec::new(),
             impl_trait_bounds: Vec::new(),
             allow_try_trait: Some([sym::try_trait_v2, sym::yeet_desugar_details][..].into()),
@@ -755,17 +754,17 @@ fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> {
         let hir_id = self.lower_node_id(i.id);
         let trait_item_def_id = hir_id.expect_owner();
 
-        let (generics, kind) = match i.kind {
+        let (generics, kind, has_default) = match i.kind {
             AssocItemKind::Const(_, ref ty, ref default) => {
                 let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
                 let body = default.as_ref().map(|x| self.lower_const_body(i.span, Some(x)));
-                (hir::Generics::empty(), hir::TraitItemKind::Const(ty, body))
+                (hir::Generics::empty(), hir::TraitItemKind::Const(ty, body), body.is_some())
             }
             AssocItemKind::Fn(box Fn { ref sig, ref generics, body: None, .. }) => {
                 let names = self.lower_fn_params_to_names(&sig.decl);
                 let (generics, sig) =
                     self.lower_method_sig(generics, sig, i.id, FnDeclKind::Trait, None);
-                (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)))
+                (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)), false)
             }
             AssocItemKind::Fn(box Fn { ref sig, ref generics, body: Some(ref body), .. }) => {
                 let asyncness = sig.header.asyncness;
@@ -778,7 +777,7 @@ fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> {
                     FnDeclKind::Trait,
                     asyncness.opt_return_id(),
                 );
-                (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)))
+                (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)), true)
             }
             AssocItemKind::TyAlias(box TyAlias {
                 ref generics,
@@ -789,7 +788,7 @@ fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> {
             }) => {
                 let mut generics = generics.clone();
                 add_ty_alias_where_clause(&mut generics, where_clauses, false);
-                self.lower_generics(
+                let (generics, kind) = self.lower_generics(
                     &generics,
                     i.id,
                     ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
@@ -805,7 +804,8 @@ fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> {
                             ty,
                         )
                     },
-                )
+                );
+                (generics, kind, ty.is_some())
             }
             AssocItemKind::MacCall(..) => panic!("macro item shouldn't exist at this point"),
         };
@@ -817,28 +817,25 @@ fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> {
             generics,
             kind,
             span: self.lower_span(i.span),
+            defaultness: hir::Defaultness::Default { has_value: has_default },
         };
         self.arena.alloc(item)
     }
 
     fn lower_trait_item_ref(&mut self, i: &AssocItem) -> hir::TraitItemRef {
-        let (kind, has_default) = match &i.kind {
-            AssocItemKind::Const(_, _, default) => (hir::AssocItemKind::Const, default.is_some()),
-            AssocItemKind::TyAlias(box TyAlias { ty, .. }) => {
-                (hir::AssocItemKind::Type, ty.is_some())
-            }
-            AssocItemKind::Fn(box Fn { sig, body, .. }) => {
-                (hir::AssocItemKind::Fn { has_self: sig.decl.has_self() }, body.is_some())
+        let kind = match &i.kind {
+            AssocItemKind::Const(..) => hir::AssocItemKind::Const,
+            AssocItemKind::TyAlias(..) => hir::AssocItemKind::Type,
+            AssocItemKind::Fn(box Fn { sig, .. }) => {
+                hir::AssocItemKind::Fn { has_self: sig.decl.has_self() }
             }
             AssocItemKind::MacCall(..) => unimplemented!(),
         };
         let id = hir::TraitItemId { def_id: self.local_def_id(i.id) };
-        let defaultness = hir::Defaultness::Default { has_value: has_default };
         hir::TraitItemRef {
             id,
             ident: self.lower_ident(i.ident),
             span: self.lower_span(i.span),
-            defaultness,
             kind,
         }
     }
@@ -849,6 +846,10 @@ pub(crate) fn expr_err(&mut self, span: Span) -> hir::Expr<'hir> {
     }
 
     fn lower_impl_item(&mut self, i: &AssocItem) -> &'hir hir::ImplItem<'hir> {
+        // Since `default impl` is not yet implemented, this is always true in impls.
+        let has_value = true;
+        let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value);
+
         let (generics, kind) = match &i.kind {
             AssocItemKind::Const(_, ty, expr) => {
                 let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
@@ -903,19 +904,16 @@ fn lower_impl_item(&mut self, i: &AssocItem) -> &'hir hir::ImplItem<'hir> {
             kind,
             vis_span: self.lower_span(i.vis.span),
             span: self.lower_span(i.span),
+            defaultness,
         };
         self.arena.alloc(item)
     }
 
     fn lower_impl_item_ref(&mut self, i: &AssocItem) -> hir::ImplItemRef {
-        // Since `default impl` is not yet implemented, this is always true in impls.
-        let has_value = true;
-        let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value);
         hir::ImplItemRef {
             id: hir::ImplItemId { def_id: self.local_def_id(i.id) },
             ident: self.lower_ident(i.ident),
             span: self.lower_span(i.span),
-            defaultness,
             kind: match &i.kind {
                 AssocItemKind::Const(..) => hir::AssocItemKind::Const,
                 AssocItemKind::TyAlias(..) => hir::AssocItemKind::Type,
@@ -1351,12 +1349,12 @@ fn lower_generics<T>(
 
         let mut predicates: SmallVec<[hir::WherePredicate<'hir>; 4]> = SmallVec::new();
         predicates.extend(generics.params.iter().filter_map(|param| {
-            let bounds = self.lower_param_bounds(&param.bounds, itctx);
             self.lower_generic_bound_predicate(
                 param.ident,
                 param.id,
                 &param.kind,
-                bounds,
+                &param.bounds,
+                itctx,
                 PredicateOrigin::GenericParam,
             )
         }));
@@ -1404,13 +1402,17 @@ pub(super) fn lower_generic_bound_predicate(
         ident: Ident,
         id: NodeId,
         kind: &GenericParamKind,
-        bounds: &'hir [hir::GenericBound<'hir>],
+        bounds: &[GenericBound],
+        itctx: ImplTraitContext,
         origin: PredicateOrigin,
     ) -> Option<hir::WherePredicate<'hir>> {
         // Do not create a clause if we do not have anything inside it.
         if bounds.is_empty() {
             return None;
         }
+
+        let bounds = self.lower_param_bounds(bounds, itctx);
+
         let ident = self.lower_ident(ident);
         let param_span = ident.span;
         let span = bounds
@@ -1451,11 +1453,8 @@ pub(super) fn lower_generic_bound_predicate(
             GenericParamKind::Lifetime => {
                 let ident_span = self.lower_span(ident.span);
                 let ident = self.lower_ident(ident);
-                let res = self.resolver.get_lifetime_res(id).unwrap_or_else(|| {
-                    panic!("Missing resolution for lifetime {:?} at {:?}", id, ident.span)
-                });
                 let lt_id = self.next_node_id();
-                let lifetime = self.new_named_lifetime_with_res(lt_id, ident_span, ident, res);
+                let lifetime = self.new_named_lifetime(id, lt_id, ident_span, ident);
                 Some(hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
                     lifetime,
                     span,
index a1bf0f94964bb70e8d342dd18b868482cb0bbb89..38d30d0ffdedbfa8c286be6a95e5c7420b20a7a3 100644 (file)
@@ -45,7 +45,7 @@
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::Lrc;
@@ -56,6 +56,7 @@
 use rustc_hir::definitions::DefPathData;
 use rustc_hir::{ConstArg, GenericArg, ItemLocalId, ParamName, TraitCandidate};
 use rustc_index::vec::{Idx, IndexVec};
+use rustc_middle::span_bug;
 use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
 use rustc_session::parse::feature_err;
 use rustc_span::hygiene::MacroKind;
@@ -77,6 +78,7 @@ macro_rules! arena_vec {
 mod expr;
 mod index;
 mod item;
+mod lifetime_collector;
 mod pat;
 mod path;
 
@@ -110,9 +112,6 @@ struct LoweringContext<'a, 'hir> {
     is_in_trait_impl: bool,
     is_in_dyn_type: bool,
 
-    /// Used to handle lifetimes appearing in impl-traits.
-    captured_lifetimes: Option<LifetimeCaptureContext>,
-
     current_hir_id_owner: LocalDefId,
     item_local_id_counter: hir::ItemLocalId,
     local_id_to_def_id: SortedMap<ItemLocalId, LocalDefId>,
@@ -129,28 +128,6 @@ struct LoweringContext<'a, 'hir> {
     allow_into_future: Option<Lrc<[Symbol]>>,
 }
 
-/// When we lower a lifetime, it is inserted in `captures`, and the resolution is modified so
-/// to point to the lifetime parameter impl-trait will generate.
-/// When traversing `for<...>` binders, they are inserted in `binders_to_ignore` so we know *not*
-/// to rebind the introduced lifetimes.
-#[derive(Debug)]
-struct LifetimeCaptureContext {
-    /// parent def_id for new definitions
-    parent_def_id: LocalDefId,
-    /// Set of lifetimes to rebind.
-    captures: FxHashMap<
-        LocalDefId, // original parameter id
-        (
-            Span,        // Span
-            NodeId,      // synthetized parameter id
-            ParamName,   // parameter name
-            LifetimeRes, // original resolution
-        ),
-    >,
-    /// Traversed binders.  The ids in this set should *not* be rebound.
-    binders_to_ignore: FxHashSet<NodeId>,
-}
-
 trait ResolverAstLoweringExt {
     fn legacy_const_generic_args(&self, expr: &Expr) -> Option<Vec<usize>>;
     fn get_partial_res(&self, id: NodeId) -> Option<PartialRes>;
@@ -159,6 +136,12 @@ trait ResolverAstLoweringExt {
     fn get_lifetime_res(&self, id: NodeId) -> Option<LifetimeRes>;
     fn take_extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)>;
     fn decl_macro_kind(&self, def_id: LocalDefId) -> MacroKind;
+    /// Record the map from `from` local def id to `to` local def id, on `generics_def_id_map`
+    /// field.
+    fn record_def_id_remap(&mut self, from: LocalDefId, to: LocalDefId);
+    /// Get the previously recorded `to` local def id given the `from` local def id, obtained using
+    /// `generics_def_id_map` field.
+    fn get_remapped_def_id(&self, local_def_id: LocalDefId) -> LocalDefId;
 }
 
 impl ResolverAstLoweringExt for ResolverAstLowering {
@@ -226,6 +209,41 @@ fn take_extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, Life
     fn decl_macro_kind(&self, def_id: LocalDefId) -> MacroKind {
         self.builtin_macro_kinds.get(&def_id).copied().unwrap_or(MacroKind::Bang)
     }
+
+    /// Push a remapping into the top-most map.
+    /// Panics if no map has been pushed.
+    /// Remapping is used when creating lowering `-> impl Trait` return
+    /// types to create the resulting opaque type.
+    #[tracing::instrument(level = "debug", skip(self))]
+    fn record_def_id_remap(&mut self, from: LocalDefId, to: LocalDefId) {
+        self.generics_def_id_map.last_mut().expect("no map pushed").insert(from, to);
+    }
+
+    fn get_remapped_def_id(&self, mut local_def_id: LocalDefId) -> LocalDefId {
+        // `generics_def_id_map` is a stack of mappings. As we go deeper in impl traits nesting we
+        // push new mappings so we need to try first the latest mappings, hence `iter().rev()`.
+        //
+        // Consider:
+        //
+        // `fn test<'a, 'b>() -> impl Trait<&'a u8, Ty = impl Sized + 'b> {}`
+        //
+        // We would end with a generics_def_id_map like:
+        //
+        // `[[fn#'b -> impl_trait#'b], [fn#'b -> impl_sized#'b]]`
+        //
+        // for the opaque type generated on `impl Sized + 'b`, We want the result to be:
+        // impl_sized#'b, so iterating forward is the wrong thing to do.
+        for map in self.generics_def_id_map.iter().rev() {
+            if let Some(r) = map.get(&local_def_id) {
+                debug!("def_id_remapper: remapping from `{local_def_id:?}` to `{r:?}`");
+                local_def_id = *r;
+            } else {
+                debug!("def_id_remapper: no remapping for `{local_def_id:?}` found in map");
+            }
+        }
+
+        local_def_id
+    }
 }
 
 /// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree,
@@ -481,8 +499,24 @@ fn next_node_id(&mut self) -> NodeId {
         start
     }
 
+    /// Given the id of some node in the AST, finds the `LocalDefId` associated with it by the name
+    /// resolver (if any), after applying any remapping from `get_remapped_def_id`.
+    ///
+    /// For example, in a function like `fn foo<'a>(x: &'a u32)`,
+    /// invoking with the id from the `ast::Lifetime` node found inside
+    /// the `&'a u32` type would return the `LocalDefId` of the
+    /// `'a` parameter declared on `foo`.
+    ///
+    /// This function also applies remapping from `get_remapped_def_id`.
+    /// These are used when synthesizing opaque types from `-> impl Trait` return types and so forth.
+    /// For example, in a function like `fn foo<'a>() -> impl Debug + 'a`,
+    /// we would create an opaque type `type FooReturn<'a1> = impl Debug + 'a1`.
+    /// When lowering the `Debug + 'a` bounds, we add a remapping to map `'a` to `'a1`.
     fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> {
-        self.resolver.node_id_to_def_id.get(&node).copied()
+        self.resolver
+            .node_id_to_def_id
+            .get(&node)
+            .map(|local_def_id| self.resolver.get_remapped_def_id(*local_def_id))
     }
 
     fn local_def_id(&self, node: NodeId) -> LocalDefId {
@@ -542,6 +576,27 @@ fn with_hir_id_owner(
         debug_assert!(_old.is_none())
     }
 
+    /// Installs the remapping `remap` in scope while `f` is being executed.
+    /// This causes references to the `LocalDefId` keys to be changed to
+    /// refer to the values instead.
+    ///
+    /// The remapping is used when one piece of AST expands to multiple
+    /// pieces of HIR. For example, the function `fn foo<'a>(...) -> impl Debug + 'a`,
+    /// expands to both a function definition (`foo`) and a TAIT for the return value,
+    /// both of which have a lifetime parameter `'a`. The remapping allows us to
+    /// rewrite the `'a` in the return value to refer to the
+    /// `'a` declared on the TAIT, instead of the function.
+    fn with_remapping<R>(
+        &mut self,
+        remap: FxHashMap<LocalDefId, LocalDefId>,
+        f: impl FnOnce(&mut Self) -> R,
+    ) -> R {
+        self.resolver.generics_def_id_map.push(remap);
+        let res = f(self);
+        self.resolver.generics_def_id_map.pop();
+        res
+    }
+
     fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> &'hir hir::OwnerInfo<'hir> {
         let attrs = std::mem::take(&mut self.attrs);
         let mut bodies = std::mem::take(&mut self.bodies);
@@ -751,40 +806,18 @@ fn lifetime_res_to_generic_param(
         })
     }
 
-    /// Setup lifetime capture for and impl-trait.
-    /// The captures will be added to `captures`.
-    fn while_capturing_lifetimes<T>(
-        &mut self,
-        parent_def_id: LocalDefId,
-        captures: &mut FxHashMap<LocalDefId, (Span, NodeId, ParamName, LifetimeRes)>,
-        f: impl FnOnce(&mut Self) -> T,
-    ) -> T {
-        let lifetime_stash = std::mem::replace(
-            &mut self.captured_lifetimes,
-            Some(LifetimeCaptureContext {
-                parent_def_id,
-                captures: std::mem::take(captures),
-                binders_to_ignore: Default::default(),
-            }),
-        );
-
-        let ret = f(self);
-
-        let ctxt = std::mem::replace(&mut self.captured_lifetimes, lifetime_stash).unwrap();
-        *captures = ctxt.captures;
-
-        ret
-    }
-
-    /// Register a binder to be ignored for lifetime capture.
-    #[tracing::instrument(level = "debug", skip(self, f))]
+    /// Lowers a lifetime binder that defines `generic_params`, returning the corresponding HIR
+    /// nodes. The returned list includes any "extra" lifetime parameters that were added by the
+    /// name resolver owing to lifetime elision; this also populates the resolver's node-id->def-id
+    /// map, so that later calls to `opt_node_id_to_def_id` that refer to these extra lifetime
+    /// parameters will be successful.
+    #[tracing::instrument(level = "debug", skip(self))]
     #[inline]
-    fn with_lifetime_binder<T>(
+    fn lower_lifetime_binder(
         &mut self,
         binder: NodeId,
         generic_params: &[GenericParam],
-        f: impl FnOnce(&mut Self, &'hir [hir::GenericParam<'hir>]) -> T,
-    ) -> T {
+    ) -> &'hir [hir::GenericParam<'hir>] {
         let mut generic_params: Vec<_> = self.lower_generic_params_mut(generic_params).collect();
         let extra_lifetimes = self.resolver.take_extra_lifetime_params(binder);
         debug!(?extra_lifetimes);
@@ -794,14 +827,7 @@ fn with_lifetime_binder<T>(
         let generic_params = self.arena.alloc_from_iter(generic_params);
         debug!(?generic_params);
 
-        if let Some(ctxt) = &mut self.captured_lifetimes {
-            ctxt.binders_to_ignore.insert(binder);
-        }
-        let ret = f(self, generic_params);
-        if let Some(ctxt) = &mut self.captured_lifetimes {
-            ctxt.binders_to_ignore.remove(&binder);
-        }
-        ret
+        generic_params
     }
 
     fn with_dyn_type_scope<T>(&mut self, in_scope: bool, f: impl FnOnce(&mut Self) -> T) -> T {
@@ -1215,22 +1241,21 @@ fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir>
                     } else {
                         self.next_node_id()
                     };
-                    let span = self.tcx.sess.source_map().next_point(t.span.shrink_to_lo());
+                    let span = self.tcx.sess.source_map().start_point(t.span);
                     Lifetime { ident: Ident::new(kw::UnderscoreLifetime, span), id }
                 });
                 let lifetime = self.lower_lifetime(&region);
                 hir::TyKind::Rptr(lifetime, self.lower_mt(mt, itctx))
             }
             TyKind::BareFn(ref f) => {
-                self.with_lifetime_binder(t.id, &f.generic_params, |this, generic_params| {
-                    hir::TyKind::BareFn(this.arena.alloc(hir::BareFnTy {
-                        generic_params,
-                        unsafety: this.lower_unsafety(f.unsafety),
-                        abi: this.lower_extern(f.ext),
-                        decl: this.lower_fn_decl(&f.decl, None, FnDeclKind::Pointer, None),
-                        param_names: this.lower_fn_params_to_names(&f.decl),
-                    }))
-                })
+                let generic_params = self.lower_lifetime_binder(t.id, &f.generic_params);
+                hir::TyKind::BareFn(self.arena.alloc(hir::BareFnTy {
+                    generic_params,
+                    unsafety: self.lower_unsafety(f.unsafety),
+                    abi: self.lower_extern(f.ext),
+                    decl: self.lower_fn_decl(&f.decl, None, FnDeclKind::Pointer, None),
+                    param_names: self.lower_fn_params_to_names(&f.decl),
+                }))
             }
             TyKind::Never => hir::TyKind::Never,
             TyKind::Tup(ref tys) => hir::TyKind::Tup(
@@ -1293,17 +1318,17 @@ fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir>
             TyKind::ImplTrait(def_node_id, ref bounds) => {
                 let span = t.span;
                 match itctx {
-                    ImplTraitContext::ReturnPositionOpaqueTy { origin } => self
-                        .lower_opaque_impl_trait(span, origin, def_node_id, |this| {
-                            this.lower_param_bounds(bounds, itctx)
-                        }),
+                    ImplTraitContext::ReturnPositionOpaqueTy { origin } => {
+                        self.lower_opaque_impl_trait(span, origin, def_node_id, bounds, itctx)
+                    }
                     ImplTraitContext::TypeAliasesOpaqueTy => {
                         let nested_itctx = ImplTraitContext::TypeAliasesOpaqueTy;
                         self.lower_opaque_impl_trait(
                             span,
                             hir::OpaqueTyOrigin::TyAlias,
                             def_node_id,
-                            |this| this.lower_param_bounds(bounds, nested_itctx),
+                            bounds,
+                            nested_itctx,
                         )
                     }
                     ImplTraitContext::Universal => {
@@ -1343,13 +1368,43 @@ fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir>
         hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.lower_node_id(t.id) }
     }
 
-    #[tracing::instrument(level = "debug", skip(self, lower_bounds))]
+    /// Lowers a `ReturnPositionOpaqueTy` (`-> impl Trait`) or a `TypeAliasesOpaqueTy` (`type F =
+    /// impl Trait`): this creates the associated Opaque Type (TAIT) definition and then returns a
+    /// HIR type that references the TAIT.
+    ///
+    /// Given a function definition like:
+    ///
+    /// ```rust
+    /// fn test<'a, T: Debug>(x: &'a T) -> impl Debug + 'a {
+    ///     x
+    /// }
+    /// ```
+    ///
+    /// we will create a TAIT definition in the HIR like
+    ///
+    /// ```
+    /// type TestReturn<'a, T, 'x> = impl Debug + 'x
+    /// ```
+    ///
+    /// and return a type like `TestReturn<'static, T, 'a>`, so that the function looks like:
+    ///
+    /// ```rust
+    /// fn test<'a, T: Debug>(x: &'a T) -> TestReturn<'static, T, 'a>
+    /// ```
+    ///
+    /// Note the subtlety around type parameters! The new TAIT, `TestReturn`, inherits all the
+    /// type parameters from the function `test` (this is implemented in the query layer, they aren't
+    /// added explicitly in the HIR). But this includes all the lifetimes, and we only want to
+    /// capture the lifetimes that are referenced in the bounds. Therefore, we add *extra* lifetime parameters
+    /// for the lifetimes that get captured (`'x`, in our example above) and reference those.
+    #[tracing::instrument(level = "debug", skip(self))]
     fn lower_opaque_impl_trait(
         &mut self,
         span: Span,
         origin: hir::OpaqueTyOrigin,
         opaque_ty_node_id: NodeId,
-        lower_bounds: impl FnOnce(&mut Self) -> hir::GenericBounds<'hir>,
+        bounds: &GenericBounds,
+        itctx: ImplTraitContext,
     ) -> hir::TyKind<'hir> {
         // Make sure we know that some funky desugaring has been going on here.
         // This is a first: there is code in other places like for loop
@@ -1359,70 +1414,108 @@ fn lower_opaque_impl_trait(
         let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None);
 
         let opaque_ty_def_id = self.local_def_id(opaque_ty_node_id);
+        debug!(?opaque_ty_def_id);
 
-        let mut collected_lifetimes = FxHashMap::default();
-        self.with_hir_id_owner(opaque_ty_node_id, |lctx| {
-            let hir_bounds = if origin == hir::OpaqueTyOrigin::TyAlias {
-                lower_bounds(lctx)
-            } else {
-                lctx.while_capturing_lifetimes(
-                    opaque_ty_def_id,
-                    &mut collected_lifetimes,
-                    lower_bounds,
-                )
-            };
-            debug!(?collected_lifetimes);
+        // Contains the new lifetime definitions created for the TAIT (if any).
+        let mut collected_lifetimes = Vec::new();
 
-            let lifetime_defs = lctx.arena.alloc_from_iter(collected_lifetimes.iter().map(
-                |(_, &(span, p_id, p_name, _))| {
-                    let hir_id = lctx.lower_node_id(p_id);
-                    debug_assert_ne!(lctx.opt_local_def_id(p_id), None);
+        // If this came from a TAIT (as opposed to a function that returns an RPIT), we only want
+        // to capture the lifetimes that appear in the bounds. So visit the bounds to find out
+        // exactly which ones those are.
+        let lifetimes_to_remap = if origin == hir::OpaqueTyOrigin::TyAlias {
+            // in a TAIT like `type Foo<'a> = impl Foo<'a>`, we don't keep all the lifetime parameters
+            Vec::new()
+        } else {
+            // in fn return position, like the `fn test<'a>() -> impl Debug + 'a` example,
+            // we only keep the lifetimes that appear in the `impl Debug` itself:
+            lifetime_collector::lifetimes_in_bounds(&self.resolver, bounds)
+        };
+        debug!(?lifetimes_to_remap);
 
-                    let kind = if p_name.ident().name == kw::UnderscoreLifetime {
-                        hir::LifetimeParamKind::Elided
-                    } else {
-                        hir::LifetimeParamKind::Explicit
-                    };
+        self.with_hir_id_owner(opaque_ty_node_id, |lctx| {
+            let mut new_remapping = FxHashMap::default();
+
+            // If this opaque type is only capturing a subset of the lifetimes (those that appear
+            // in bounds), then create the new lifetime parameters required and create a mapping
+            // from the old `'a` (on the function) to the new `'a` (on the opaque type).
+            collected_lifetimes = lctx.create_lifetime_defs(
+                opaque_ty_def_id,
+                &lifetimes_to_remap,
+                &mut new_remapping,
+            );
+            debug!(?collected_lifetimes);
+            debug!(?new_remapping);
+
+            // Install the remapping from old to new (if any):
+            lctx.with_remapping(new_remapping, |lctx| {
+                // This creates HIR lifetime definitions as `hir::GenericParam`, in the given
+                // example `type TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection
+                // containing `&['x]`.
+                let lifetime_defs = lctx.arena.alloc_from_iter(collected_lifetimes.iter().map(
+                    |&(new_node_id, lifetime)| {
+                        let hir_id = lctx.lower_node_id(new_node_id);
+                        debug_assert_ne!(lctx.opt_local_def_id(new_node_id), None);
+
+                        let (name, kind) = if lifetime.ident.name == kw::UnderscoreLifetime {
+                            (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided)
+                        } else {
+                            (
+                                hir::ParamName::Plain(lifetime.ident),
+                                hir::LifetimeParamKind::Explicit,
+                            )
+                        };
 
-                    hir::GenericParam {
-                        hir_id,
-                        name: p_name,
-                        span,
-                        pure_wrt_drop: false,
-                        kind: hir::GenericParamKind::Lifetime { kind },
-                        colon_span: None,
-                    }
-                },
-            ));
-
-            debug!("lower_opaque_impl_trait: lifetime_defs={:#?}", lifetime_defs);
-
-            let opaque_ty_item = hir::OpaqueTy {
-                generics: self.arena.alloc(hir::Generics {
-                    params: lifetime_defs,
-                    predicates: &[],
-                    has_where_clause_predicates: false,
-                    where_clause_span: lctx.lower_span(span),
-                    span: lctx.lower_span(span),
-                }),
-                bounds: hir_bounds,
-                origin,
-            };
+                        hir::GenericParam {
+                            hir_id,
+                            name,
+                            span: lifetime.ident.span,
+                            pure_wrt_drop: false,
+                            kind: hir::GenericParamKind::Lifetime { kind },
+                            colon_span: None,
+                        }
+                    },
+                ));
+                debug!(?lifetime_defs);
+
+                // Then when we lower the param bounds, references to 'a are remapped to 'a1, so we
+                // get back Debug + 'a1, which is suitable for use on the TAIT.
+                let hir_bounds = lctx.lower_param_bounds(bounds, itctx);
+                debug!(?hir_bounds);
+
+                let opaque_ty_item = hir::OpaqueTy {
+                    generics: self.arena.alloc(hir::Generics {
+                        params: lifetime_defs,
+                        predicates: &[],
+                        has_where_clause_predicates: false,
+                        where_clause_span: lctx.lower_span(span),
+                        span: lctx.lower_span(span),
+                    }),
+                    bounds: hir_bounds,
+                    origin,
+                };
+                debug!(?opaque_ty_item);
 
-            trace!("lower_opaque_impl_trait: {:#?}", opaque_ty_def_id);
-            lctx.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span)
+                lctx.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span)
+            })
         });
 
-        let lifetimes = self.arena.alloc_from_iter(collected_lifetimes.into_iter().map(
-            |(_, (span, _, p_name, res))| {
+        // This creates HIR lifetime arguments as `hir::GenericArg`, in the given example `type
+        // TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection containing `&['x]`.
+        let lifetimes =
+            self.arena.alloc_from_iter(collected_lifetimes.into_iter().map(|(_, lifetime)| {
                 let id = self.next_node_id();
-                let ident = Ident::new(p_name.ident().name, span);
-                let l = self.new_named_lifetime_with_res(id, span, ident, res);
-                hir::GenericArg::Lifetime(l)
-            },
-        ));
+                let span = lifetime.ident.span;
 
-        debug!("lower_opaque_impl_trait: lifetimes={:#?}", lifetimes);
+                let ident = if lifetime.ident.name == kw::UnderscoreLifetime {
+                    Ident::with_dummy_span(kw::UnderscoreLifetime)
+                } else {
+                    lifetime.ident
+                };
+
+                let l = self.new_named_lifetime(lifetime.id, id, span, ident);
+                hir::GenericArg::Lifetime(l)
+            }));
+        debug!(?lifetimes);
 
         // `impl Trait` now just becomes `Foo<'a, 'b, ..>`.
         hir::TyKind::OpaqueDef(hir::ItemId { def_id: opaque_ty_def_id }, lifetimes)
@@ -1450,6 +1543,70 @@ fn generate_opaque_type(
         hir::OwnerNode::Item(self.arena.alloc(opaque_ty_item))
     }
 
+    /// Given a `parent_def_id`, a list of `lifetimes_in_bounds and a `remapping` hash to be
+    /// filled, this function creates new definitions for `Param` and `Fresh` lifetimes, inserts the
+    /// new definition, adds it to the remapping with the definition of the given lifetime and
+    /// returns a list of lifetimes to be lowered afterwards.
+    fn create_lifetime_defs(
+        &mut self,
+        parent_def_id: LocalDefId,
+        lifetimes_in_bounds: &[Lifetime],
+        remapping: &mut FxHashMap<LocalDefId, LocalDefId>,
+    ) -> Vec<(NodeId, Lifetime)> {
+        let mut result = Vec::new();
+
+        for lifetime in lifetimes_in_bounds {
+            let res = self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error);
+            debug!(?res);
+
+            match res {
+                LifetimeRes::Param { param: old_def_id, binder: _ } => {
+                    if remapping.get(&old_def_id).is_none() {
+                        let node_id = self.next_node_id();
+
+                        let new_def_id = self.create_def(
+                            parent_def_id,
+                            node_id,
+                            DefPathData::LifetimeNs(lifetime.ident.name),
+                        );
+                        remapping.insert(old_def_id, new_def_id);
+
+                        result.push((node_id, *lifetime));
+                    }
+                }
+
+                LifetimeRes::Fresh { param, binder: _ } => {
+                    debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime);
+                    let old_def_id = self.local_def_id(param);
+                    if remapping.get(&old_def_id).is_none() {
+                        let node_id = self.next_node_id();
+
+                        let new_def_id = self.create_def(
+                            parent_def_id,
+                            node_id,
+                            DefPathData::LifetimeNs(kw::UnderscoreLifetime),
+                        );
+                        remapping.insert(old_def_id, new_def_id);
+
+                        result.push((node_id, *lifetime));
+                    }
+                }
+
+                LifetimeRes::Static | LifetimeRes::Error => {}
+
+                res => {
+                    let bug_msg = format!(
+                        "Unexpected lifetime resolution {:?} for {:?} at {:?}",
+                        res, lifetime.ident, lifetime.ident.span
+                    );
+                    span_bug!(lifetime.ident.span, "{}", bug_msg);
+                }
+            }
+        }
+
+        result
+    }
+
     fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Ident] {
         // Skip the `...` (`CVarArgs`) trailing arguments from the AST,
         // as they are not explicit in HIR/Ty function signatures.
@@ -1582,11 +1739,9 @@ fn lower_fn_decl(
     //
     //     type OpaqueTy<generics_from_parent_fn> = impl Future<Output = T>;
     //
-    // `inputs`: lowered types of parameters to the function (used to collect lifetimes)
     // `output`: unlowered output type (`T` in `-> T`)
     // `fn_def_id`: `DefId` of the parent function (used to create child impl trait definition)
     // `opaque_ty_node_id`: `NodeId` of the opaque `impl Trait` type that should be created
-    // `elided_lt_replacement`: replacement for elided lifetimes in the return type
     #[tracing::instrument(level = "debug", skip(self))]
     fn lower_async_fn_ret_ty(
         &mut self,
@@ -1643,90 +1798,126 @@ fn lower_async_fn_ret_ty(
         // by the opaque type. This should include all in-scope
         // lifetime parameters, including those defined in-band.
 
-        let mut captures = FxHashMap::default();
+        // Contains the new lifetime definitions created for the TAIT (if any) generated for the
+        // return type.
+        let mut collected_lifetimes = Vec::new();
+        let mut new_remapping = FxHashMap::default();
 
         let extra_lifetime_params = self.resolver.take_extra_lifetime_params(opaque_ty_node_id);
         debug!(?extra_lifetime_params);
         for (ident, outer_node_id, outer_res) in extra_lifetime_params {
-            let Ident { name, span } = ident;
             let outer_def_id = self.local_def_id(outer_node_id);
             let inner_node_id = self.next_node_id();
 
             // Add a definition for the in scope lifetime def.
-            self.create_def(opaque_ty_def_id, inner_node_id, DefPathData::LifetimeNs(name));
+            let inner_def_id = self.create_def(
+                opaque_ty_def_id,
+                inner_node_id,
+                DefPathData::LifetimeNs(ident.name),
+            );
+            new_remapping.insert(outer_def_id, inner_def_id);
 
-            let (p_name, inner_res) = match outer_res {
+            let inner_res = match outer_res {
                 // Input lifetime like `'a`:
                 LifetimeRes::Param { param, .. } => {
-                    (hir::ParamName::Plain(ident), LifetimeRes::Param { param, binder: fn_node_id })
+                    LifetimeRes::Param { param, binder: fn_node_id }
                 }
                 // Input lifetime like `'1`:
                 LifetimeRes::Fresh { param, .. } => {
-                    (hir::ParamName::Fresh, LifetimeRes::Fresh { param, binder: fn_node_id })
+                    LifetimeRes::Fresh { param, binder: fn_node_id }
                 }
                 LifetimeRes::Static | LifetimeRes::Error => continue,
                 res => {
-                    panic!("Unexpected lifetime resolution {:?} for {:?} at {:?}", res, ident, span)
+                    panic!(
+                        "Unexpected lifetime resolution {:?} for {:?} at {:?}",
+                        res, ident, ident.span
+                    )
                 }
             };
 
-            captures.insert(outer_def_id, (span, inner_node_id, p_name, inner_res));
+            let lifetime = Lifetime { id: outer_node_id, ident };
+            collected_lifetimes.push((inner_node_id, lifetime, Some(inner_res)));
         }
 
-        debug!(?captures);
-
-        self.with_hir_id_owner(opaque_ty_node_id, |this| {
-            let future_bound =
-                this.while_capturing_lifetimes(opaque_ty_def_id, &mut captures, |this| {
-                    // We have to be careful to get elision right here. The
-                    // idea is that we create a lifetime parameter for each
-                    // lifetime in the return type.  So, given a return type
-                    // like `async fn foo(..) -> &[&u32]`, we lower to `impl
-                    // Future<Output = &'1 [ &'2 u32 ]>`.
-                    //
-                    // Then, we will create `fn foo(..) -> Foo<'_, '_>`, and
-                    // hence the elision takes place at the fn site.
-                    this.lower_async_fn_output_type_to_future_bound(output, fn_def_id, span)
-                });
-            debug!("lower_async_fn_ret_ty: future_bound={:#?}", future_bound);
-            debug!("lower_async_fn_ret_ty: captures={:#?}", captures);
+        debug!(?collected_lifetimes);
 
-            let generic_params =
-                this.arena.alloc_from_iter(captures.iter().map(|(_, &(span, p_id, p_name, _))| {
-                    let hir_id = this.lower_node_id(p_id);
-                    debug_assert_ne!(this.opt_local_def_id(p_id), None);
+        // We only want to capture the lifetimes that appear in the bounds. So visit the bounds to
+        // find out exactly which ones those are.
+        // in fn return position, like the `fn test<'a>() -> impl Debug + 'a` example,
+        // we only keep the lifetimes that appear in the `impl Debug` itself:
+        let lifetimes_to_remap = lifetime_collector::lifetimes_in_ret_ty(&self.resolver, output);
+        debug!(?lifetimes_to_remap);
 
-                    let kind = if p_name.ident().name == kw::UnderscoreLifetime {
-                        hir::LifetimeParamKind::Elided
-                    } else {
-                        hir::LifetimeParamKind::Explicit
-                    };
+        self.with_hir_id_owner(opaque_ty_node_id, |this| {
+            // If this opaque type is only capturing a subset of the lifetimes (those that appear
+            // in bounds), then create the new lifetime parameters required and create a mapping
+            // from the old `'a` (on the function) to the new `'a` (on the opaque type).
+            collected_lifetimes.extend(
+                this.create_lifetime_defs(
+                    opaque_ty_def_id,
+                    &lifetimes_to_remap,
+                    &mut new_remapping,
+                )
+                .into_iter()
+                .map(|(new_node_id, lifetime)| (new_node_id, lifetime, None)),
+            );
+            debug!(?collected_lifetimes);
+            debug!(?new_remapping);
+
+            // Install the remapping from old to new (if any):
+            this.with_remapping(new_remapping, |this| {
+                // We have to be careful to get elision right here. The
+                // idea is that we create a lifetime parameter for each
+                // lifetime in the return type.  So, given a return type
+                // like `async fn foo(..) -> &[&u32]`, we lower to `impl
+                // Future<Output = &'1 [ &'2 u32 ]>`.
+                //
+                // Then, we will create `fn foo(..) -> Foo<'_, '_>`, and
+                // hence the elision takes place at the fn site.
+                let future_bound =
+                    this.lower_async_fn_output_type_to_future_bound(output, fn_def_id, span);
+
+                let generic_params = this.arena.alloc_from_iter(collected_lifetimes.iter().map(
+                    |&(new_node_id, lifetime, _)| {
+                        let hir_id = this.lower_node_id(new_node_id);
+                        debug_assert_ne!(this.opt_local_def_id(new_node_id), None);
+
+                        let (name, kind) = if lifetime.ident.name == kw::UnderscoreLifetime {
+                            (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided)
+                        } else {
+                            (
+                                hir::ParamName::Plain(lifetime.ident),
+                                hir::LifetimeParamKind::Explicit,
+                            )
+                        };
 
-                    hir::GenericParam {
-                        hir_id,
-                        name: p_name,
-                        span,
-                        pure_wrt_drop: false,
-                        kind: hir::GenericParamKind::Lifetime { kind },
-                        colon_span: None,
-                    }
-                }));
-            debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params);
-
-            let opaque_ty_item = hir::OpaqueTy {
-                generics: this.arena.alloc(hir::Generics {
-                    params: generic_params,
-                    predicates: &[],
-                    has_where_clause_predicates: false,
-                    where_clause_span: this.lower_span(span),
-                    span: this.lower_span(span),
-                }),
-                bounds: arena_vec![this; future_bound],
-                origin: hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
-            };
+                        hir::GenericParam {
+                            hir_id,
+                            name,
+                            span: lifetime.ident.span,
+                            pure_wrt_drop: false,
+                            kind: hir::GenericParamKind::Lifetime { kind },
+                            colon_span: None,
+                        }
+                    },
+                ));
+                debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params);
+
+                let opaque_ty_item = hir::OpaqueTy {
+                    generics: this.arena.alloc(hir::Generics {
+                        params: generic_params,
+                        predicates: &[],
+                        has_where_clause_predicates: false,
+                        where_clause_span: this.lower_span(span),
+                        span: this.lower_span(span),
+                    }),
+                    bounds: arena_vec![this; future_bound],
+                    origin: hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
+                };
 
-            trace!("exist ty from async fn def id: {:#?}", opaque_ty_def_id);
-            this.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span)
+                trace!("exist ty from async fn def id: {:#?}", opaque_ty_def_id);
+                this.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span)
+            })
         });
 
         // As documented above, we need to create the lifetime
@@ -1744,13 +1935,24 @@ fn lower_async_fn_ret_ty(
         //
         // For the "output" lifetime parameters, we just want to
         // generate `'_`.
-        let generic_args =
-            self.arena.alloc_from_iter(captures.into_iter().map(|(_, (span, _, p_name, res))| {
+        let generic_args = self.arena.alloc_from_iter(collected_lifetimes.into_iter().map(
+            |(_, lifetime, res)| {
                 let id = self.next_node_id();
-                let ident = Ident::new(p_name.ident().name, span);
+                let span = lifetime.ident.span;
+
+                let ident = if lifetime.ident.name == kw::UnderscoreLifetime {
+                    Ident::with_dummy_span(kw::UnderscoreLifetime)
+                } else {
+                    lifetime.ident
+                };
+
+                let res = res.unwrap_or(
+                    self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error),
+                );
                 let l = self.new_named_lifetime_with_res(id, span, ident, res);
                 hir::GenericArg::Lifetime(l)
-            }));
+            },
+        ));
 
         // Create the `Foo<...>` reference itself. Note that the `type
         // Foo = impl Trait` is, internally, created as a child of the
@@ -1820,8 +2022,7 @@ fn lower_param_bound(
     fn lower_lifetime(&mut self, l: &Lifetime) -> hir::Lifetime {
         let span = self.lower_span(l.ident.span);
         let ident = self.lower_ident(l.ident);
-        let res = self.resolver.get_lifetime_res(l.id).unwrap_or(LifetimeRes::Error);
-        self.new_named_lifetime_with_res(l.id, span, ident, res)
+        self.new_named_lifetime(l.id, l.id, span, ident)
     }
 
     #[tracing::instrument(level = "debug", skip(self))]
@@ -1832,55 +2033,17 @@ fn new_named_lifetime_with_res(
         ident: Ident,
         res: LifetimeRes,
     ) -> hir::Lifetime {
-        debug!(?self.captured_lifetimes);
         let name = match res {
-            LifetimeRes::Param { mut param, binder } => {
+            LifetimeRes::Param { param, .. } => {
                 let p_name = ParamName::Plain(ident);
-                if let Some(mut captured_lifetimes) = self.captured_lifetimes.take() {
-                    if !captured_lifetimes.binders_to_ignore.contains(&binder) {
-                        match captured_lifetimes.captures.entry(param) {
-                            Entry::Occupied(o) => param = self.local_def_id(o.get().1),
-                            Entry::Vacant(v) => {
-                                let p_id = self.next_node_id();
-                                let p_def_id = self.create_def(
-                                    captured_lifetimes.parent_def_id,
-                                    p_id,
-                                    DefPathData::LifetimeNs(p_name.ident().name),
-                                );
-
-                                v.insert((span, p_id, p_name, res));
-                                param = p_def_id;
-                            }
-                        }
-                    }
+                let param = self.resolver.get_remapped_def_id(param);
 
-                    self.captured_lifetimes = Some(captured_lifetimes);
-                }
                 hir::LifetimeName::Param(param, p_name)
             }
-            LifetimeRes::Fresh { param, binder } => {
+            LifetimeRes::Fresh { param, .. } => {
                 debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
-                let mut param = self.local_def_id(param);
-                if let Some(mut captured_lifetimes) = self.captured_lifetimes.take() {
-                    if !captured_lifetimes.binders_to_ignore.contains(&binder) {
-                        match captured_lifetimes.captures.entry(param) {
-                            Entry::Occupied(o) => param = self.local_def_id(o.get().1),
-                            Entry::Vacant(v) => {
-                                let p_id = self.next_node_id();
-                                let p_def_id = self.create_def(
-                                    captured_lifetimes.parent_def_id,
-                                    p_id,
-                                    DefPathData::LifetimeNs(kw::UnderscoreLifetime),
-                                );
-
-                                v.insert((span, p_id, ParamName::Fresh, res));
-                                param = p_def_id;
-                            }
-                        }
-                    }
+                let param = self.local_def_id(param);
 
-                    self.captured_lifetimes = Some(captured_lifetimes);
-                }
                 hir::LifetimeName::Param(param, ParamName::Fresh)
             }
             LifetimeRes::Infer => hir::LifetimeName::Infer,
@@ -1888,11 +2051,23 @@ fn new_named_lifetime_with_res(
             LifetimeRes::Error => hir::LifetimeName::Error,
             res => panic!("Unexpected lifetime resolution {:?} for {:?} at {:?}", res, ident, span),
         };
-        debug!(?self.captured_lifetimes);
+
         debug!(?name);
         hir::Lifetime { hir_id: self.lower_node_id(id), span: self.lower_span(span), name }
     }
 
+    #[tracing::instrument(level = "debug", skip(self))]
+    fn new_named_lifetime(
+        &mut self,
+        id: NodeId,
+        new_id: NodeId,
+        span: Span,
+        ident: Ident,
+    ) -> hir::Lifetime {
+        let res = self.resolver.get_lifetime_res(id).unwrap_or(LifetimeRes::Error);
+        self.new_named_lifetime_with_res(new_id, span, ident, res)
+    }
+
     fn lower_generic_params_mut<'s>(
         &'s mut self,
         params: &'s [GenericParam],
@@ -1975,14 +2150,10 @@ fn lower_poly_trait_ref(
         p: &PolyTraitRef,
         itctx: ImplTraitContext,
     ) -> hir::PolyTraitRef<'hir> {
-        self.with_lifetime_binder(
-            p.trait_ref.ref_id,
-            &p.bound_generic_params,
-            |this, bound_generic_params| {
-                let trait_ref = this.lower_trait_ref(&p.trait_ref, itctx);
-                hir::PolyTraitRef { bound_generic_params, trait_ref, span: this.lower_span(p.span) }
-            },
-        )
+        let bound_generic_params =
+            self.lower_lifetime_binder(p.trait_ref.ref_id, &p.bound_generic_params);
+        let trait_ref = self.lower_trait_ref(&p.trait_ref, itctx);
+        hir::PolyTraitRef { bound_generic_params, trait_ref, span: self.lower_span(p.span) }
     }
 
     fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext) -> hir::MutTy<'hir> {
@@ -2015,7 +2186,6 @@ fn lower_generic_and_bounds(
         // Add a definition for the in-band `Param`.
         let def_id = self.local_def_id(node_id);
 
-        let hir_bounds = self.lower_param_bounds(bounds, ImplTraitContext::Universal);
         // Set the name to `impl Bound1 + Bound2`.
         let param = hir::GenericParam {
             hir_id: self.lower_node_id(node_id),
@@ -2030,7 +2200,8 @@ fn lower_generic_and_bounds(
             ident,
             node_id,
             &GenericParamKind::Type { default: None },
-            hir_bounds,
+            bounds,
+            ImplTraitContext::Universal,
             hir::PredicateOrigin::ImplTrait,
         );
 
diff --git a/compiler/rustc_ast_lowering/src/lifetime_collector.rs b/compiler/rustc_ast_lowering/src/lifetime_collector.rs
new file mode 100644 (file)
index 0000000..8c67ceb
--- /dev/null
@@ -0,0 +1,112 @@
+use super::ResolverAstLoweringExt;
+use rustc_ast::visit::{self, BoundKind, LifetimeCtxt, Visitor};
+use rustc_ast::{FnRetTy, GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, Ty, TyKind};
+use rustc_hir::def::LifetimeRes;
+use rustc_middle::span_bug;
+use rustc_middle::ty::ResolverAstLowering;
+use rustc_span::symbol::{kw, Ident};
+use rustc_span::Span;
+
+struct LifetimeCollectVisitor<'ast> {
+    resolver: &'ast ResolverAstLowering,
+    current_binders: Vec<NodeId>,
+    collected_lifetimes: Vec<Lifetime>,
+}
+
+impl<'ast> LifetimeCollectVisitor<'ast> {
+    fn new(resolver: &'ast ResolverAstLowering) -> Self {
+        Self { resolver, current_binders: Vec::new(), collected_lifetimes: Vec::new() }
+    }
+
+    fn record_lifetime_use(&mut self, lifetime: Lifetime) {
+        match self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error) {
+            LifetimeRes::Param { binder, .. } | LifetimeRes::Fresh { binder, .. } => {
+                if !self.current_binders.contains(&binder) {
+                    if !self.collected_lifetimes.contains(&lifetime) {
+                        self.collected_lifetimes.push(lifetime);
+                    }
+                }
+            }
+            LifetimeRes::Static | LifetimeRes::Error => {
+                if !self.collected_lifetimes.contains(&lifetime) {
+                    self.collected_lifetimes.push(lifetime);
+                }
+            }
+            LifetimeRes::Infer => {}
+            res => {
+                let bug_msg = format!(
+                    "Unexpected lifetime resolution {:?} for {:?} at {:?}",
+                    res, lifetime.ident, lifetime.ident.span
+                );
+                span_bug!(lifetime.ident.span, "{}", bug_msg);
+            }
+        }
+    }
+
+    /// This collect lifetimes that are elided, for nodes like `Foo<T>` where there are no explicit
+    /// lifetime nodes. Is equivalent to having "pseudo" nodes introduced for each of the node ids
+    /// in the list start..end.
+    fn record_elided_anchor(&mut self, node_id: NodeId, span: Span) {
+        if let Some(LifetimeRes::ElidedAnchor { start, end }) =
+            self.resolver.get_lifetime_res(node_id)
+        {
+            for i in start..end {
+                let lifetime = Lifetime { id: i, ident: Ident::new(kw::UnderscoreLifetime, span) };
+                self.record_lifetime_use(lifetime);
+            }
+        }
+    }
+}
+
+impl<'ast> Visitor<'ast> for LifetimeCollectVisitor<'ast> {
+    fn visit_lifetime(&mut self, lifetime: &'ast Lifetime, _: LifetimeCtxt) {
+        self.record_lifetime_use(*lifetime);
+    }
+
+    fn visit_path_segment(&mut self, path_span: Span, path_segment: &'ast PathSegment) {
+        self.record_elided_anchor(path_segment.id, path_span);
+        visit::walk_path_segment(self, path_span, path_segment);
+    }
+
+    fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef) {
+        self.current_binders.push(t.trait_ref.ref_id);
+
+        visit::walk_poly_trait_ref(self, t);
+
+        self.current_binders.pop();
+    }
+
+    fn visit_ty(&mut self, t: &'ast Ty) {
+        match t.kind {
+            TyKind::BareFn(_) => {
+                self.current_binders.push(t.id);
+                visit::walk_ty(self, t);
+                self.current_binders.pop();
+            }
+            TyKind::Rptr(None, _) => {
+                self.record_elided_anchor(t.id, t.span);
+                visit::walk_ty(self, t);
+            }
+            _ => {
+                visit::walk_ty(self, t);
+            }
+        }
+    }
+}
+
+pub fn lifetimes_in_ret_ty(resolver: &ResolverAstLowering, ret_ty: &FnRetTy) -> Vec<Lifetime> {
+    let mut visitor = LifetimeCollectVisitor::new(resolver);
+    visitor.visit_fn_ret_ty(ret_ty);
+    visitor.collected_lifetimes
+}
+
+pub fn lifetimes_in_bounds(
+    resolver: &ResolverAstLowering,
+    bounds: &GenericBounds,
+) -> Vec<Lifetime> {
+    let mut visitor = LifetimeCollectVisitor::new(resolver);
+    for bound in bounds {
+        visitor.visit_param_bound(bound, BoundKind::Bound);
+    }
+    visitor.collected_lifetimes
+}
index 60560b1c00e251ee262e7f10f092c3d1aee109ef..e61dfef7bd380394b28d3f0711c4a22cf8445a80 100644 (file)
@@ -13,9 +13,7 @@
 use rustc_ast::*;
 use rustc_ast_pretty::pprust::{self, State};
 use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::{
-    error_code, pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed,
-};
+use rustc_errors::{error_code, pluralize, struct_span_err, Applicability, Diagnostic};
 use rustc_parse::validate_attr;
 use rustc_session::lint::builtin::{
     DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY,
@@ -477,7 +475,7 @@ fn error_item_without_body_with_help(
         ctx: &str,
         msg: &str,
         sugg: &str,
-        help: impl FnOnce(&mut DiagnosticBuilder<'_, ErrorGuaranteed>),
+        help: impl FnOnce(&mut Diagnostic),
     ) {
         let source_map = self.session.source_map();
         let end = source_map.end_point(sp);
@@ -1196,7 +1194,7 @@ fn visit_item(&mut self, item: &'a Item) {
                     let msg = "free function without a body";
                     let ext = sig.header.ext;
 
-                    let f = |e: &mut DiagnosticBuilder<'_, _>| {
+                    let f = |e: &mut Diagnostic| {
                         if let Extern::Implicit(start_span) | Extern::Explicit(_, start_span) = &ext
                         {
                             let start_suggestion = if let Extern::Explicit(abi, _) = ext {
@@ -1538,25 +1536,17 @@ fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) {
         visit::walk_param_bound(self, bound)
     }
 
-    fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifier) {
+    fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef) {
         self.check_late_bound_lifetime_defs(&t.bound_generic_params);
-        visit::walk_poly_trait_ref(self, t, m);
+        visit::walk_poly_trait_ref(self, t);
     }
 
     fn visit_variant_data(&mut self, s: &'a VariantData) {
         self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
     }
 
-    fn visit_enum_def(
-        &mut self,
-        enum_definition: &'a EnumDef,
-        generics: &'a Generics,
-        item_id: NodeId,
-        _: Span,
-    ) {
-        self.with_banned_assoc_ty_bound(|this| {
-            visit::walk_enum_def(this, enum_definition, generics, item_id)
-        })
+    fn visit_enum_def(&mut self, enum_definition: &'a EnumDef) {
+        self.with_banned_assoc_ty_bound(|this| visit::walk_enum_def(this, enum_definition))
     }
 
     fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
index ad9ed798e558bde002fc058adade9b854c903bf5..97eee56f948076d3379c7439c4094a1824f0eaaa 100644 (file)
@@ -2,7 +2,7 @@
 use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
 use rustc_ast::{AssocConstraint, AssocConstraintKind, NodeId};
 use rustc_ast::{PatKind, RangeEnd, VariantData};
-use rustc_errors::struct_span_err;
+use rustc_errors::{struct_span_err, Applicability};
 use rustc_feature::{AttributeGate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
 use rustc_feature::{Features, GateIssue};
 use rustc_session::parse::{feature_err, feature_err_issue};
@@ -417,6 +417,7 @@ macro_rules! gate_doc { ($($name:ident => $feature:ident)*) => {
                 || attr.has_name(sym::stable)
                 || attr.has_name(sym::rustc_const_unstable)
                 || attr.has_name(sym::rustc_const_stable)
+                || attr.has_name(sym::rustc_default_body_unstable)
             {
                 struct_span_err!(
                     self.sess,
@@ -577,6 +578,32 @@ fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FnRetTy) {
         }
     }
 
+    fn visit_stmt(&mut self, stmt: &'a ast::Stmt) {
+        if let ast::StmtKind::Semi(expr) = &stmt.kind
+            && let ast::ExprKind::Assign(lhs, _, _) = &expr.kind
+            && let ast::ExprKind::Type(..) = lhs.kind
+            && self.sess.parse_sess.span_diagnostic.err_count() == 0
+            && !self.features.type_ascription
+            && !lhs.span.allows_unstable(sym::type_ascription)
+        {
+            // When we encounter a statement of the form `foo: Ty = val;`, this will emit a type
+            // ascription error, but the likely intention was to write a `let` statement. (#78907).
+            feature_err_issue(
+                &self.sess.parse_sess,
+                sym::type_ascription,
+                lhs.span,
+                GateIssue::Language,
+                "type ascription is experimental",
+            ).span_suggestion_verbose(
+                lhs.span.shrink_to_lo(),
+                "you might have meant to introduce a new binding",
+                "let ".to_string(),
+                Applicability::MachineApplicable,
+            ).emit();
+        }
+        visit::walk_stmt(self, stmt);
+    }
+
     fn visit_expr(&mut self, e: &'a ast::Expr) {
         match e.kind {
             ast::ExprKind::Box(_) => {
@@ -795,8 +822,6 @@ fn maybe_stage_features(sess: &Session, krate: &ast::Crate) {
     // checks if `#![feature]` has been used to enable any lang feature
     // does not check the same for lib features unless there's at least one
     // declared lang feature
-    use rustc_errors::Applicability;
-
     if !sess.opts.unstable_features.is_nightly_build() {
         let lang_features = &sess.features_untracked().declared_lang_features;
         if lang_features.len() == 0 {
index 9c7369c83e2da57f8cf2bca9c4cc15862dc5065d..be3e46661bf02398fa20f401b8c0d22262e8f949 100644 (file)
@@ -79,9 +79,9 @@ fn visit_param_bound(&mut self, bounds: &GenericBound, _ctxt: BoundKind) {
         self.count += 1;
         walk_param_bound(self, bounds)
     }
-    fn visit_poly_trait_ref(&mut self, t: &PolyTraitRef, m: &TraitBoundModifier) {
+    fn visit_poly_trait_ref(&mut self, t: &PolyTraitRef) {
         self.count += 1;
-        walk_poly_trait_ref(self, t, m)
+        walk_poly_trait_ref(self, t)
     }
     fn visit_variant_data(&mut self, s: &VariantData) {
         self.count += 1;
@@ -91,15 +91,9 @@ fn visit_field_def(&mut self, s: &FieldDef) {
         self.count += 1;
         walk_field_def(self, s)
     }
-    fn visit_enum_def(
-        &mut self,
-        enum_definition: &EnumDef,
-        generics: &Generics,
-        item_id: NodeId,
-        _: Span,
-    ) {
+    fn visit_enum_def(&mut self, enum_definition: &EnumDef) {
         self.count += 1;
-        walk_enum_def(self, enum_definition, generics, item_id)
+        walk_enum_def(self, enum_definition)
     }
     fn visit_variant(&mut self, v: &Variant) {
         self.count += 1;
index 55ddd24c48a83a83972ced7be3ba273f7af6e705..5eb7bf6347f7bb5a6b13e85294fd1b29f5d20e36 100644 (file)
@@ -377,7 +377,7 @@ fn print_literal(&mut self, lit: &ast::Lit) {
 
     fn print_string(&mut self, st: &str, style: ast::StrStyle) {
         let st = match style {
-            ast::StrStyle::Cooked => (format!("\"{}\"", st.escape_debug())),
+            ast::StrStyle::Cooked => format!("\"{}\"", st.escape_debug()),
             ast::StrStyle::Raw(n) => {
                 format!("r{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = st)
             }
index ead38caee287fb0e5fdab685628bd06e0b4338d3..bcefa8ce0b9ce6ca8ff078b10e3fb3cc8d722a0d 100644 (file)
@@ -193,9 +193,13 @@ fn print_expr_call(&mut self, func: &ast::Expr, args: &[P<ast::Expr>]) {
         self.print_call_post(args)
     }
 
-    fn print_expr_method_call(&mut self, segment: &ast::PathSegment, args: &[P<ast::Expr>]) {
-        let base_args = &args[1..];
-        self.print_expr_maybe_paren(&args[0], parser::PREC_POSTFIX);
+    fn print_expr_method_call(
+        &mut self,
+        segment: &ast::PathSegment,
+        receiver: &ast::Expr,
+        base_args: &[P<ast::Expr>],
+    ) {
+        self.print_expr_maybe_paren(receiver, parser::PREC_POSTFIX);
         self.word(".");
         self.print_ident(segment.ident);
         if let Some(ref args) = segment.args {
@@ -303,8 +307,8 @@ pub(super) fn print_expr_outer_attr_style(&mut self, expr: &ast::Expr, is_inline
             ast::ExprKind::Call(ref func, ref args) => {
                 self.print_expr_call(func, &args);
             }
-            ast::ExprKind::MethodCall(ref segment, ref args, _) => {
-                self.print_expr_method_call(segment, &args);
+            ast::ExprKind::MethodCall(ref segment, ref receiver, ref args, _) => {
+                self.print_expr_method_call(segment, &receiver, &args);
             }
             ast::ExprKind::Binary(op, ref lhs, ref rhs) => {
                 self.print_expr_binary(op, lhs, rhs);
index f1caf22f3640fc9ced4e03f4df36e955e1ff58de..bd87987010e8fd2a15ae17ef490ef2547a3c6077 100644 (file)
@@ -412,9 +412,9 @@ fn print_variants(&mut self, variants: &[ast::Variant], span: rustc_span::Span)
     pub(crate) fn print_visibility(&mut self, vis: &ast::Visibility) {
         match vis.kind {
             ast::VisibilityKind::Public => self.word_nbsp("pub"),
-            ast::VisibilityKind::Restricted { ref path, .. } => {
+            ast::VisibilityKind::Restricted { ref path, id: _, shorthand } => {
                 let path = Self::to_string(|s| s.print_path(path, false, 0));
-                if path == "crate" || path == "self" || path == "super" {
+                if shorthand && (path == "crate" || path == "self" || path == "super") {
                     self.word_nbsp(format!("pub({})", path))
                 } else {
                     self.word_nbsp(format!("pub(in {})", path))
index 10a9cfb626e63391ae7ae22a439f1d13d9f2a907..62ccd734fe7206a09e255a5358cb145d7ac6253e 100644 (file)
@@ -131,6 +131,14 @@ pub fn is_const_stable(&self) -> bool {
     }
 }
 
+/// Represents the `#[rustc_default_body_unstable]` attribute.
+#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(HashStable_Generic)]
+pub struct DefaultBodyStability {
+    pub level: StabilityLevel,
+    pub feature: Symbol,
+}
+
 /// The available stability levels.
 #[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
 #[derive(HashStable_Generic)]
@@ -214,7 +222,8 @@ pub fn find_stability(
     sess: &Session,
     attrs: &[Attribute],
     item_sp: Span,
-) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>) {
+) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>, Option<(DefaultBodyStability, Span)>)
+{
     find_stability_generic(sess, attrs.iter(), item_sp)
 }
 
@@ -222,7 +231,7 @@ fn find_stability_generic<'a, I>(
     sess: &Session,
     attrs_iter: I,
     item_sp: Span,
-) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>)
+) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>, Option<(DefaultBodyStability, Span)>)
 where
     I: Iterator<Item = &'a Attribute>,
 {
@@ -230,6 +239,7 @@ fn find_stability_generic<'a, I>(
 
     let mut stab: Option<(Stability, Span)> = None;
     let mut const_stab: Option<(ConstStability, Span)> = None;
+    let mut body_stab: Option<(DefaultBodyStability, Span)> = None;
     let mut promotable = false;
     let mut allowed_through_unstable_modules = false;
 
@@ -243,6 +253,7 @@ fn find_stability_generic<'a, I>(
             sym::stable,
             sym::rustc_promotable,
             sym::rustc_allowed_through_unstable_modules,
+            sym::rustc_default_body_unstable,
         ]
         .iter()
         .any(|&s| attr.has_name(s))
@@ -280,7 +291,7 @@ fn find_stability_generic<'a, I>(
 
             let meta_name = meta.name_or_empty();
             match meta_name {
-                sym::rustc_const_unstable | sym::unstable => {
+                sym::rustc_const_unstable | sym::rustc_default_body_unstable | sym::unstable => {
                     if meta_name == sym::unstable && stab.is_some() {
                         handle_errors(
                             &sess.parse_sess,
@@ -295,6 +306,13 @@ fn find_stability_generic<'a, I>(
                             AttrError::MultipleStabilityLevels,
                         );
                         break;
+                    } else if meta_name == sym::rustc_default_body_unstable && body_stab.is_some() {
+                        handle_errors(
+                            &sess.parse_sess,
+                            attr.span,
+                            AttrError::MultipleStabilityLevels,
+                        );
+                        break;
                     }
 
                     let mut feature = None;
@@ -405,11 +423,16 @@ fn find_stability_generic<'a, I>(
                             };
                             if sym::unstable == meta_name {
                                 stab = Some((Stability { level, feature }, attr.span));
-                            } else {
+                            } else if sym::rustc_const_unstable == meta_name {
                                 const_stab = Some((
                                     ConstStability { level, feature, promotable: false },
                                     attr.span,
                                 ));
+                            } else if sym::rustc_default_body_unstable == meta_name {
+                                body_stab =
+                                    Some((DefaultBodyStability { level, feature }, attr.span));
+                            } else {
+                                unreachable!("Unknown stability attribute {meta_name}");
                             }
                         }
                         (None, _, _) => {
@@ -542,7 +565,7 @@ fn find_stability_generic<'a, I>(
         }
     }
 
-    (stab, const_stab)
+    (stab, const_stab, body_stab)
 }
 
 pub fn find_crate_name(sess: &Session, attrs: &[Attribute]) -> Option<Symbol> {
index eae162fe479ee0f52880179d866d3269b712d243..84a0d4ba7ba10b67fea7fe8f95cc21270bb20a33 100644 (file)
@@ -16,9 +16,7 @@
     FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
     ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm,
 };
-use rustc_middle::ty::{
-    self, subst::Subst, suggest_constraining_type_params, EarlyBinder, PredicateKind, Ty,
-};
+use rustc_middle::ty::{self, subst::Subst, suggest_constraining_type_params, PredicateKind, Ty};
 use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::hygiene::DesugaringKind;
@@ -39,7 +37,7 @@
 
 use super::{
     explain_borrow::{BorrowExplanation, LaterUseKind},
-    IncludingDowncast, RegionName, RegionNameSource, UseSpans,
+    DescribePlaceOpt, RegionName, RegionNameSource, UseSpans,
 };
 
 #[derive(Debug)]
@@ -137,7 +135,10 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
                 span,
                 desired_action.as_noun(),
                 partially_str,
-                self.describe_place_with_options(moved_place, IncludingDowncast(true)),
+                self.describe_place_with_options(
+                    moved_place,
+                    DescribePlaceOpt { including_downcast: true, including_tuple_field: true },
+                ),
             );
 
             let reinit_spans = maybe_reinitialized_locations
@@ -274,8 +275,10 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
                 }
             }
 
-            let opt_name =
-                self.describe_place_with_options(place.as_ref(), IncludingDowncast(true));
+            let opt_name = self.describe_place_with_options(
+                place.as_ref(),
+                DescribePlaceOpt { including_downcast: true, including_tuple_field: true },
+            );
             let note_msg = match opt_name {
                 Some(ref name) => format!("`{}`", name),
                 None => "value".to_owned(),
@@ -341,12 +344,17 @@ fn report_use_of_uninitialized(
             }
         }
 
-        let (name, desc) =
-            match self.describe_place_with_options(moved_place, IncludingDowncast(true)) {
-                Some(name) => (format!("`{name}`"), format!("`{name}` ")),
-                None => ("the variable".to_string(), String::new()),
-            };
-        let path = match self.describe_place_with_options(used_place, IncludingDowncast(true)) {
+        let (name, desc) = match self.describe_place_with_options(
+            moved_place,
+            DescribePlaceOpt { including_downcast: true, including_tuple_field: true },
+        ) {
+            Some(name) => (format!("`{name}`"), format!("`{name}` ")),
+            None => ("the variable".to_string(), String::new()),
+        };
+        let path = match self.describe_place_with_options(
+            used_place,
+            DescribePlaceOpt { including_downcast: true, including_tuple_field: true },
+        ) {
             Some(name) => format!("`{name}`"),
             None => "value".to_string(),
         };
@@ -443,7 +451,7 @@ fn report_use_of_uninitialized(
 
     fn suggest_borrow_fn_like(
         &self,
-        err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+        err: &mut Diagnostic,
         ty: Ty<'tcx>,
         move_sites: &[MoveSite],
         value_name: &str,
@@ -451,23 +459,24 @@ fn suggest_borrow_fn_like(
         let tcx = self.infcx.tcx;
 
         // Find out if the predicates show that the type is a Fn or FnMut
-        let find_fn_kind_from_did = |predicates: &[(ty::Predicate<'tcx>, Span)], substs| {
-            predicates.iter().find_map(|(pred, _)| {
-                let pred = if let Some(substs) = substs {
-                    EarlyBinder(*pred).subst(tcx, substs).kind().skip_binder()
-                } else {
-                    pred.kind().skip_binder()
-                };
-                if let ty::PredicateKind::Trait(pred) = pred && pred.self_ty() == ty {
+        let find_fn_kind_from_did =
+            |predicates: ty::EarlyBinder<&[(ty::Predicate<'tcx>, Span)]>, substs| {
+                predicates.0.iter().find_map(|(pred, _)| {
+                    let pred = if let Some(substs) = substs {
+                        predicates.rebind(*pred).subst(tcx, substs).kind().skip_binder()
+                    } else {
+                        pred.kind().skip_binder()
+                    };
+                    if let ty::PredicateKind::Trait(pred) = pred && pred.self_ty() == ty {
                     if Some(pred.def_id()) == tcx.lang_items().fn_trait() {
                         return Some(hir::Mutability::Not);
                     } else if Some(pred.def_id()) == tcx.lang_items().fn_mut_trait() {
                         return Some(hir::Mutability::Mut);
                     }
                 }
-                None
-            })
-        };
+                    None
+                })
+            };
 
         // If the type is opaque/param/closure, and it is Fn or FnMut, let's suggest (mutably)
         // borrowing the type, since `&mut F: FnMut` iff `F: FnMut` and similarly for `Fn`.
@@ -475,11 +484,12 @@ fn suggest_borrow_fn_like(
         // borrowed variants in a function body when we see a move error.
         let borrow_level = match ty.kind() {
             ty::Param(_) => find_fn_kind_from_did(
-                tcx.explicit_predicates_of(self.mir_def_id().to_def_id()).predicates,
+                tcx.bound_explicit_predicates_of(self.mir_def_id().to_def_id())
+                    .map_bound(|p| p.predicates),
                 None,
             ),
             ty::Opaque(did, substs) => {
-                find_fn_kind_from_did(tcx.explicit_item_bounds(*did), Some(*substs))
+                find_fn_kind_from_did(tcx.bound_explicit_item_bounds(*did), Some(*substs))
             }
             ty::Closure(_, substs) => match substs.as_closure().kind() {
                 ty::ClosureKind::Fn => Some(hir::Mutability::Not),
@@ -516,12 +526,7 @@ fn suggest_borrow_fn_like(
         true
     }
 
-    fn suggest_adding_copy_bounds(
-        &self,
-        err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
-        ty: Ty<'tcx>,
-        span: Span,
-    ) {
+    fn suggest_adding_copy_bounds(&self, err: &mut Diagnostic, ty: Ty<'tcx>, span: Span) {
         let tcx = self.infcx.tcx;
         let generics = tcx.generics_of(self.mir_def_id());
 
@@ -2726,7 +2731,7 @@ fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
                                 self.errors.push((
                                     e.span,
                                     format!(
-                                        "if the `for` loop runs 0 times, {} is not initialized ",
+                                        "if the `for` loop runs 0 times, {} is not initialized",
                                         self.name
                                     ),
                                 ));
index 0300180f80a80275af945920f33d232c35d192c6..098e8de9420fb89ef02b228382f0654bdee29975 100644 (file)
@@ -4,7 +4,7 @@
 use rustc_const_eval::util::{call_kind, CallDesugaringKind};
 use rustc_errors::{Applicability, Diagnostic};
 use rustc_hir as hir;
-use rustc_hir::def::Namespace;
+use rustc_hir::def::{CtorKind, Namespace};
 use rustc_hir::GeneratorKind;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::mir::tcx::PlaceTy;
@@ -16,7 +16,7 @@
 use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt};
 use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult};
 use rustc_span::def_id::LocalDefId;
-use rustc_span::{symbol::sym, Span, DUMMY_SP};
+use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP};
 use rustc_target::abi::VariantIdx;
 use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;
 
 pub(crate) use region_name::{RegionName, RegionNameSource};
 pub(crate) use rustc_const_eval::util::CallKind;
 
-pub(super) struct IncludingDowncast(pub(super) bool);
+pub(super) struct DescribePlaceOpt {
+    pub including_downcast: bool,
+
+    /// Enable/Disable tuple fields.
+    /// For example `x` tuple. if it's `true` `x.0`. Otherwise `x`
+    pub including_tuple_field: bool,
+}
+
+pub(super) struct IncludingTupleField(pub(super) bool);
 
 impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     /// Adds a suggestion when a closure is invoked twice with a moved variable or when a closure
@@ -164,7 +172,10 @@ pub(super) fn describe_any_place(&self, place_ref: PlaceRef<'tcx>) -> String {
     /// End-user visible description of `place` if one can be found.
     /// If the place is a temporary for instance, `None` will be returned.
     pub(super) fn describe_place(&self, place_ref: PlaceRef<'tcx>) -> Option<String> {
-        self.describe_place_with_options(place_ref, IncludingDowncast(false))
+        self.describe_place_with_options(
+            place_ref,
+            DescribePlaceOpt { including_downcast: false, including_tuple_field: true },
+        )
     }
 
     /// End-user visible description of `place` if one can be found. If the place is a temporary
@@ -174,7 +185,7 @@ pub(super) fn describe_place(&self, place_ref: PlaceRef<'tcx>) -> Option<String>
     pub(super) fn describe_place_with_options(
         &self,
         place: PlaceRef<'tcx>,
-        including_downcast: IncludingDowncast,
+        opt: DescribePlaceOpt,
     ) -> Option<String> {
         let local = place.local;
         let mut autoderef_index = None;
@@ -224,7 +235,7 @@ pub(super) fn describe_place_with_options(
                         }
                     }
                 }
-                ProjectionElem::Downcast(..) if including_downcast.0 => return None,
+                ProjectionElem::Downcast(..) if opt.including_downcast => return None,
                 ProjectionElem::Downcast(..) => (),
                 ProjectionElem::Field(field, _ty) => {
                     // FIXME(project-rfc_2229#36): print capture precisely here.
@@ -238,9 +249,12 @@ pub(super) fn describe_place_with_options(
                         let field_name = self.describe_field(
                             PlaceRef { local, projection: place.projection.split_at(index).0 },
                             *field,
+                            IncludingTupleField(opt.including_tuple_field),
                         );
-                        buf.push('.');
-                        buf.push_str(&field_name);
+                        if let Some(field_name_str) = field_name {
+                            buf.push('.');
+                            buf.push_str(&field_name_str);
+                        }
                     }
                 }
                 ProjectionElem::Index(index) => {
@@ -261,6 +275,18 @@ pub(super) fn describe_place_with_options(
         ok.ok().map(|_| buf)
     }
 
+    fn describe_name(&self, place: PlaceRef<'tcx>) -> Option<Symbol> {
+        for elem in place.projection.into_iter() {
+            match elem {
+                ProjectionElem::Downcast(Some(name), _) => {
+                    return Some(*name);
+                }
+                _ => {}
+            }
+        }
+        None
+    }
+
     /// Appends end-user visible description of the `local` place to `buf`. If `local` doesn't have
     /// a name, or its name was generated by the compiler, then `Err` is returned
     fn append_local_to_string(&self, local: Local, buf: &mut String) -> Result<(), ()> {
@@ -275,7 +301,12 @@ fn append_local_to_string(&self, local: Local, buf: &mut String) -> Result<(), (
     }
 
     /// End-user visible description of the `field`nth field of `base`
-    fn describe_field(&self, place: PlaceRef<'tcx>, field: Field) -> String {
+    fn describe_field(
+        &self,
+        place: PlaceRef<'tcx>,
+        field: Field,
+        including_tuple_field: IncludingTupleField,
+    ) -> Option<String> {
         let place_ty = match place {
             PlaceRef { local, projection: [] } => PlaceTy::from_ty(self.body.local_decls[local].ty),
             PlaceRef { local, projection: [proj_base @ .., elem] } => match elem {
@@ -289,7 +320,12 @@ fn describe_field(&self, place: PlaceRef<'tcx>, field: Field) -> String {
                 ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type),
             },
         };
-        self.describe_field_from_ty(place_ty.ty, field, place_ty.variant_index)
+        self.describe_field_from_ty(
+            place_ty.ty,
+            field,
+            place_ty.variant_index,
+            including_tuple_field,
+        )
     }
 
     /// End-user visible description of the `field_index`nth field of `ty`
@@ -298,10 +334,11 @@ fn describe_field_from_ty(
         ty: Ty<'_>,
         field: Field,
         variant_index: Option<VariantIdx>,
-    ) -> String {
+        including_tuple_field: IncludingTupleField,
+    ) -> Option<String> {
         if ty.is_box() {
             // If the type is a box, the field is described from the boxed type
-            self.describe_field_from_ty(ty.boxed_ty(), field, variant_index)
+            self.describe_field_from_ty(ty.boxed_ty(), field, variant_index, including_tuple_field)
         } else {
             match *ty.kind() {
                 ty::Adt(def, _) => {
@@ -311,14 +348,17 @@ fn describe_field_from_ty(
                     } else {
                         def.non_enum_variant()
                     };
-                    variant.fields[field.index()].name.to_string()
+                    if !including_tuple_field.0 && variant.ctor_kind == CtorKind::Fn {
+                        return None;
+                    }
+                    Some(variant.fields[field.index()].name.to_string())
                 }
-                ty::Tuple(_) => field.index().to_string(),
+                ty::Tuple(_) => Some(field.index().to_string()),
                 ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => {
-                    self.describe_field_from_ty(ty, field, variant_index)
+                    self.describe_field_from_ty(ty, field, variant_index, including_tuple_field)
                 }
                 ty::Array(ty, _) | ty::Slice(ty) => {
-                    self.describe_field_from_ty(ty, field, variant_index)
+                    self.describe_field_from_ty(ty, field, variant_index, including_tuple_field)
                 }
                 ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => {
                     // We won't be borrowck'ing here if the closure came from another crate,
@@ -335,7 +375,7 @@ fn describe_field_from_ty(
                         .unwrap()
                         .get_root_variable();
 
-                    self.infcx.tcx.hir().name(var_id).to_string()
+                    Some(self.infcx.tcx.hir().name(var_id).to_string())
                 }
                 _ => {
                     // Might need a revision when the fields in trait RFC is implemented
index becb81b2e26a8d916a8ea6a84853004803060db1..cb3cd479ae2b63dbe446495b3a115051d8516113 100644 (file)
@@ -6,7 +6,7 @@
 };
 use rustc_span::Span;
 
-use crate::diagnostics::UseSpans;
+use crate::diagnostics::{DescribePlaceOpt, UseSpans};
 use crate::prefixes::PrefixSet;
 use crate::MirBorrowckCtxt;
 
@@ -368,13 +368,31 @@ fn report_cannot_move_from_borrowed_content(
             }
             _ => {
                 let source = self.borrowed_content_source(deref_base);
-                match (self.describe_place(move_place.as_ref()), source.describe_for_named_place())
-                {
-                    (Some(place_desc), Some(source_desc)) => self.cannot_move_out_of(
+                let move_place_ref = move_place.as_ref();
+                match (
+                    self.describe_place_with_options(
+                        move_place_ref,
+                        DescribePlaceOpt {
+                            including_downcast: false,
+                            including_tuple_field: false,
+                        },
+                    ),
+                    self.describe_name(move_place_ref),
+                    source.describe_for_named_place(),
+                ) {
+                    (Some(place_desc), Some(name), Some(source_desc)) => self.cannot_move_out_of(
+                        span,
+                        &format!("`{place_desc}` as enum variant `{name}` which is behind a {source_desc}"),
+                    ),
+                    (Some(place_desc), Some(name), None) => self.cannot_move_out_of(
+                        span,
+                        &format!("`{place_desc}` as enum variant `{name}`"),
+                    ),
+                    (Some(place_desc), _, Some(source_desc)) => self.cannot_move_out_of(
                         span,
                         &format!("`{place_desc}` which is behind a {source_desc}"),
                     ),
-                    (_, _) => self.cannot_move_out_of(
+                    (_, _, _) => self.cannot_move_out_of(
                         span,
                         &source.describe_for_unnamed_place(self.infcx.tcx),
                     ),
index 176090c3b7a14e9dd78caccfad7a10bca07c4d66..bd3a2a3d69496c84728ea5ef189cda004a49994d 100644 (file)
@@ -783,7 +783,7 @@ fn add_static_impl_trait_suggestion(
 
     fn maybe_suggest_constrain_dyn_trait_impl(
         &self,
-        diag: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+        diag: &mut Diagnostic,
         f: Region<'tcx>,
         o: Region<'tcx>,
         category: &ConstraintCategory<'tcx>,
index f68358ecfe6d203de81ac6945addce03da4de1ee..a87e8bd5ba16fc276183bc1366a121107141dd94 100644 (file)
@@ -839,7 +839,7 @@ fn give_name_if_anonymous_region_appears_in_yield_ty(
             hir::Node::Expr(hir::Expr {
                 kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }),
                 ..
-            }) => (tcx.sess.source_map().end_point(fn_decl_span)),
+            }) => tcx.sess.source_map().end_point(fn_decl_span),
             _ => self.body.span,
         };
 
index 167960918308cd365c50894a3db07acc040415e4..9fab7ad914a847118c4d0a4abf067707141d4f06 100644 (file)
@@ -6,7 +6,7 @@
 use rustc_infer::infer::{self, InferCtxt, SubregionOrigin};
 use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::TypeVisitable;
+use rustc_middle::ty::TypeFoldable;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::{Span, DUMMY_SP};
 
@@ -109,23 +109,11 @@ pub(super) fn convert(&mut self, query_constraint: &QueryOutlivesConstraint<'tcx
                 self.add_outlives(r1_vid, r2_vid);
             }
 
-            GenericArgKind::Type(mut t1) => {
+            GenericArgKind::Type(t1) => {
                 // we don't actually use this for anything, but
                 // the `TypeOutlives` code needs an origin.
                 let origin = infer::RelateParamBound(DUMMY_SP, t1, None);
 
-                // Placeholder regions need to be converted now because it may
-                // create new region variables, which can't be done later when
-                // verifying these bounds.
-                if t1.has_placeholders() {
-                    t1 = tcx.fold_regions(t1, |r, _| match *r {
-                        ty::RePlaceholder(placeholder) => {
-                            self.constraints.placeholder_region(self.infcx, placeholder)
-                        }
-                        _ => r,
-                    });
-                }
-
                 TypeOutlives::new(
                     &mut *self,
                     tcx,
@@ -143,6 +131,25 @@ pub(super) fn convert(&mut self, query_constraint: &QueryOutlivesConstraint<'tcx
         }
     }
 
+    /// Placeholder regions need to be converted eagerly because it may
+    /// create new region variables, which we must not do when verifying
+    /// our region bounds.
+    ///
+    /// FIXME: This should get removed once higher ranked region obligations
+    /// are dealt with during trait solving.
+    fn replace_placeholders_with_nll<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
+        if value.has_placeholders() {
+            self.tcx.fold_regions(value, |r, _| match *r {
+                ty::RePlaceholder(placeholder) => {
+                    self.constraints.placeholder_region(self.infcx, placeholder)
+                }
+                _ => r,
+            })
+        } else {
+            value
+        }
+    }
+
     fn verify_to_type_test(
         &mut self,
         generic_kind: GenericKind<'tcx>,
@@ -150,7 +157,6 @@ fn verify_to_type_test(
         verify_bound: VerifyBound<'tcx>,
     ) -> TypeTest<'tcx> {
         let lower_bound = self.to_region_vid(region);
-
         TypeTest { generic_kind, lower_bound, locations: self.locations, verify_bound }
     }
 
@@ -198,6 +204,8 @@ fn push_verify(
         a: ty::Region<'tcx>,
         bound: VerifyBound<'tcx>,
     ) {
+        let kind = self.replace_placeholders_with_nll(kind);
+        let bound = self.replace_placeholders_with_nll(bound);
         let type_test = self.verify_to_type_test(kind, a, bound);
         self.add_type_test(type_test);
     }
index cc0318ede54a0e98858df911cd48a6134d811656..74655369faf0388d5872ffae944e3895202f3d4a 100644 (file)
@@ -242,10 +242,9 @@ pub(crate) fn create(mut self) -> CreateResult<'tcx> {
         let constraint_sets: Vec<_> = unnormalized_input_output_tys
             .flat_map(|ty| {
                 debug!("build: input_or_output={:?}", ty);
-                // We only add implied bounds for the normalized type as the unnormalized
-                // type may not actually get checked by the caller.
-                //
-                // Can otherwise be unsound, see #91068.
+                // We add implied bounds from both the unnormalized and normalized ty.
+                // See issue #87748
+                let constraints_implied1 = self.add_implied_bounds(ty);
                 let TypeOpOutput { output: norm_ty, constraints: constraints1, .. } = self
                     .param_env
                     .and(type_op::normalize::Normalize::new(ty))
@@ -273,9 +272,10 @@ pub(crate) fn create(mut self) -> CreateResult<'tcx> {
                 // }
                 // ```
                 // Both &Self::Bar and &() are WF
-                let constraints_implied = self.add_implied_bounds(norm_ty);
+                let constraints_implied2 =
+                    if ty != norm_ty { self.add_implied_bounds(norm_ty) } else { None };
                 normalized_inputs_and_output.push(norm_ty);
-                constraints1.into_iter().chain(constraints_implied)
+                constraints1.into_iter().chain(constraints_implied1).chain(constraints_implied2)
             })
             .collect();
 
index f7d35da02597d8f65a7f4e7a1d858c377476b2ca..7bf7f7357bf4f57c5d4f6d8cb71b447f2434aba2 100644 (file)
@@ -1448,9 +1448,14 @@ fn check_terminator(
                     ))
                 });
                 debug!(?sig);
-                let sig = self.normalize(sig, term_location);
-                self.check_call_dest(body, term, &sig, *destination, target, term_location);
-
+                // IMPORTANT: We have to prove well formed for the function signature before
+                // we normalize it, as otherwise types like `<&'a &'b () as Trait>::Assoc`
+                // get normalized away, causing us to ignore the `'b: 'a` bound used by the function.
+                //
+                // Normalization results in a well formed type if the input is well formed, so we
+                // don't have to check it twice.
+                //
+                // See #91068 for an example.
                 self.prove_predicates(
                     sig.inputs_and_output
                         .iter()
@@ -1458,6 +1463,8 @@ fn check_terminator(
                     term_location.to_locations(),
                     ConstraintCategory::Boring,
                 );
+                let sig = self.normalize(sig, term_location);
+                self.check_call_dest(body, term, &sig, *destination, target, term_location);
 
                 // The ordinary liveness rules will ensure that all
                 // regions in the type of the callee are live here. We
@@ -2619,6 +2626,34 @@ fn prove_closure_bounds(
             );
         }
 
+        // Now equate closure substs to regions inherited from `typeck_root_def_id`. Fixes #98589.
+        let typeck_root_def_id = tcx.typeck_root_def_id(self.body.source.def_id());
+        let typeck_root_substs = ty::InternalSubsts::identity_for_item(tcx, typeck_root_def_id);
+
+        let parent_substs = match tcx.def_kind(def_id) {
+            DefKind::Closure => substs.as_closure().parent_substs(),
+            DefKind::Generator => substs.as_generator().parent_substs(),
+            DefKind::InlineConst => substs.as_inline_const().parent_substs(),
+            other => bug!("unexpected item {:?}", other),
+        };
+        let parent_substs = tcx.mk_substs(parent_substs.iter());
+
+        assert_eq!(typeck_root_substs.len(), parent_substs.len());
+        if let Err(_) = self.eq_substs(
+            typeck_root_substs,
+            parent_substs,
+            location.to_locations(),
+            ConstraintCategory::BoringNoLocation,
+        ) {
+            span_mirbug!(
+                self,
+                def_id,
+                "could not relate closure to parent {:?} != {:?}",
+                typeck_root_substs,
+                parent_substs
+            );
+        }
+
         tcx.predicates_of(def_id).instantiate(tcx, substs)
     }
 
index c45850c6d840f8752998e9bb741f0eacfbd69930..c97a6a1a6587a56aa13f07c564c1e4af4430ee99 100644 (file)
@@ -38,6 +38,23 @@ pub(super) fn relate_types(
         .relate(a, b)?;
         Ok(())
     }
+
+    /// Add sufficient constraints to ensure `a == b`. See also [Self::relate_types].
+    pub(super) fn eq_substs(
+        &mut self,
+        a: ty::SubstsRef<'tcx>,
+        b: ty::SubstsRef<'tcx>,
+        locations: Locations,
+        category: ConstraintCategory<'tcx>,
+    ) -> Fallible<()> {
+        TypeRelating::new(
+            self.infcx,
+            NllTypeRelatingDelegate::new(self, locations, category, UniverseInfo::other()),
+            ty::Variance::Invariant,
+        )
+        .relate(a, b)?;
+        Ok(())
+    }
 }
 
 struct NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
index a2205c3613d92737900d3e02cfffe5db3bf44301..1a0ea8f416064f27c0b90a31254c9f0dd7af6731 100644 (file)
@@ -410,12 +410,12 @@ fn parse_options<'a>(
             try_set_option(p, args, sym::noreturn, ast::InlineAsmOptions::NORETURN);
         } else if !is_global_asm && p.eat_keyword(sym::nostack) {
             try_set_option(p, args, sym::nostack, ast::InlineAsmOptions::NOSTACK);
+        } else if !is_global_asm && p.eat_keyword(sym::may_unwind) {
+            try_set_option(p, args, kw::Raw, ast::InlineAsmOptions::MAY_UNWIND);
         } else if p.eat_keyword(sym::att_syntax) {
             try_set_option(p, args, sym::att_syntax, ast::InlineAsmOptions::ATT_SYNTAX);
         } else if p.eat_keyword(kw::Raw) {
             try_set_option(p, args, kw::Raw, ast::InlineAsmOptions::RAW);
-        } else if p.eat_keyword(sym::may_unwind) {
-            try_set_option(p, args, kw::Raw, ast::InlineAsmOptions::MAY_UNWIND);
         } else {
             return p.unexpected();
         }
@@ -656,7 +656,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
                     let span = arg_spans.next().unwrap_or(template_sp);
 
                     let operand_idx = match arg.position {
-                        parse::ArgumentIs(idx, _) | parse::ArgumentImplicitlyIs(idx) => {
+                        parse::ArgumentIs(idx) | parse::ArgumentImplicitlyIs(idx) => {
                             if idx >= args.operands.len()
                                 || named_pos.contains_key(&idx)
                                 || args.reg_args.contains(&idx)
@@ -702,11 +702,12 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
                                 Some(idx)
                             }
                         }
-                        parse::ArgumentNamed(name, span) => {
+                        parse::ArgumentNamed(name) => {
                             match args.named_args.get(&Symbol::intern(name)) {
                                 Some(&idx) => Some(idx),
                                 None => {
                                     let msg = format!("there is no argument named `{}`", name);
+                                    let span = arg.position_span;
                                     ecx.struct_span_err(
                                         template_span
                                             .from_inner(InnerSpan::new(span.start, span.end)),
index dcea883a5a37869fac600c2c027410d38a0043c7..c04d04020cc679cb06c386659684876795f3fb55 100644 (file)
@@ -240,8 +240,8 @@ fn manage_cond_expr(&mut self, expr: &mut P<Expr>) {
                 self.manage_cond_expr(prefix);
                 self.manage_cond_expr(suffix);
             }
-            ExprKind::MethodCall(_, ref mut local_exprs, _) => {
-                for local_expr in local_exprs.iter_mut().skip(1) {
+            ExprKind::MethodCall(_, _,ref mut local_exprs, _) => {
+                for local_expr in local_exprs.iter_mut() {
                     self.manage_cond_expr(local_expr);
                 }
             }
@@ -377,14 +377,12 @@ fn manage_try_capture(&mut self, capture: Ident, curr_capture_idx: usize, expr:
                     id: DUMMY_NODE_ID,
                     ident: Ident::new(sym::try_capture, self.span),
                 },
-                vec![
-                    expr_paren(self.cx, self.span, self.cx.expr_addr_of(self.span, wrapper)),
-                    expr_addr_of_mut(
-                        self.cx,
-                        self.span,
-                        self.cx.expr_path(Path::from_ident(capture)),
-                    ),
-                ],
+                expr_paren(self.cx, self.span, self.cx.expr_addr_of(self.span, wrapper)),
+                vec![expr_addr_of_mut(
+                    self.cx,
+                    self.span,
+                    self.cx.expr_path(Path::from_ident(capture)),
+                )],
                 self.span,
             ))
             .add_trailing_semicolon();
@@ -442,10 +440,11 @@ fn expr_addr_of_mut(cx: &ExtCtxt<'_>, sp: Span, e: P<Expr>) -> P<Expr> {
 fn expr_method_call(
     cx: &ExtCtxt<'_>,
     path: PathSegment,
+    receiver: P<Expr>,
     args: Vec<P<Expr>>,
     span: Span,
 ) -> P<Expr> {
-    cx.expr(span, ExprKind::MethodCall(path, args, span))
+    cx.expr(span, ExprKind::MethodCall(path, receiver, args, span))
 }
 
 fn expr_paren(cx: &ExtCtxt<'_>, sp: Span, e: P<Expr>) -> P<Expr> {
index 735017aa5a850f9d3ec9690aab3e029b7bfba649..ef64f52d40b761e723f50be49bd9aafc642b704f 100644 (file)
@@ -383,16 +383,12 @@ fn visit_ty(&mut self, ty: &'a ast::Ty) {
         }
 
         // Place bound generic params on a stack, to extract them when a type is encountered.
-        fn visit_poly_trait_ref(
-            &mut self,
-            trait_ref: &'a ast::PolyTraitRef,
-            modifier: &'a ast::TraitBoundModifier,
-        ) {
+        fn visit_poly_trait_ref(&mut self, trait_ref: &'a ast::PolyTraitRef) {
             let stack_len = self.bound_generic_params_stack.len();
             self.bound_generic_params_stack
                 .extend(trait_ref.bound_generic_params.clone().into_iter());
 
-            visit::walk_poly_trait_ref(self, trait_ref, modifier);
+            visit::walk_poly_trait_ref(self, trait_ref);
 
             self.bound_generic_params_stack.truncate(stack_len);
         }
index 082c78934262bf23bfdabce0fa9f8d2a41294eaf..9eb96ec76800c8634355aae052d55bc7eca4450f 100644 (file)
@@ -16,6 +16,7 @@
 
 use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY;
 use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiagnostics, LintId};
+use rustc_parse_format::Count;
 use std::borrow::Cow;
 use std::collections::hash_map::Entry;
 
@@ -57,26 +58,45 @@ struct PositionalNamedArg {
     replacement: Symbol,
     /// The span for the positional named argument (so the lint can point a message to it)
     positional_named_arg_span: Span,
+    has_formatting: bool,
 }
 
 impl PositionalNamedArg {
-    /// Determines what span to replace with the name of the named argument
-    fn get_span_to_replace(&self, cx: &Context<'_, '_>) -> Option<Span> {
+    /// Determines:
+    /// 1) span to be replaced with the name of the named argument and
+    /// 2) span to be underlined for error messages
+    fn get_positional_arg_spans(&self, cx: &Context<'_, '_>) -> (Option<Span>, Option<Span>) {
         if let Some(inner_span) = &self.inner_span_to_replace {
-            return Some(
-                cx.fmtsp.from_inner(InnerSpan { start: inner_span.start, end: inner_span.end }),
-            );
+            let span =
+                cx.fmtsp.from_inner(InnerSpan { start: inner_span.start, end: inner_span.end });
+            (Some(span), Some(span))
         } else if self.ty == PositionalNamedArgType::Arg {
-            // In the case of a named argument whose position is implicit, there will not be a span
-            // to replace. Instead, we insert the name after the `{`, which is the first character
-            // of arg_span.
-            return cx
-                .arg_spans
-                .get(self.cur_piece)
-                .map(|arg_span| arg_span.with_lo(arg_span.lo() + BytePos(1)).shrink_to_lo());
+            // In the case of a named argument whose position is implicit, if the argument *has*
+            // formatting, there will not be a span to replace. Instead, we insert the name after
+            // the `{`, which will be the first character of arg_span. If the argument does *not*
+            // have formatting, there may or may not be a span to replace. This is because
+            // whitespace is allowed in arguments without formatting (such as `format!("{  }", 1);`)
+            // but is not allowed in arguments with formatting (an error will be generated in cases
+            // like `format!("{ :1.1}", 1.0f32);`.
+            // For the message span, if there is formatting, we want to use the opening `{` and the
+            // next character, which will the `:` indicating the start of formatting. If there is
+            // not any formatting, we want to underline the entire span.
+            cx.arg_spans.get(self.cur_piece).map_or((None, None), |arg_span| {
+                if self.has_formatting {
+                    (
+                        Some(arg_span.with_lo(arg_span.lo() + BytePos(1)).shrink_to_lo()),
+                        Some(arg_span.with_hi(arg_span.lo() + BytePos(2))),
+                    )
+                } else {
+                    let replace_start = arg_span.lo() + BytePos(1);
+                    let replace_end = arg_span.hi() - BytePos(1);
+                    let to_replace = arg_span.with_lo(replace_start).with_hi(replace_end);
+                    (Some(to_replace), Some(*arg_span))
+                }
+            })
+        } else {
+            (None, None)
         }
-
-        None
     }
 }
 
@@ -117,10 +137,18 @@ fn maybe_add_positional_named_arg(
         cur_piece: usize,
         inner_span_to_replace: Option<rustc_parse_format::InnerSpan>,
         names: &FxHashMap<Symbol, (usize, Span)>,
+        has_formatting: bool,
     ) {
         let start_of_named_args = total_args_length - names.len();
         if current_positional_arg >= start_of_named_args {
-            self.maybe_push(format_argument_index, ty, cur_piece, inner_span_to_replace, names)
+            self.maybe_push(
+                format_argument_index,
+                ty,
+                cur_piece,
+                inner_span_to_replace,
+                names,
+                has_formatting,
+            )
         }
     }
 
@@ -134,6 +162,7 @@ fn maybe_push(
         cur_piece: usize,
         inner_span_to_replace: Option<rustc_parse_format::InnerSpan>,
         names: &FxHashMap<Symbol, (usize, Span)>,
+        has_formatting: bool,
     ) {
         let named_arg = names
             .iter()
@@ -156,6 +185,7 @@ fn maybe_push(
                 inner_span_to_replace,
                 replacement,
                 positional_named_arg_span,
+                has_formatting,
             });
         }
     }
@@ -250,6 +280,11 @@ struct Context<'a, 'b> {
     unused_names_lint: PositionalNamedArgsLint,
 }
 
+pub struct FormatArg {
+    expr: P<ast::Expr>,
+    named: bool,
+}
+
 /// Parses the arguments from the given list of tokens, returning the diagnostic
 /// if there's a parse error so we can continue parsing other format!
 /// expressions.
@@ -263,8 +298,8 @@ fn parse_args<'a>(
     ecx: &mut ExtCtxt<'a>,
     sp: Span,
     tts: TokenStream,
-) -> PResult<'a, (P<ast::Expr>, Vec<P<ast::Expr>>, FxHashMap<Symbol, (usize, Span)>)> {
-    let mut args = Vec::<P<ast::Expr>>::new();
+) -> PResult<'a, (P<ast::Expr>, Vec<FormatArg>, FxHashMap<Symbol, (usize, Span)>)> {
+    let mut args = Vec::<FormatArg>::new();
     let mut names = FxHashMap::<Symbol, (usize, Span)>::default();
 
     let mut p = ecx.new_parser_from_tts(tts);
@@ -332,7 +367,7 @@ fn parse_args<'a>(
                 let e = p.parse_expr()?;
                 if let Some((prev, _)) = names.get(&ident.name) {
                     ecx.struct_span_err(e.span, &format!("duplicate argument named `{}`", ident))
-                        .span_label(args[*prev].span, "previously here")
+                        .span_label(args[*prev].expr.span, "previously here")
                         .span_label(e.span, "duplicate argument")
                         .emit();
                     continue;
@@ -344,7 +379,7 @@ fn parse_args<'a>(
                 // args. And remember the names.
                 let slot = args.len();
                 names.insert(ident.name, (slot, ident.span));
-                args.push(e);
+                args.push(FormatArg { expr: e, named: true });
             }
             _ => {
                 let e = p.parse_expr()?;
@@ -355,11 +390,11 @@ fn parse_args<'a>(
                     );
                     err.span_label(e.span, "positional arguments must be before named arguments");
                     for pos in names.values() {
-                        err.span_label(args[pos.0].span, "named argument");
+                        err.span_label(args[pos.0].expr.span, "named argument");
                     }
                     err.emit();
                 }
-                args.push(e);
+                args.push(FormatArg { expr: e, named: false });
             }
         }
     }
@@ -381,8 +416,8 @@ fn resolve_name_inplace(&mut self, p: &mut parse::Piece<'_>) {
         match *p {
             parse::String(_) => {}
             parse::NextArgument(ref mut arg) => {
-                if let parse::ArgumentNamed(s, _) = arg.position {
-                    arg.position = parse::ArgumentIs(lookup(s), None);
+                if let parse::ArgumentNamed(s) = arg.position {
+                    arg.position = parse::ArgumentIs(lookup(s));
                 }
                 if let parse::CountIsName(s, _) = arg.format.width {
                     arg.format.width = parse::CountIsParam(lookup(s));
@@ -414,18 +449,22 @@ fn verify_piece(&mut self, p: &parse::Piece<'_>) {
                     PositionalNamedArgType::Precision,
                 );
 
+                let has_precision = arg.format.precision != Count::CountImplied;
+                let has_width = arg.format.width != Count::CountImplied;
+
                 // argument second, if it's an implicit positional parameter
                 // it's written second, so it should come after width/precision.
                 let pos = match arg.position {
-                    parse::ArgumentIs(i, arg_end) => {
+                    parse::ArgumentIs(i) => {
                         self.unused_names_lint.maybe_add_positional_named_arg(
                             i,
                             self.args.len(),
                             i,
                             PositionalNamedArgType::Arg,
                             self.curpiece,
-                            arg_end,
+                            Some(arg.position_span),
                             &self.names,
+                            has_precision || has_width,
                         );
 
                         Exact(i)
@@ -439,11 +478,13 @@ fn verify_piece(&mut self, p: &parse::Piece<'_>) {
                             self.curpiece,
                             None,
                             &self.names,
+                            has_precision || has_width,
                         );
                         Exact(i)
                     }
-                    parse::ArgumentNamed(s, span) => {
+                    parse::ArgumentNamed(s) => {
                         let symbol = Symbol::intern(s);
+                        let span = arg.position_span;
                         Named(symbol, InnerSpan::new(span.start, span.end))
                     }
                 };
@@ -529,6 +570,7 @@ fn verify_count(
                     self.curpiece,
                     *inner_span,
                     &self.names,
+                    true,
                 );
                 self.verify_arg_type(Exact(i), Count);
             }
@@ -878,8 +920,9 @@ fn build_piece(
                         // track the current argument ourselves.
                         let i = self.curarg;
                         self.curarg += 1;
-                        parse::ArgumentIs(i, None)
+                        parse::ArgumentIs(i)
                     },
+                    position_span: arg.position_span,
                     format: parse::FormatSpec {
                         fill: arg.format.fill,
                         align: parse::AlignUnknown,
@@ -1150,24 +1193,22 @@ pub fn expand_format_args_nl<'cx>(
 
 fn create_lints_for_named_arguments_used_positionally(cx: &mut Context<'_, '_>) {
     for named_arg in &cx.unused_names_lint.positional_named_args {
-        let arg_span = named_arg.get_span_to_replace(cx);
+        let (position_sp_to_replace, position_sp_for_msg) = named_arg.get_positional_arg_spans(cx);
 
         let msg = format!("named argument `{}` is not used by name", named_arg.replacement);
-        let replacement = match named_arg.ty {
-            PositionalNamedArgType::Arg => named_arg.replacement.to_string(),
-            _ => named_arg.replacement.to_string() + "$",
-        };
 
         cx.ecx.buffered_early_lint.push(BufferedEarlyLint {
             span: MultiSpan::from_span(named_arg.positional_named_arg_span),
             msg: msg.clone(),
             node_id: ast::CRATE_NODE_ID,
             lint_id: LintId::of(&NAMED_ARGUMENTS_USED_POSITIONALLY),
-            diagnostic: BuiltinLintDiagnostics::NamedArgumentUsedPositionally(
-                arg_span,
-                named_arg.positional_named_arg_span,
-                replacement,
-            ),
+            diagnostic: BuiltinLintDiagnostics::NamedArgumentUsedPositionally {
+                position_sp_to_replace,
+                position_sp_for_msg,
+                named_arg_sp: named_arg.positional_named_arg_span,
+                named_arg_name: named_arg.replacement.to_string(),
+                is_formatting_arg: named_arg.ty != PositionalNamedArgType::Arg,
+            },
         });
     }
 }
@@ -1178,7 +1219,7 @@ pub fn expand_preparsed_format_args(
     ecx: &mut ExtCtxt<'_>,
     sp: Span,
     efmt: P<ast::Expr>,
-    args: Vec<P<ast::Expr>>,
+    args: Vec<FormatArg>,
     names: FxHashMap<Symbol, (usize, Span)>,
     append_newline: bool,
 ) -> P<ast::Expr> {
@@ -1268,6 +1309,25 @@ pub fn expand_preparsed_format_args(
                 e.span_label(fmt_span.from_inner(InnerSpan::new(span.start, span.end)), label);
             }
         }
+        if err.should_be_replaced_with_positional_argument {
+            let captured_arg_span =
+                fmt_span.from_inner(InnerSpan::new(err.span.start, err.span.end));
+            let positional_args = args.iter().filter(|arg| !arg.named).collect::<Vec<_>>();
+            if let Ok(arg) = ecx.source_map().span_to_snippet(captured_arg_span) {
+                let span = match positional_args.last() {
+                    Some(arg) => arg.expr.span,
+                    None => fmt_sp,
+                };
+                e.multipart_suggestion_verbose(
+                    "consider using a positional formatting argument instead",
+                    vec![
+                        (captured_arg_span, positional_args.len().to_string()),
+                        (span.shrink_to_hi(), format!(", {}", arg)),
+                    ],
+                    Applicability::MachineApplicable,
+                );
+            }
+        }
         e.emit();
         return DummyResult::raw_expr(sp, true);
     }
@@ -1282,7 +1342,7 @@ pub fn expand_preparsed_format_args(
 
     let mut cx = Context {
         ecx,
-        args,
+        args: args.into_iter().map(|arg| arg.expr).collect(),
         num_captured_args: 0,
         arg_types,
         arg_unique_types,
index 532049c858d4f4ce78218a816512d2a9c7acd9cb..402fbb16f97ee9f0acf661ef75b25739aa48d349 100644 (file)
@@ -15,9 +15,9 @@ dependencies = [
 
 [[package]]
 name = "anyhow"
-version = "1.0.56"
+version = "1.0.60"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27"
+checksum = "c794e162a5eff65c72ef524dfe393eb923c354e350bb78b9c7383df13f3bc142"
 
 [[package]]
 name = "ar"
index a0a640473eb516967cd16d3a3d2af2ecc7cb5c8e..96d238eda59d08d417a5910a505d8c5ea0f5bcde 100644 (file)
@@ -440,6 +440,8 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
             .features
             .split(',')
             .filter(|v| !v.is_empty() && backend_feature_name(v).is_some())
+            // Drop +atomics-32 feature introduced in LLVM 15.
+            .filter(|v| *v != "+atomics-32" || get_version() >= (15, 0, 0))
             .map(String::from),
     );
 
index 13a7b6be947ec9e4c443fbcdf0542a1a76810e59..953761a782052f952e1e60722253a49489d6e1f1 100644 (file)
@@ -1583,12 +1583,21 @@ fn crt_objects_fallback(sess: &Session, crate_type: CrateType) -> bool {
 fn add_pre_link_objects(
     cmd: &mut dyn Linker,
     sess: &Session,
+    flavor: LinkerFlavor,
     link_output_kind: LinkOutputKind,
     self_contained: bool,
 ) {
+    // FIXME: we are currently missing some infra here (per-linker-flavor CRT objects),
+    // so Fuchsia has to be special-cased.
     let opts = &sess.target;
-    let objects =
-        if self_contained { &opts.pre_link_objects_fallback } else { &opts.pre_link_objects };
+    let empty = Default::default();
+    let objects = if self_contained {
+        &opts.pre_link_objects_fallback
+    } else if !(sess.target.os == "fuchsia" && flavor == LinkerFlavor::Gcc) {
+        &opts.pre_link_objects
+    } else {
+        &empty
+    };
     for obj in objects.get(&link_output_kind).iter().copied().flatten() {
         cmd.add_object(&get_object_file_path(sess, obj, self_contained));
     }
@@ -1914,7 +1923,7 @@ fn linker_with_args<'a>(
     // ------------ Object code and libraries, order-dependent ------------
 
     // Pre-link CRT objects.
-    add_pre_link_objects(cmd, sess, link_output_kind, crt_objects_fallback);
+    add_pre_link_objects(cmd, sess, flavor, link_output_kind, crt_objects_fallback);
 
     add_linked_symbol_object(
         cmd,
@@ -2070,7 +2079,10 @@ fn add_order_independent_options(
 
     add_link_script(cmd, sess, tmpdir, crate_type);
 
-    if sess.target.os == "fuchsia" && crate_type == CrateType::Executable {
+    if sess.target.os == "fuchsia"
+        && crate_type == CrateType::Executable
+        && flavor != LinkerFlavor::Gcc
+    {
         let prefix = if sess.opts.unstable_opts.sanitizer.contains(SanitizerSet::ADDRESS) {
             "asan/"
         } else {
@@ -2267,7 +2279,7 @@ fn add_local_native_libraries(
                     // be added explicitly if necessary, see the error in `fn link_rlib`) compiled
                     // as an executable due to `--test`. Use whole-archive implicitly, like before
                     // the introduction of native lib modifiers.
-                    || (bundle != Some(false) && sess.opts.test)
+                    || (whole_archive == None && bundle != Some(false) && sess.opts.test)
                 {
                     cmd.link_whole_staticlib(
                         name,
@@ -2674,11 +2686,16 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
     let os = &sess.target.os;
     let llvm_target = &sess.target.llvm_target;
     if sess.target.vendor != "apple"
-        || !matches!(os.as_ref(), "ios" | "tvos" | "watchos")
-        || flavor != LinkerFlavor::Gcc
+        || !matches!(os.as_ref(), "ios" | "tvos" | "watchos" | "macos")
+        || (flavor != LinkerFlavor::Gcc && flavor != LinkerFlavor::Lld(LldFlavor::Ld64))
     {
         return;
     }
+
+    if os == "macos" && flavor != LinkerFlavor::Lld(LldFlavor::Ld64) {
+        return;
+    }
+
     let sdk_name = match (arch.as_ref(), os.as_ref()) {
         ("aarch64", "tvos") => "appletvos",
         ("x86_64", "tvos") => "appletvsimulator",
@@ -2694,6 +2711,7 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
         ("aarch64", "watchos") if llvm_target.ends_with("-simulator") => "watchsimulator",
         ("aarch64", "watchos") => "watchos",
         ("arm", "watchos") => "watchos",
+        (_, "macos") => "macosx",
         _ => {
             sess.err(&format!("unsupported arch `{}` for os `{}`", arch, os));
             return;
@@ -2706,13 +2724,16 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
             return;
         }
     };
-    if llvm_target.contains("macabi") {
-        cmd.args(&["-target", llvm_target])
-    } else {
-        let arch_name = llvm_target.split('-').next().expect("LLVM target must have a hyphen");
-        cmd.args(&["-arch", arch_name])
+
+    match flavor {
+        LinkerFlavor::Gcc => {
+            cmd.args(&["-isysroot", &sdk_root, "-Wl,-syslibroot", &sdk_root]);
+        }
+        LinkerFlavor::Lld(LldFlavor::Ld64) => {
+            cmd.args(&["-syslibroot", &sdk_root]);
+        }
+        _ => unreachable!(),
     }
-    cmd.args(&["-isysroot", &sdk_root, "-Wl,-syslibroot", &sdk_root]);
 }
 
 fn get_apple_sdk_root(sdk_name: &str) -> Result<String, String> {
index 1b5ad87107af6ded64e8d7f9bc05e4e102f534ed..dbd55590e5c08e0b6189d153b12a630c8fadbed9 100644 (file)
@@ -256,8 +256,11 @@ macro_rules! if_regular {
             {
                 MergeFunctions::Disabled => false,
                 MergeFunctions::Trampolines | MergeFunctions::Aliases => {
-                    sess.opts.optimize == config::OptLevel::Default
-                        || sess.opts.optimize == config::OptLevel::Aggressive
+                    use config::OptLevel::*;
+                    match sess.opts.optimize {
+                        Aggressive | Default | SizeMin | Size => true,
+                        Less | No => false,
+                    }
                 }
             },
 
index ba8222dc15218d245af6ab41ceab5d2524ad7e3b..936044fbe24b260455760eeb9ea52f26eac5dbae 100644 (file)
@@ -13,7 +13,7 @@
 use rustc_middle::traits::Reveal;
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::{self, subst::Subst, EarlyBinder, TyCtxt};
+use rustc_middle::ty::{self, subst::Subst, TyCtxt};
 use rustc_span::source_map::Span;
 use rustc_target::abi::{self, Abi};
 use std::borrow::Cow;
@@ -45,7 +45,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
         "Unexpected DefKind: {:?}",
         ecx.tcx.def_kind(cid.instance.def_id())
     );
-    let layout = ecx.layout_of(EarlyBinder(body.return_ty()).subst(tcx, cid.instance.substs))?;
+    let layout = ecx.layout_of(body.bound_return_ty().subst(tcx, cid.instance.substs))?;
     assert!(!layout.is_unsized());
     let ret = ecx.allocate(layout, MemoryKind::Stack)?;
 
index ed2c4edf9dd72920e0d634c2ae406cc8f65986e8..75528d6140ce5da524076c5de688394326687cde 100644 (file)
@@ -520,6 +520,8 @@ fn get_global_alloc(
 
     /// Gives raw access to the `Allocation`, without bounds or alignment checks.
     /// The caller is responsible for calling the access hooks!
+    ///
+    /// You almost certainly want to use `get_ptr_alloc`/`get_ptr_alloc_mut` instead.
     fn get_alloc_raw(
         &self,
         id: AllocId,
@@ -589,6 +591,11 @@ pub fn get_alloc_extra<'a>(&'a self, id: AllocId) -> InterpResult<'tcx, &'a M::A
         Ok(&self.get_alloc_raw(id)?.extra)
     }
 
+    /// Return the `mutability` field of the given allocation.
+    pub fn get_alloc_mutability<'a>(&'a self, id: AllocId) -> InterpResult<'tcx, Mutability> {
+        Ok(self.get_alloc_raw(id)?.mutability)
+    }
+
     /// Gives raw mutable access to the `Allocation`, without bounds or alignment checks.
     /// The caller is responsible for calling the access hooks!
     ///
index de284bd3bae3775a9000e3dbae1635d226403bdc..fe80a55dfd28ce9fbd6bb9a4273c4e04ea7b2960 100644 (file)
@@ -37,9 +37,6 @@ pub enum Immediate<Prov: Provenance = AllocId> {
     Uninit,
 }
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Immediate, 56);
-
 impl<Prov: Provenance> From<ScalarMaybeUninit<Prov>> for Immediate<Prov> {
     #[inline(always)]
     fn from(val: ScalarMaybeUninit<Prov>) -> Self {
@@ -117,9 +114,6 @@ pub struct ImmTy<'tcx, Prov: Provenance = AllocId> {
     pub layout: TyAndLayout<'tcx>,
 }
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(ImmTy<'_>, 72);
-
 impl<Prov: Provenance> std::fmt::Display for ImmTy<'_, Prov> {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         /// Helper function for printing a scalar to a FmtPrinter
@@ -187,9 +181,6 @@ pub enum Operand<Prov: Provenance = AllocId> {
     Indirect(MemPlace<Prov>),
 }
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Operand, 64);
-
 #[derive(Clone, Debug)]
 pub struct OpTy<'tcx, Prov: Provenance = AllocId> {
     op: Operand<Prov>, // Keep this private; it helps enforce invariants.
@@ -204,9 +195,6 @@ pub struct OpTy<'tcx, Prov: Provenance = AllocId> {
     pub align: Option<Align>,
 }
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(OpTy<'_>, 88);
-
 impl<'tcx, Prov: Provenance> std::ops::Deref for OpTy<'tcx, Prov> {
     type Target = Operand<Prov>;
     #[inline(always)]
@@ -830,3 +818,15 @@ pub fn read_discriminant(
         })
     }
 }
+
+// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+mod size_asserts {
+    use super::*;
+    use rustc_data_structures::static_assert_size;
+    // These are in alphabetical order, which is easy to maintain.
+    static_assert_size!(Immediate, 56);
+    static_assert_size!(ImmTy<'_>, 72);
+    static_assert_size!(Operand, 64);
+    static_assert_size!(OpTy<'_>, 88);
+}
index 473da71a0ab9cb570ee88d11d9eb89db16b347bf..97fe23cb5bcf3ee5f4e7741778635645c9730227 100644 (file)
@@ -25,9 +25,6 @@ pub enum MemPlaceMeta<Prov: Provenance = AllocId> {
     None,
 }
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(MemPlaceMeta, 24);
-
 impl<Prov: Provenance> MemPlaceMeta<Prov> {
     pub fn unwrap_meta(self) -> Scalar<Prov> {
         match self {
@@ -56,9 +53,6 @@ pub struct MemPlace<Prov: Provenance = AllocId> {
     pub meta: MemPlaceMeta<Prov>,
 }
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(MemPlace, 40);
-
 /// A MemPlace with its layout. Constructing it is only possible in this module.
 #[derive(Copy, Clone, Hash, Eq, PartialEq, Debug)]
 pub struct MPlaceTy<'tcx, Prov: Provenance = AllocId> {
@@ -71,9 +65,6 @@ pub struct MPlaceTy<'tcx, Prov: Provenance = AllocId> {
     pub align: Align,
 }
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(MPlaceTy<'_>, 64);
-
 #[derive(Copy, Clone, Debug)]
 pub enum Place<Prov: Provenance = AllocId> {
     /// A place referring to a value allocated in the `Memory` system.
@@ -84,9 +75,6 @@ pub enum Place<Prov: Provenance = AllocId> {
     Local { frame: usize, local: mir::Local },
 }
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Place, 48);
-
 #[derive(Clone, Debug)]
 pub struct PlaceTy<'tcx, Prov: Provenance = AllocId> {
     place: Place<Prov>, // Keep this private; it helps enforce invariants.
@@ -98,9 +86,6 @@ pub struct PlaceTy<'tcx, Prov: Provenance = AllocId> {
     pub align: Align,
 }
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(PlaceTy<'_>, 72);
-
 impl<'tcx, Prov: Provenance> std::ops::Deref for PlaceTy<'tcx, Prov> {
     type Target = Place<Prov>;
     #[inline(always)]
@@ -901,3 +886,16 @@ pub(super) fn unpack_dyn_trait(
         Ok(mplace)
     }
 }
+
+// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+mod size_asserts {
+    use super::*;
+    use rustc_data_structures::static_assert_size;
+    // These are in alphabetical order, which is easy to maintain.
+    static_assert_size!(MemPlaceMeta, 24);
+    static_assert_size!(MemPlace, 40);
+    static_assert_size!(MPlaceTy<'_>, 64);
+    static_assert_size!(Place, 48);
+    static_assert_size!(PlaceTy<'_>, 72);
+}
index 628298df4738560af218809c0cba1f6770768344..0adb88a180f8becdb183157af41c32965b2c9521 100644 (file)
@@ -772,7 +772,7 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                             let mut nonconst_call_permission = false;
                             if let Some(callee_trait) = tcx.trait_of_item(callee)
                                 && tcx.has_attr(callee_trait, sym::const_trait)
-                                && Some(callee_trait) == tcx.trait_of_item(caller)
+                                && Some(callee_trait) == tcx.trait_of_item(caller.to_def_id())
                                 // Can only call methods when it's `<Self as TheTrait>::f`.
                                 && tcx.types.self_param == substs.type_at(0)
                             {
index e099445117225e4a268718c01617e1612bcbeb63..45dadcfff2e5b9a5ebafdeba23b8574ce29eee1c 100644 (file)
@@ -5,12 +5,11 @@
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::LangItem;
 use rustc_infer::infer::TyCtxtInferExt;
-use rustc_infer::traits::TraitEngine;
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty};
 use rustc_span::DUMMY_SP;
 use rustc_trait_selection::traits::{
-    self, FulfillmentContext, ImplSource, Obligation, ObligationCause, SelectionContext,
+    self, ImplSource, Obligation, ObligationCause, SelectionContext,
 };
 
 use super::ConstCx;
@@ -189,15 +188,8 @@ fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
                 return false;
             }
 
-            // If we successfully found one, then select all of the predicates
-            // implied by our const drop impl.
-            let mut fcx = FulfillmentContext::new();
-            for nested in impl_src.nested_obligations() {
-                fcx.register_predicate_obligation(&infcx, nested);
-            }
-
             // If we had any errors, then it's bad
-            !fcx.select_all_or_error(&infcx).is_empty()
+            !traits::fully_solve_obligations(&infcx, impl_src.nested_obligations()).is_empty()
         })
     }
 
index fe4a726fe12a0df8481ff4f389685b2d65c83a76..4f39dad205ae335e6ede6e21880021c05245b288 100644 (file)
@@ -48,20 +48,16 @@ fn is_within_packed<'tcx, L>(
 where
     L: HasLocalDecls<'tcx>,
 {
-    for (place_base, elem) in place.iter_projections().rev() {
-        match elem {
-            // encountered a Deref, which is ABI-aligned
-            ProjectionElem::Deref => break,
-            ProjectionElem::Field(..) => {
-                let ty = place_base.ty(local_decls, tcx).ty;
-                match ty.kind() {
-                    ty::Adt(def, _) => return def.repr().pack,
-                    _ => {}
-                }
-            }
-            _ => {}
-        }
-    }
-
-    None
+    place
+        .iter_projections()
+        .rev()
+        // Stop at `Deref`; standard ABI alignment applies there.
+        .take_while(|(_base, elem)| !matches!(elem, ProjectionElem::Deref))
+        // Consider the packed alignments at play here...
+        .filter_map(|(base, _elem)| {
+            base.ty(local_decls, tcx).ty.ty_adt_def().and_then(|adt| adt.repr().pack)
+        })
+        // ... and compute their minimum.
+        // The overall smallest alignment is what matters.
+        .min()
 }
index a7a480dd1d79018063d2bb74030e875767374c3e..af9d83f0609e5ef7779820689cd80595e5cb3db8 100644 (file)
@@ -66,9 +66,12 @@ pub fn call_kind<'tcx>(
     from_hir_call: bool,
     self_arg: Option<Ident>,
 ) -> CallKind<'tcx> {
-    let parent = tcx.opt_associated_item(method_did).and_then(|assoc| match assoc.container {
-        AssocItemContainer::ImplContainer(impl_did) => tcx.trait_id_of_impl(impl_did),
-        AssocItemContainer::TraitContainer(trait_did) => Some(trait_did),
+    let parent = tcx.opt_associated_item(method_did).and_then(|assoc| {
+        let container_id = assoc.container_id(tcx);
+        match assoc.container {
+            AssocItemContainer::ImplContainer => tcx.trait_id_of_impl(container_id),
+            AssocItemContainer::TraitContainer => Some(container_id),
+        }
     });
 
     let fn_call = parent
index 53ae913f94f124f9dd1166c5eb723e177d21253b..94639bf8e1ee4f1d122cd6bf52e382d9e79d52dd 100644 (file)
@@ -1148,6 +1148,17 @@ pub fn catch_with_exit_code(f: impl FnOnce() -> interface::Result<()>) -> i32 {
     LazyLock::new(|| {
         let hook = panic::take_hook();
         panic::set_hook(Box::new(|info| {
+            // If the error was caused by a broken pipe then this is not a bug.
+            // Write the error and return immediately. See #98700.
+            #[cfg(windows)]
+            if let Some(msg) = info.payload().downcast_ref::<String>() {
+                if msg.starts_with("failed printing to stdout: ") && msg.ends_with("(os error 232)")
+                {
+                    early_error_no_abort(ErrorOutputType::default(), &msg);
+                    return;
+                }
+            };
+
             // Invoke the default handler, which prints the actual panic message and optionally a backtrace
             (*DEFAULT_HOOK)(info);
 
index b17eb9c2d260e9a4a14b9eb07220b229ed5a6c7f..d8056c77f0f4233cd1f01a689723b65cfc23a902 100644 (file)
@@ -262,3 +262,6 @@ passes-rustc-lint-opt-ty = `#[rustc_lint_opt_ty]` should be applied to a struct
 
 passes-rustc-lint-opt-deny-field-access = `#[rustc_lint_opt_deny_field_access]` should be applied to a field
     .label = not a field
+
+passes-link-ordinal = attribute should be applied to a foreign function or static
+    .label = not a foreign function or static
\ No newline at end of file
index 7d7e92c522922fbf99ba2ac57eb238023a85c715..36805aa874fe7740961f1740f80317f74556e02e 100644 (file)
@@ -18,7 +18,7 @@ rustc_lint_defs = { path = "../rustc_lint_defs" }
 unicode-width = "0.1.4"
 atty = "0.2"
 termcolor = "1.0"
-annotate-snippets = "0.8.0"
+annotate-snippets = "0.9"
 termize = "0.1.1"
 serde = { version = "1.0.125", features = ["derive"] }
 serde_json = "1.0.59"
index 0fcd61d1e58c37f2b06456dd7149d20c0108f2f3..3df562c7edac7fc1ca0077797aa455b7f2cc5db2 100644 (file)
@@ -183,7 +183,11 @@ fn emit_messages_default(
                     annotation_type: annotation_type_for_level(*level),
                 }),
                 footer: vec![],
-                opt: FormatOptions { color: true, anonymized_line_numbers: self.ui_testing },
+                opt: FormatOptions {
+                    color: true,
+                    anonymized_line_numbers: self.ui_testing,
+                    margin: None,
+                },
                 slices: annotated_files
                     .iter()
                     .map(|(source, line_index, annotations)| {
index 2a4f609a2d8a41b6d703012a0edf365cafea7c82..17e6c9e9575fd28dd56922b981051a44233a4113 100644 (file)
@@ -40,6 +40,26 @@ pub trait IntoDiagnosticArg {
     fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static>;
 }
 
+pub struct DiagnosticArgFromDisplay<'a>(pub &'a dyn fmt::Display);
+
+impl IntoDiagnosticArg for DiagnosticArgFromDisplay<'_> {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        self.0.to_string().into_diagnostic_arg()
+    }
+}
+
+impl<'a> From<&'a dyn fmt::Display> for DiagnosticArgFromDisplay<'a> {
+    fn from(t: &'a dyn fmt::Display) -> Self {
+        DiagnosticArgFromDisplay(t)
+    }
+}
+
+impl<'a, T: fmt::Display> From<&'a T> for DiagnosticArgFromDisplay<'a> {
+    fn from(t: &'a T) -> Self {
+        DiagnosticArgFromDisplay(t)
+    }
+}
+
 macro_rules! into_diagnostic_arg_using_display {
     ($( $ty:ty ),+ $(,)?) => {
         $(
index b173ac0e916b8fd2af682d92643d5bb237cce340..15c1858023de7f0de498a09245e7257fda773372 100644 (file)
@@ -4,7 +4,6 @@
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(drain_filter)]
-#![feature(backtrace)]
 #![feature(if_let_guard)]
 #![cfg_attr(bootstrap, feature(let_chains))]
 #![feature(let_else)]
@@ -371,8 +370,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 impl error::Error for ExplicitBug {}
 
 pub use diagnostic::{
-    AddSubdiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgValue, DiagnosticId,
-    DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic,
+    AddSubdiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgFromDisplay,
+    DiagnosticArgValue, DiagnosticId, DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic,
 };
 pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee, LintDiagnosticBuilder};
 use std::backtrace::Backtrace;
index 6e093811fcf6efe112c7bcb9ef25292a86ed091e..852ea806b20ff51c64139e3b5a2b293f7496b877 100644 (file)
@@ -772,7 +772,7 @@ pub fn new(
                 )
             })
             .unwrap_or_else(|| (None, helper_attrs));
-        let (stability, const_stability) = attr::find_stability(&sess, attrs, span);
+        let (stability, const_stability, body_stability) = attr::find_stability(&sess, attrs, span);
         if let Some((_, sp)) = const_stability {
             sess.parse_sess
                 .span_diagnostic
@@ -784,6 +784,17 @@ pub fn new(
                 )
                 .emit();
         }
+        if let Some((_, sp)) = body_stability {
+            sess.parse_sess
+                .span_diagnostic
+                .struct_span_err(sp, "macros cannot have body stability attributes")
+                .span_label(sp, "invalid body stability attribute")
+                .span_label(
+                    sess.source_map().guess_head_span(span),
+                    "body stability attribute affects this macro",
+                )
+                .emit();
+        }
 
         SyntaxExtension {
             kind,
index f7e1575afbf429b547d9c91084bb5389138df363..e009e4f7c68d09388b4e9c26388fdae6755528fd 100644 (file)
@@ -14,7 +14,7 @@
 use rustc_ast_pretty::pprust;
 use rustc_attr::{self as attr, TransparencyError};
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
-use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
+use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder};
 use rustc_feature::Features;
 use rustc_lint_defs::builtin::{
     RUST_2021_INCOMPATIBLE_OR_PATTERNS, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
@@ -608,11 +608,7 @@ enum ExplainDocComment {
     },
 }
 
-fn annotate_doc_comment(
-    err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
-    sm: &SourceMap,
-    span: Span,
-) {
+fn annotate_doc_comment(err: &mut Diagnostic, sm: &SourceMap, span: Span) {
     if let Ok(src) = sm.span_to_snippet(span) {
         if src.starts_with("///") || src.starts_with("/**") {
             err.subdiagnostic(ExplainDocComment::Outer { span });
index 0e73d8fd7f600f284e2af7be4c7f08cf89c3d344..ee46a364546a92fa94cf3786bfc57698e94abddf 100644 (file)
@@ -499,6 +499,10 @@ pub struct BuiltinAttribute {
     ),
     ungated!(rustc_const_unstable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk),
     ungated!(rustc_const_stable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk),
+    ungated!(
+        rustc_default_body_unstable, Normal,
+        template!(List: r#"feature = "name", reason = "...", issue = "N""#), DuplicatesOk
+    ),
     gated!(
         allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."), DuplicatesOk,
         "allow_internal_unstable side-steps feature gating and stability checks",
index 5f8801cc4e20d67cc180edc5af4b049e81520be8..c2c551e78a41105af9ee32fe96fbabbd750a3b7e 100644 (file)
@@ -338,7 +338,12 @@ pub fn new(stable_crate_id: StableCrateId) -> Definitions {
 
     /// Adds a definition with a parent definition.
     pub fn create_def(&mut self, parent: LocalDefId, data: DefPathData) -> LocalDefId {
-        debug!("create_def(parent={:?}, data={:?})", parent, data);
+        // We can't use `Debug` implementation for `LocalDefId` here, since it tries to acquire a
+        // reference to `Definitions` and we're already holding a mutable reference.
+        debug!(
+            "create_def(parent={}, data={data:?})",
+            self.def_path(parent).to_string_no_crate_verbose(),
+        );
 
         // The root node must be created with `create_root_def()`.
         assert!(data != DefPathData::CrateRoot);
index f71400898e60b44fa561f49917a481dd650c9ce5..7a87a3e4882601700eb7e5ebd1ef9272d4769d8a 100644 (file)
@@ -2222,6 +2222,7 @@ pub struct TraitItem<'hir> {
     pub generics: &'hir Generics<'hir>,
     pub kind: TraitItemKind<'hir>,
     pub span: Span,
+    pub defaultness: Defaultness,
 }
 
 impl TraitItem<'_> {
@@ -2281,6 +2282,7 @@ pub struct ImplItem<'hir> {
     pub def_id: LocalDefId,
     pub generics: &'hir Generics<'hir>,
     pub kind: ImplItemKind<'hir>,
+    pub defaultness: Defaultness,
     pub span: Span,
     pub vis_span: Span,
 }
@@ -3083,7 +3085,6 @@ pub struct TraitItemRef {
     pub ident: Ident,
     pub kind: AssocItemKind,
     pub span: Span,
-    pub defaultness: Defaultness,
 }
 
 /// A reference from an impl to one of its associated items. This
@@ -3098,7 +3099,6 @@ pub struct ImplItemRef {
     pub ident: Ident,
     pub kind: AssocItemKind,
     pub span: Span,
-    pub defaultness: Defaultness,
     /// When we are in a trait impl, link to the trait-item's id.
     pub trait_item_def_id: Option<DefId>,
 }
@@ -3489,17 +3489,18 @@ pub fn tuple_fields(&self) -> Option<&'hir [FieldDef<'hir>]> {
 // Some nodes are used a lot. Make sure they don't unintentionally get bigger.
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 mod size_asserts {
-    rustc_data_structures::static_assert_size!(super::Block<'static>, 48);
-    rustc_data_structures::static_assert_size!(super::Expr<'static>, 56);
-    rustc_data_structures::static_assert_size!(super::Pat<'static>, 88);
-    rustc_data_structures::static_assert_size!(super::QPath<'static>, 24);
-    rustc_data_structures::static_assert_size!(super::Ty<'static>, 72);
-    rustc_data_structures::static_assert_size!(super::GenericBound<'_>, 48);
-    rustc_data_structures::static_assert_size!(super::Generics<'static>, 56);
-    rustc_data_structures::static_assert_size!(super::Impl<'static>, 80);
-
-    rustc_data_structures::static_assert_size!(super::Item<'static>, 80);
-    rustc_data_structures::static_assert_size!(super::TraitItem<'static>, 88);
-    rustc_data_structures::static_assert_size!(super::ImplItem<'static>, 80);
-    rustc_data_structures::static_assert_size!(super::ForeignItem<'static>, 72);
+    use super::*;
+    // These are in alphabetical order, which is easy to maintain.
+    static_assert_size!(Block<'static>, 48);
+    static_assert_size!(Expr<'static>, 56);
+    static_assert_size!(ForeignItem<'static>, 72);
+    static_assert_size!(GenericBound<'_>, 48);
+    static_assert_size!(Generics<'static>, 56);
+    static_assert_size!(ImplItem<'static>, 88);
+    static_assert_size!(Impl<'static>, 80);
+    static_assert_size!(Item<'static>, 80);
+    static_assert_size!(Pat<'static>, 88);
+    static_assert_size!(QPath<'static>, 24);
+    static_assert_size!(TraitItem<'static>, 96);
+    static_assert_size!(Ty<'static>, 72);
 }
index 640974115b926e2075a9b26f42d13c3c7b4c0352..51b1bfad8a0d85a2cbdcc16d9178866dab6a57b5 100644 (file)
@@ -385,30 +385,17 @@ fn visit_param_bound(&mut self, bounds: &'v GenericBound<'v>) {
     fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef<'v>, m: TraitBoundModifier) {
         walk_poly_trait_ref(self, t, m)
     }
-    fn visit_variant_data(
-        &mut self,
-        s: &'v VariantData<'v>,
-        _: Symbol,
-        _: &'v Generics<'v>,
-        _parent_id: HirId,
-        _: Span,
-    ) {
+    fn visit_variant_data(&mut self, s: &'v VariantData<'v>) {
         walk_struct_def(self, s)
     }
     fn visit_field_def(&mut self, s: &'v FieldDef<'v>) {
         walk_field_def(self, s)
     }
-    fn visit_enum_def(
-        &mut self,
-        enum_definition: &'v EnumDef<'v>,
-        generics: &'v Generics<'v>,
-        item_id: HirId,
-        _: Span,
-    ) {
-        walk_enum_def(self, enum_definition, generics, item_id)
+    fn visit_enum_def(&mut self, enum_definition: &'v EnumDef<'v>, item_id: HirId) {
+        walk_enum_def(self, enum_definition, item_id)
     }
-    fn visit_variant(&mut self, v: &'v Variant<'v>, g: &'v Generics<'v>, item_id: HirId) {
-        walk_variant(self, v, g, item_id)
+    fn visit_variant(&mut self, v: &'v Variant<'v>) {
+        walk_variant(self, v)
     }
     fn visit_label(&mut self, label: &'v Label) {
         walk_label(self, label)
@@ -572,7 +559,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) {
         ItemKind::Enum(ref enum_definition, ref generics) => {
             visitor.visit_generics(generics);
             // `visit_enum_def()` takes care of visiting the `Item`'s `HirId`.
-            visitor.visit_enum_def(enum_definition, generics, item.hir_id(), item.span)
+            visitor.visit_enum_def(enum_definition, item.hir_id())
         }
         ItemKind::Impl(Impl {
             unsafety: _,
@@ -595,13 +582,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) {
         | ItemKind::Union(ref struct_definition, ref generics) => {
             visitor.visit_generics(generics);
             visitor.visit_id(item.hir_id());
-            visitor.visit_variant_data(
-                struct_definition,
-                item.ident.name,
-                generics,
-                item.hir_id(),
-                item.span,
-            );
+            visitor.visit_variant_data(struct_definition);
         }
         ItemKind::Trait(.., ref generics, bounds, trait_item_refs) => {
             visitor.visit_id(item.hir_id());
@@ -649,28 +630,16 @@ pub fn walk_use<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path<'v>, hir_id:
 pub fn walk_enum_def<'v, V: Visitor<'v>>(
     visitor: &mut V,
     enum_definition: &'v EnumDef<'v>,
-    generics: &'v Generics<'v>,
     item_id: HirId,
 ) {
     visitor.visit_id(item_id);
-    walk_list!(visitor, visit_variant, enum_definition.variants, generics, item_id);
+    walk_list!(visitor, visit_variant, enum_definition.variants);
 }
 
-pub fn walk_variant<'v, V: Visitor<'v>>(
-    visitor: &mut V,
-    variant: &'v Variant<'v>,
-    generics: &'v Generics<'v>,
-    parent_item_id: HirId,
-) {
+pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V, variant: &'v Variant<'v>) {
     visitor.visit_ident(variant.ident);
     visitor.visit_id(variant.id);
-    visitor.visit_variant_data(
-        &variant.data,
-        variant.ident.name,
-        generics,
-        parent_item_id,
-        variant.span,
-    );
+    visitor.visit_variant_data(&variant.data);
     walk_list!(visitor, visit_anon_const, &variant.disr_expr);
 }
 
@@ -946,32 +915,30 @@ pub fn walk_fn<'v, V: Visitor<'v>>(
 }
 
 pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v TraitItem<'v>) {
-    visitor.visit_ident(trait_item.ident);
-    visitor.visit_generics(&trait_item.generics);
-    match trait_item.kind {
+    // N.B., deliberately force a compilation error if/when new fields are added.
+    let TraitItem { ident, generics, ref defaultness, ref kind, span, def_id: _ } = *trait_item;
+    let hir_id = trait_item.hir_id();
+    visitor.visit_ident(ident);
+    visitor.visit_generics(&generics);
+    visitor.visit_defaultness(&defaultness);
+    match *kind {
         TraitItemKind::Const(ref ty, default) => {
-            visitor.visit_id(trait_item.hir_id());
+            visitor.visit_id(hir_id);
             visitor.visit_ty(ty);
             walk_list!(visitor, visit_nested_body, default);
         }
         TraitItemKind::Fn(ref sig, TraitFn::Required(param_names)) => {
-            visitor.visit_id(trait_item.hir_id());
+            visitor.visit_id(hir_id);
             visitor.visit_fn_decl(&sig.decl);
             for &param_name in param_names {
                 visitor.visit_ident(param_name);
             }
         }
         TraitItemKind::Fn(ref sig, TraitFn::Provided(body_id)) => {
-            visitor.visit_fn(
-                FnKind::Method(trait_item.ident, sig),
-                &sig.decl,
-                body_id,
-                trait_item.span,
-                trait_item.hir_id(),
-            );
+            visitor.visit_fn(FnKind::Method(ident, sig), &sig.decl, body_id, span, hir_id);
         }
         TraitItemKind::Type(bounds, ref default) => {
-            visitor.visit_id(trait_item.hir_id());
+            visitor.visit_id(hir_id);
             walk_list!(visitor, visit_param_bound, bounds);
             walk_list!(visitor, visit_ty, default);
         }
@@ -980,19 +947,27 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai
 
 pub fn walk_trait_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, trait_item_ref: &'v TraitItemRef) {
     // N.B., deliberately force a compilation error if/when new fields are added.
-    let TraitItemRef { id, ident, ref kind, span: _, ref defaultness } = *trait_item_ref;
+    let TraitItemRef { id, ident, ref kind, span: _ } = *trait_item_ref;
     visitor.visit_nested_trait_item(id);
     visitor.visit_ident(ident);
     visitor.visit_associated_item_kind(kind);
-    visitor.visit_defaultness(defaultness);
 }
 
 pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplItem<'v>) {
     // N.B., deliberately force a compilation error if/when new fields are added.
-    let ImplItem { def_id: _, ident, ref generics, ref kind, span: _, vis_span: _ } = *impl_item;
+    let ImplItem {
+        def_id: _,
+        ident,
+        ref generics,
+        ref kind,
+        ref defaultness,
+        span: _,
+        vis_span: _,
+    } = *impl_item;
 
     visitor.visit_ident(ident);
     visitor.visit_generics(generics);
+    visitor.visit_defaultness(defaultness);
     match *kind {
         ImplItemKind::Const(ref ty, body) => {
             visitor.visit_id(impl_item.hir_id());
@@ -1027,12 +1002,10 @@ pub fn walk_foreign_item_ref<'v, V: Visitor<'v>>(
 
 pub fn walk_impl_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, impl_item_ref: &'v ImplItemRef) {
     // N.B., deliberately force a compilation error if/when new fields are added.
-    let ImplItemRef { id, ident, ref kind, span: _, ref defaultness, trait_item_def_id: _ } =
-        *impl_item_ref;
+    let ImplItemRef { id, ident, ref kind, span: _, trait_item_def_id: _ } = *impl_item_ref;
     visitor.visit_nested_impl_item(id);
     visitor.visit_ident(ident);
     visitor.visit_associated_item_kind(kind);
-    visitor.visit_defaultness(defaultness);
 }
 
 pub fn walk_struct_def<'v, V: Visitor<'v>>(
index 13b3e954e1f5889d906536bbfaf912b65a469eb6..c337be12ae4929416e36901c49c3f09b7e7b33ce 100644 (file)
@@ -191,6 +191,9 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
     CoerceUnsized,           sym::coerce_unsized,      coerce_unsized_trait,       Target::Trait,          GenericRequirement::Minimum(1);
     DispatchFromDyn,         sym::dispatch_from_dyn,   dispatch_from_dyn_trait,    Target::Trait,          GenericRequirement::Minimum(1);
 
+    // language items relating to transmutability
+    TransmuteTrait,          sym::transmute_trait,     transmute_trait,            Target::Trait,          GenericRequirement::Exact(6);
+
     Add(Op),                 sym::add,                 add_trait,                  Target::Trait,          GenericRequirement::Exact(1);
     Sub(Op),                 sym::sub,                 sub_trait,                  Target::Trait,          GenericRequirement::Exact(1);
     Mul(Op),                 sym::mul,                 mul_trait,                  Target::Trait,          GenericRequirement::Exact(1);
index 96dd00ec5cff193210506e64b99e8a60fb285981..6236dea10c88f3c23258a1821f56199c7bef3085 100644 (file)
@@ -60,51 +60,7 @@ pub enum Target {
 
 impl Display for Target {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(
-            f,
-            "{}",
-            match *self {
-                Target::ExternCrate => "extern crate",
-                Target::Use => "use",
-                Target::Static => "static item",
-                Target::Const => "constant item",
-                Target::Fn => "function",
-                Target::Closure => "closure",
-                Target::Mod => "module",
-                Target::ForeignMod => "foreign module",
-                Target::GlobalAsm => "global asm",
-                Target::TyAlias => "type alias",
-                Target::OpaqueTy => "opaque type",
-                Target::Enum => "enum",
-                Target::Variant => "enum variant",
-                Target::Struct => "struct",
-                Target::Field => "struct field",
-                Target::Union => "union",
-                Target::Trait => "trait",
-                Target::TraitAlias => "trait alias",
-                Target::Impl => "item",
-                Target::Expression => "expression",
-                Target::Statement => "statement",
-                Target::Arm => "match arm",
-                Target::AssocConst => "associated const",
-                Target::Method(kind) => match kind {
-                    MethodKind::Inherent => "inherent method",
-                    MethodKind::Trait { body: false } => "required trait method",
-                    MethodKind::Trait { body: true } => "provided trait method",
-                },
-                Target::AssocTy => "associated type",
-                Target::ForeignFn => "foreign function",
-                Target::ForeignStatic => "foreign static item",
-                Target::ForeignTy => "foreign type",
-                Target::GenericParam(kind) => match kind {
-                    GenericParamKind::Type => "type parameter",
-                    GenericParamKind::Lifetime => "lifetime parameter",
-                    GenericParamKind::Const => "const parameter",
-                },
-                Target::MacroDef => "macro def",
-                Target::Param => "function param",
-            }
-        )
+        write!(f, "{}", Self::name(*self))
     }
 }
 
@@ -185,4 +141,48 @@ pub fn from_generic_param(generic_param: &hir::GenericParam<'_>) -> Target {
             hir::GenericParamKind::Const { .. } => Target::GenericParam(GenericParamKind::Const),
         }
     }
+
+    pub fn name(self) -> &'static str {
+        match self {
+            Target::ExternCrate => "extern crate",
+            Target::Use => "use",
+            Target::Static => "static item",
+            Target::Const => "constant item",
+            Target::Fn => "function",
+            Target::Closure => "closure",
+            Target::Mod => "module",
+            Target::ForeignMod => "foreign module",
+            Target::GlobalAsm => "global asm",
+            Target::TyAlias => "type alias",
+            Target::OpaqueTy => "opaque type",
+            Target::Enum => "enum",
+            Target::Variant => "enum variant",
+            Target::Struct => "struct",
+            Target::Field => "struct field",
+            Target::Union => "union",
+            Target::Trait => "trait",
+            Target::TraitAlias => "trait alias",
+            Target::Impl => "implementation block",
+            Target::Expression => "expression",
+            Target::Statement => "statement",
+            Target::Arm => "match arm",
+            Target::AssocConst => "associated const",
+            Target::Method(kind) => match kind {
+                MethodKind::Inherent => "inherent method",
+                MethodKind::Trait { body: false } => "required trait method",
+                MethodKind::Trait { body: true } => "provided trait method",
+            },
+            Target::AssocTy => "associated type",
+            Target::ForeignFn => "foreign function",
+            Target::ForeignStatic => "foreign static item",
+            Target::ForeignTy => "foreign type",
+            Target::GenericParam(kind) => match kind {
+                GenericParamKind::Type => "type parameter",
+                GenericParamKind::Lifetime => "lifetime parameter",
+                GenericParamKind::Const => "const parameter",
+            },
+            Target::MacroDef => "macro def",
+            Target::Param => "function param",
+        }
+    }
 }
index 35a278e6c92abb87b1faecffad452ba33347e63e..710c4a01b244f81e79fe37c1eaa1d49ad591551d 100644 (file)
@@ -80,7 +80,7 @@
 /// Extra `DepNode`s for functions and methods.
 const EXTRA_ASSOCIATED: &[&str] = &[label_strs::associated_item];
 
-const EXTRA_TRAIT: &[&str] = &[label_strs::trait_of_item];
+const EXTRA_TRAIT: &[&str] = &[];
 
 // Fully Built Labels
 
index 9c30c81123b1487092db51b365336a9d69554b26..ca7862c9dc46778be5f69fa54b76bf54bfc48a86 100644 (file)
@@ -511,7 +511,9 @@ fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
             }
             ty::ConstKind::Placeholder(placeholder) => {
                 return self.canonicalize_const_var(
-                    CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderConst(placeholder) },
+                    CanonicalVarInfo {
+                        kind: CanonicalVarKind::PlaceholderConst(placeholder, ct.ty()),
+                    },
                     ct,
                 );
             }
@@ -695,11 +697,14 @@ fn canonical_var(&mut self, info: CanonicalVarInfo<'tcx>, kind: GenericArg<'tcx>
                             ..placeholder
                         })
                     }
-                    CanonicalVarKind::PlaceholderConst(placeholder) => {
-                        CanonicalVarKind::PlaceholderConst(ty::Placeholder {
-                            universe: reverse_universe_map[&placeholder.universe],
-                            ..placeholder
-                        })
+                    CanonicalVarKind::PlaceholderConst(placeholder, t) => {
+                        CanonicalVarKind::PlaceholderConst(
+                            ty::Placeholder {
+                                universe: reverse_universe_map[&placeholder.universe],
+                                ..placeholder
+                            },
+                            t,
+                        )
                     }
                 },
             })
index f251d561c6087bd09fb8984768e999a9f9339dd6..a9294a85e51894b15688cab9dba92b0babbf802c 100644 (file)
@@ -144,13 +144,13 @@ fn instantiate_canonical_var(
                 )
                 .into(),
 
-            CanonicalVarKind::PlaceholderConst(ty::PlaceholderConst { universe, name }) => {
+            CanonicalVarKind::PlaceholderConst(ty::PlaceholderConst { universe, name }, ty) => {
                 let universe_mapped = universe_map(universe);
                 let placeholder_mapped = ty::PlaceholderConst { universe: universe_mapped, name };
                 self.tcx
                     .mk_const(ty::ConstS {
                         kind: ty::ConstKind::Placeholder(placeholder_mapped),
-                        ty: name.ty,
+                        ty,
                     })
                     .into()
             }
index 246d27be71cffa85e97c4b9c63f81b2457d9a4a1..9886c572a8aaf4897d0de7dca6b4244ec71e0526 100644 (file)
@@ -76,10 +76,11 @@ pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorGuaranteed> {
                             "...is used and required to live as long as `'static` here \
                              because of an implicit lifetime bound on the {}",
                             match ctxt.assoc_item.container {
-                                AssocItemContainer::TraitContainer(id) =>
-                                    format!("`impl` of `{}`", tcx.def_path_str(id)),
-                                AssocItemContainer::ImplContainer(_) =>
-                                    "inherent `impl`".to_string(),
+                                AssocItemContainer::TraitContainer => {
+                                    let id = ctxt.assoc_item.container_id(tcx);
+                                    format!("`impl` of `{}`", tcx.def_path_str(id))
+                                }
+                                AssocItemContainer::ImplContainer => "inherent `impl`".to_string(),
                             },
                         ),
                     );
index ed257c144e0aacb3b1d9cf2d7da7cd2f907d7123..d0d9efe152cc04109799f78aa8df246f6db4a191 100644 (file)
@@ -17,7 +17,7 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> {
     ///
     /// This is implemented by first entering a new universe.
     /// We then replace all bound variables in `sup` with placeholders,
-    /// and all bound variables in `sup` with inference vars.
+    /// and all bound variables in `sub` with inference vars.
     /// We can then just relate the two resulting types as normal.
     ///
     /// Note: this is a subtle algorithm. For a full explanation, please see
@@ -97,7 +97,7 @@ pub fn replace_bound_vars_with_placeholders<T>(&self, binder: ty::Binder<'tcx, T
                 self.tcx.mk_const(ty::ConstS {
                     kind: ty::ConstKind::Placeholder(ty::PlaceholderConst {
                         universe: next_universe,
-                        name: ty::BoundConst { var: bound_var, ty },
+                        name: bound_var,
                     }),
                     ty,
                 })
index 6d5f4993d8d298261e8371a2ae576543b9139941..d7d1b5fa218680207754c6ad4af269bd2d595b16 100644 (file)
@@ -8,7 +8,7 @@
 use self::opaque_types::OpaqueTypeStorage;
 pub(crate) use self::undo_log::{InferCtxtUndoLogs, Snapshot, UndoLog};
 
-use crate::traits::{self, ObligationCause, PredicateObligations, TraitEngine};
+use crate::traits::{self, ObligationCause, PredicateObligations, TraitEngine, TraitEngineExt};
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::Lrc;
@@ -645,9 +645,7 @@ pub fn into_value_registering_obligations(
         fulfill_cx: &mut dyn TraitEngine<'tcx>,
     ) -> T {
         let InferOk { value, obligations } = self;
-        for obligation in obligations {
-            fulfill_cx.register_predicate_obligation(infcx, obligation);
-        }
+        fulfill_cx.register_predicate_obligations(infcx, obligations);
         value
     }
 }
@@ -842,18 +840,6 @@ fn commit_from(&self, snapshot: CombinedSnapshot<'a, 'tcx>) {
         self.inner.borrow_mut().commit(undo_snapshot);
     }
 
-    /// Executes `f` and commit the bindings.
-    #[instrument(skip(self, f), level = "debug")]
-    pub fn commit_unconditionally<R, F>(&self, f: F) -> R
-    where
-        F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R,
-    {
-        let snapshot = self.start_snapshot();
-        let r = f(&snapshot);
-        self.commit_from(snapshot);
-        r
-    }
-
     /// Execute `f` and commit the bindings if closure `f` returns `Ok(_)`.
     #[instrument(skip(self, f), level = "debug")]
     pub fn commit_if_ok<T, E, F>(&self, f: F) -> Result<T, E>
@@ -2069,7 +2055,7 @@ fn replace_param_and_infer_substs_with_placeholder<'tcx>(
                     ty,
                     kind: ty::ConstKind::Placeholder(ty::PlaceholderConst {
                         universe: ty::UniverseIndex::ROOT,
-                        name: ty::BoundConst { ty, var: ty::BoundVar::from_usize(idx) },
+                        name: ty::BoundVar::from_usize(idx),
                     }),
                 })
                 .into()
index 0d4472a1cfd9c11944821f2992dca524e9458c39..780e6ead10efa8e6062e8d0fa185735a54db43f1 100644 (file)
@@ -187,7 +187,7 @@ pub enum GenericKind<'tcx> {
 /// }
 /// ```
 /// This is described with an `AnyRegion('a, 'b)` node.
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, TypeFoldable, TypeVisitable)]
 pub enum VerifyBound<'tcx> {
     /// See [`VerifyIfEq`] docs
     IfEq(ty::Binder<'tcx, VerifyIfEq<'tcx>>),
index 0ba6c56dbb50147b7e54ad80dccdeb7b00649c39..21557a9c8540126fb09d8724626c624d888ac9b8 100644 (file)
@@ -61,8 +61,8 @@ pub(crate) fn is_eof(&self) -> bool {
     }
 
     /// Returns amount of already consumed symbols.
-    pub(crate) fn len_consumed(&self) -> usize {
-        self.initial_len - self.chars.as_str().len()
+    pub(crate) fn len_consumed(&self) -> u32 {
+        (self.initial_len - self.chars.as_str().len()) as u32
     }
 
     /// Resets the number of bytes consumed to 0.
index a41e0374f410ae969dacb26a62afc50fb6d73d09..6d311af9007b1684a1bb6e738b6b20a76d4773d6 100644 (file)
 #[derive(Debug)]
 pub struct Token {
     pub kind: TokenKind,
-    pub len: usize,
+    pub len: u32,
 }
 
 impl Token {
-    fn new(kind: TokenKind, len: usize) -> Token {
+    fn new(kind: TokenKind, len: u32) -> Token {
         Token { kind, len }
     }
 }
 
 /// Enum representing common lexeme types.
-// perf note: Changing all `usize` to `u32` doesn't change performance. See #77629
-#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 pub enum TokenKind {
     // Multi-char tokens:
     /// "// comment"
@@ -76,7 +75,7 @@ pub enum TokenKind {
     /// tokens.
     UnknownPrefix,
     /// "12_u8", "1.0e-40", "b"123"". See `LiteralKind` for more details.
-    Literal { kind: LiteralKind, suffix_start: usize },
+    Literal { kind: LiteralKind, suffix_start: u32 },
     /// "'a"
     Lifetime { starts_with_number: bool },
 
@@ -160,26 +159,24 @@ pub enum LiteralKind {
     Str { terminated: bool },
     /// "b"abc"", "b"abc"
     ByteStr { terminated: bool },
-    /// "r"abc"", "r#"abc"#", "r####"ab"###"c"####", "r#"a"
-    RawStr { n_hashes: u8, err: Option<RawStrError> },
-    /// "br"abc"", "br#"abc"#", "br####"ab"###"c"####", "br#"a"
-    RawByteStr { n_hashes: u8, err: Option<RawStrError> },
+    /// "r"abc"", "r#"abc"#", "r####"ab"###"c"####", "r#"a". `None` indicates
+    /// an invalid literal.
+    RawStr { n_hashes: Option<u8> },
+    /// "br"abc"", "br#"abc"#", "br####"ab"###"c"####", "br#"a". `None`
+    /// indicates an invalid literal.
+    RawByteStr { n_hashes: Option<u8> },
 }
 
-/// Error produced validating a raw string. Represents cases like:
-/// - `r##~"abcde"##`: `InvalidStarter`
-/// - `r###"abcde"##`: `NoTerminator { expected: 3, found: 2, possible_terminator_offset: Some(11)`
-/// - Too many `#`s (>255): `TooManyDelimiters`
-// perf note: It doesn't matter that this makes `Token` 36 bytes bigger. See #77629
 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
 pub enum RawStrError {
-    /// Non `#` characters exist between `r` and `"` eg. `r#~"..`
+    /// Non `#` characters exist between `r` and `"`, e.g. `r##~"abcde"##`
     InvalidStarter { bad_char: char },
-    /// The string was never terminated. `possible_terminator_offset` is the number of characters after `r` or `br` where they
-    /// may have intended to terminate it.
-    NoTerminator { expected: usize, found: usize, possible_terminator_offset: Option<usize> },
+    /// The string was not terminated, e.g. `r###"abcde"##`.
+    /// `possible_terminator_offset` is the number of characters after `r` or
+    /// `br` where they may have intended to terminate it.
+    NoTerminator { expected: u32, found: u32, possible_terminator_offset: Option<u32> },
     /// More than 255 `#`s exist.
-    TooManyDelimiters { found: usize },
+    TooManyDelimiters { found: u32 },
 }
 
 /// Base of numeric literal encoding according to its prefix.
@@ -221,11 +218,25 @@ pub fn strip_shebang(input: &str) -> Option<usize> {
 }
 
 /// Parses the first token from the provided input string.
+#[inline]
 pub fn first_token(input: &str) -> Token {
     debug_assert!(!input.is_empty());
     Cursor::new(input).advance_token()
 }
 
+/// Validates a raw string literal. Used for getting more information about a
+/// problem with a `RawStr`/`RawByteStr` with a `None` field.
+#[inline]
+pub fn validate_raw_str(input: &str, prefix_len: u32) -> Result<(), RawStrError> {
+    debug_assert!(!input.is_empty());
+    let mut cursor = Cursor::new(input);
+    // Move past the leading `r` or `br`.
+    for _ in 0..prefix_len {
+        cursor.bump().unwrap();
+    }
+    cursor.raw_double_quoted_string(prefix_len).map(|_| ())
+}
+
 /// Creates an iterator that produces tokens from the input string.
 pub fn tokenize(input: &str) -> impl Iterator<Item = Token> + '_ {
     let mut cursor = Cursor::new(input);
@@ -315,12 +326,12 @@ fn advance_token(&mut self) -> Token {
             'r' => match (self.first(), self.second()) {
                 ('#', c1) if is_id_start(c1) => self.raw_ident(),
                 ('#', _) | ('"', _) => {
-                    let (n_hashes, err) = self.raw_double_quoted_string(1);
+                    let res = self.raw_double_quoted_string(1);
                     let suffix_start = self.len_consumed();
-                    if err.is_none() {
+                    if res.is_ok() {
                         self.eat_literal_suffix();
                     }
-                    let kind = RawStr { n_hashes, err };
+                    let kind = RawStr { n_hashes: res.ok() };
                     Literal { kind, suffix_start }
                 }
                 _ => self.ident_or_unknown_prefix(),
@@ -350,12 +361,12 @@ fn advance_token(&mut self) -> Token {
                 }
                 ('r', '"') | ('r', '#') => {
                     self.bump();
-                    let (n_hashes, err) = self.raw_double_quoted_string(2);
+                    let res = self.raw_double_quoted_string(2);
                     let suffix_start = self.len_consumed();
-                    if err.is_none() {
+                    if res.is_ok() {
                         self.eat_literal_suffix();
                     }
-                    let kind = RawByteStr { n_hashes, err };
+                    let kind = RawByteStr { n_hashes: res.ok() };
                     Literal { kind, suffix_start }
                 }
                 _ => self.ident_or_unknown_prefix(),
@@ -698,19 +709,18 @@ fn double_quoted_string(&mut self) -> bool {
     }
 
     /// Eats the double-quoted string and returns `n_hashes` and an error if encountered.
-    fn raw_double_quoted_string(&mut self, prefix_len: usize) -> (u8, Option<RawStrError>) {
+    fn raw_double_quoted_string(&mut self, prefix_len: u32) -> Result<u8, RawStrError> {
         // Wrap the actual function to handle the error with too many hashes.
         // This way, it eats the whole raw string.
-        let (n_hashes, err) = self.raw_string_unvalidated(prefix_len);
+        let n_hashes = self.raw_string_unvalidated(prefix_len)?;
         // Only up to 255 `#`s are allowed in raw strings
         match u8::try_from(n_hashes) {
-            Ok(num) => (num, err),
-            // We lie about the number of hashes here :P
-            Err(_) => (0, Some(RawStrError::TooManyDelimiters { found: n_hashes })),
+            Ok(num) => Ok(num),
+            Err(_) => Err(RawStrError::TooManyDelimiters { found: n_hashes }),
         }
     }
 
-    fn raw_string_unvalidated(&mut self, prefix_len: usize) -> (usize, Option<RawStrError>) {
+    fn raw_string_unvalidated(&mut self, prefix_len: u32) -> Result<u32, RawStrError> {
         debug_assert!(self.prev() == 'r');
         let start_pos = self.len_consumed();
         let mut possible_terminator_offset = None;
@@ -729,7 +739,7 @@ fn raw_string_unvalidated(&mut self, prefix_len: usize) -> (usize, Option<RawStr
             Some('"') => (),
             c => {
                 let c = c.unwrap_or(EOF_CHAR);
-                return (n_start_hashes, Some(RawStrError::InvalidStarter { bad_char: c }));
+                return Err(RawStrError::InvalidStarter { bad_char: c });
             }
         }
 
@@ -739,14 +749,11 @@ fn raw_string_unvalidated(&mut self, prefix_len: usize) -> (usize, Option<RawStr
             self.eat_while(|c| c != '"');
 
             if self.is_eof() {
-                return (
-                    n_start_hashes,
-                    Some(RawStrError::NoTerminator {
-                        expected: n_start_hashes,
-                        found: max_hashes,
-                        possible_terminator_offset,
-                    }),
-                );
+                return Err(RawStrError::NoTerminator {
+                    expected: n_start_hashes,
+                    found: max_hashes,
+                    possible_terminator_offset,
+                });
             }
 
             // Eat closing double quote.
@@ -764,7 +771,7 @@ fn raw_string_unvalidated(&mut self, prefix_len: usize) -> (usize, Option<RawStr
             }
 
             if n_end_hashes == n_start_hashes {
-                return (n_start_hashes, None);
+                return Ok(n_start_hashes);
             } else if n_end_hashes > max_hashes {
                 // Keep track of possible terminators to give a hint about
                 // where there might be a missing terminator
index 07daee06f0f860d911db92bf847e686960bab832..e4c1787f2ccef043e002d228346c72b8a2958655 100644 (file)
@@ -2,42 +2,39 @@
 
 use expect_test::{expect, Expect};
 
-fn check_raw_str(s: &str, expected_hashes: u8, expected_err: Option<RawStrError>) {
+fn check_raw_str(s: &str, expected: Result<u8, RawStrError>) {
     let s = &format!("r{}", s);
     let mut cursor = Cursor::new(s);
     cursor.bump();
-    let (n_hashes, err) = cursor.raw_double_quoted_string(0);
-    assert_eq!(n_hashes, expected_hashes);
-    assert_eq!(err, expected_err);
+    let res = cursor.raw_double_quoted_string(0);
+    assert_eq!(res, expected);
 }
 
 #[test]
 fn test_naked_raw_str() {
-    check_raw_str(r#""abc""#, 0, None);
+    check_raw_str(r#""abc""#, Ok(0));
 }
 
 #[test]
 fn test_raw_no_start() {
-    check_raw_str(r##""abc"#"##, 0, None);
+    check_raw_str(r##""abc"#"##, Ok(0));
 }
 
 #[test]
 fn test_too_many_terminators() {
     // this error is handled in the parser later
-    check_raw_str(r###"#"abc"##"###, 1, None);
+    check_raw_str(r###"#"abc"##"###, Ok(1));
 }
 
 #[test]
 fn test_unterminated() {
     check_raw_str(
         r#"#"abc"#,
-        1,
-        Some(RawStrError::NoTerminator { expected: 1, found: 0, possible_terminator_offset: None }),
+        Err(RawStrError::NoTerminator { expected: 1, found: 0, possible_terminator_offset: None }),
     );
     check_raw_str(
         r###"##"abc"#"###,
-        2,
-        Some(RawStrError::NoTerminator {
+        Err(RawStrError::NoTerminator {
             expected: 2,
             found: 1,
             possible_terminator_offset: Some(7),
@@ -46,14 +43,13 @@ fn test_unterminated() {
     // We're looking for "# not just any #
     check_raw_str(
         r###"##"abc#"###,
-        2,
-        Some(RawStrError::NoTerminator { expected: 2, found: 0, possible_terminator_offset: None }),
+        Err(RawStrError::NoTerminator { expected: 2, found: 0, possible_terminator_offset: None }),
     )
 }
 
 #[test]
 fn test_invalid_start() {
-    check_raw_str(r##"#~"abc"#"##, 1, Some(RawStrError::InvalidStarter { bad_char: '~' }));
+    check_raw_str(r##"#~"abc"#"##, Err(RawStrError::InvalidStarter { bad_char: '~' }));
 }
 
 #[test]
@@ -61,26 +57,24 @@ fn test_unterminated_no_pound() {
     // https://github.com/rust-lang/rust/issues/70677
     check_raw_str(
         r#"""#,
-        0,
-        Some(RawStrError::NoTerminator { expected: 0, found: 0, possible_terminator_offset: None }),
+        Err(RawStrError::NoTerminator { expected: 0, found: 0, possible_terminator_offset: None }),
     );
 }
 
 #[test]
 fn test_too_many_hashes() {
     let max_count = u8::MAX;
-    let mut hashes: String = "#".repeat(max_count.into());
+    let hashes1 = "#".repeat(max_count as usize);
+    let hashes2 = "#".repeat(max_count as usize + 1);
+    let middle = "\"abc\"";
+    let s1 = [&hashes1, middle, &hashes1].join("");
+    let s2 = [&hashes2, middle, &hashes2].join("");
 
-    // Valid number of hashes (255 = 2^8 - 1 = u8::MAX), but invalid string.
-    check_raw_str(&hashes, max_count, Some(RawStrError::InvalidStarter { bad_char: '\u{0}' }));
+    // Valid number of hashes (255 = 2^8 - 1 = u8::MAX).
+    check_raw_str(&s1, Ok(255));
 
     // One more hash sign (256 = 2^8) becomes too many.
-    hashes.push('#');
-    check_raw_str(
-        &hashes,
-        0,
-        Some(RawStrError::TooManyDelimiters { found: usize::from(max_count) + 1 }),
-    );
+    check_raw_str(&s2, Err(RawStrError::TooManyDelimiters { found: u32::from(max_count) + 1 }));
 }
 
 #[test]
@@ -251,7 +245,7 @@ fn raw_string() {
     check_lexing(
         "r###\"\"#a\\b\x00c\"\"###",
         expect![[r#"
-            Token { kind: Literal { kind: RawStr { n_hashes: 3, err: None }, suffix_start: 17 }, len: 17 }
+            Token { kind: Literal { kind: RawStr { n_hashes: Some(3) }, suffix_start: 17 }, len: 17 }
         "#]],
     )
 }
@@ -295,9 +289,9 @@ fn literal_suffixes() {
             Token { kind: Whitespace, len: 1 }
             Token { kind: Literal { kind: Int { base: Decimal, empty_int: false }, suffix_start: 1 }, len: 3 }
             Token { kind: Whitespace, len: 1 }
-            Token { kind: Literal { kind: RawStr { n_hashes: 3, err: None }, suffix_start: 12 }, len: 18 }
+            Token { kind: Literal { kind: RawStr { n_hashes: Some(3) }, suffix_start: 12 }, len: 18 }
             Token { kind: Whitespace, len: 1 }
-            Token { kind: Literal { kind: RawByteStr { n_hashes: 3, err: None }, suffix_start: 13 }, len: 19 }
+            Token { kind: Literal { kind: RawByteStr { n_hashes: Some(3) }, suffix_start: 13 }, len: 19 }
             Token { kind: Whitespace, len: 1 }
         "#]],
     )
index ca3e6ce4d60bfb75c12cadd61120f6f061f0ca9e..bd58021f78fc022381f5c015b474704e7369e98f 100644 (file)
@@ -1364,7 +1364,6 @@ fn perform_lint(
         cx: &LateContext<'_>,
         what: &str,
         def_id: LocalDefId,
-        span: Span,
         vis_span: Span,
         exportable: bool,
     ) {
@@ -1373,7 +1372,7 @@ fn perform_lint(
             if vis_span.from_expansion() {
                 applicability = Applicability::MaybeIncorrect;
             }
-            let def_span = cx.tcx.sess.source_map().guess_head_span(span);
+            let def_span = cx.tcx.def_span(def_id);
             cx.struct_span_lint(UNREACHABLE_PUB, def_span, |lint| {
                 let mut err = lint.build(fluent::lint::builtin_unreachable_pub);
                 err.set_arg("what", what);
@@ -1399,36 +1398,22 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
         if let hir::ItemKind::Use(_, hir::UseKind::ListStem) = &item.kind {
             return;
         }
-        self.perform_lint(cx, "item", item.def_id, item.span, item.vis_span, true);
+        self.perform_lint(cx, "item", item.def_id, item.vis_span, true);
     }
 
     fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::ForeignItem<'tcx>) {
-        self.perform_lint(
-            cx,
-            "item",
-            foreign_item.def_id,
-            foreign_item.span,
-            foreign_item.vis_span,
-            true,
-        );
+        self.perform_lint(cx, "item", foreign_item.def_id, foreign_item.vis_span, true);
     }
 
     fn check_field_def(&mut self, cx: &LateContext<'_>, field: &hir::FieldDef<'_>) {
         let def_id = cx.tcx.hir().local_def_id(field.hir_id);
-        self.perform_lint(cx, "field", def_id, field.span, field.vis_span, false);
+        self.perform_lint(cx, "field", def_id, field.vis_span, false);
     }
 
     fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
         // Only lint inherent impl items.
         if cx.tcx.associated_item(impl_item.def_id).trait_item_def_id.is_none() {
-            self.perform_lint(
-                cx,
-                "item",
-                impl_item.def_id,
-                impl_item.span,
-                impl_item.vis_span,
-                false,
-            );
+            self.perform_lint(cx, "item", impl_item.def_id, impl_item.vis_span, false);
         }
     }
 }
index 04ac50f1d48061b02b9893e21e5c5006dffb2cc4..b95fc341db656c0091b92020eb726ba7f4450bdd 100644 (file)
@@ -856,13 +856,18 @@ fn lookup_with_diagnostics(
                         Applicability::MachineApplicable,
                     );
                 },
-                BuiltinLintDiagnostics::NamedArgumentUsedPositionally(positional_arg, named_arg, name) => {
-                    db.span_label(named_arg, "this named argument is only referred to by position in formatting string");
-                    if let Some(positional_arg) = positional_arg {
-                        let msg = format!("this formatting argument uses named argument `{}` by position", name);
-                        db.span_label(positional_arg, msg);
+                BuiltinLintDiagnostics::NamedArgumentUsedPositionally{ position_sp_to_replace, position_sp_for_msg, named_arg_sp, named_arg_name, is_formatting_arg} => {
+                    db.span_label(named_arg_sp, "this named argument is referred to by position in formatting string");
+                    if let Some(positional_arg_for_msg) = position_sp_for_msg {
+                        let msg = format!("this formatting argument uses named argument `{}` by position", named_arg_name);
+                        db.span_label(positional_arg_for_msg, msg);
+                    }
+
+                    if let Some(positional_arg_to_replace) = position_sp_to_replace {
+                        let name = if is_formatting_arg { named_arg_name + "$" } else { named_arg_name };
+
                         db.span_suggestion_verbose(
-                            positional_arg,
+                            positional_arg_to_replace,
                             "use the named argument by name to avoid ambiguity",
                             name,
                             Applicability::MaybeIncorrect,
index d13711c3ab59851636b0449dfa2fd3fee538ecf8..cbf1a6775550106534f89da3f30f31dcadad279f 100644 (file)
@@ -233,9 +233,9 @@ fn visit_where_predicate(&mut self, p: &'a ast::WherePredicate) {
         ast_visit::walk_where_predicate(self, p);
     }
 
-    fn visit_poly_trait_ref(&mut self, t: &'a ast::PolyTraitRef, m: &'a ast::TraitBoundModifier) {
-        run_early_pass!(self, check_poly_trait_ref, t, m);
-        ast_visit::walk_poly_trait_ref(self, t, m);
+    fn visit_poly_trait_ref(&mut self, t: &'a ast::PolyTraitRef) {
+        run_early_pass!(self, check_poly_trait_ref, t);
+        ast_visit::walk_poly_trait_ref(self, t);
     }
 
     fn visit_assoc_item(&mut self, item: &'a ast::AssocItem, ctxt: ast_visit::AssocCtxt) {
index a329b37519d98a04ec661f9c194918b0c8614b5b..5188ac633d3928b9bcf56cc63bcab58bd76ab4da 100644 (file)
@@ -24,7 +24,6 @@
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::lint::LintPass;
-use rustc_span::symbol::Symbol;
 use rustc_span::Span;
 
 use std::any::Any;
@@ -194,14 +193,7 @@ fn visit_fn(
         self.context.cached_typeck_results.set(old_cached_typeck_results);
     }
 
-    fn visit_variant_data(
-        &mut self,
-        s: &'tcx hir::VariantData<'tcx>,
-        _: Symbol,
-        _: &'tcx hir::Generics<'tcx>,
-        _: hir::HirId,
-        _: Span,
-    ) {
+    fn visit_variant_data(&mut self, s: &'tcx hir::VariantData<'tcx>) {
         lint_callback!(self, check_struct_def, s);
         hir_visit::walk_struct_def(self, s);
     }
@@ -213,15 +205,10 @@ fn visit_field_def(&mut self, s: &'tcx hir::FieldDef<'tcx>) {
         })
     }
 
-    fn visit_variant(
-        &mut self,
-        v: &'tcx hir::Variant<'tcx>,
-        g: &'tcx hir::Generics<'tcx>,
-        item_id: hir::HirId,
-    ) {
+    fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) {
         self.with_lint_attrs(v.id, |cx| {
             lint_callback!(cx, check_variant, v);
-            hir_visit::walk_variant(cx, v, g, item_id);
+            hir_visit::walk_variant(cx, v);
         })
     }
 
index 00e96f20d1aaaec4ecd24c2349ecad72949e58da..7ab9302d835a2d57da295324c08020b11b2a2dda 100644 (file)
@@ -772,14 +772,9 @@ fn visit_field_def(&mut self, s: &'tcx hir::FieldDef<'tcx>) {
         })
     }
 
-    fn visit_variant(
-        &mut self,
-        v: &'tcx hir::Variant<'tcx>,
-        g: &'tcx hir::Generics<'tcx>,
-        item_id: hir::HirId,
-    ) {
+    fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) {
         self.with_lint_attrs(v.id, |builder| {
-            intravisit::walk_variant(builder, v, g, item_id);
+            intravisit::walk_variant(builder, v);
         })
     }
 
index 33ac2ed02aa00c0ef89c222247d89a917f08ef18..8d04d68bf1c2de3e9f0ddd5d237ddd666103654c 100644 (file)
@@ -22,8 +22,8 @@ pub fn method_context(cx: &LateContext<'_>, id: hir::HirId) -> MethodLateContext
     let def_id = cx.tcx.hir().local_def_id(id);
     let item = cx.tcx.associated_item(def_id);
     match item.container {
-        ty::TraitContainer(..) => MethodLateContext::TraitAutoImpl,
-        ty::ImplContainer(cid) => match cx.tcx.impl_trait_ref(cid) {
+        ty::TraitContainer => MethodLateContext::TraitAutoImpl,
+        ty::ImplContainer => match cx.tcx.impl_trait_ref(item.container_id(cx.tcx)) {
             Some(_) => MethodLateContext::TraitImpl,
             None => MethodLateContext::PlainImpl,
         },
index cb7bd407ed4c8670168f71f30a270de693004f9e..413f06a97a2455f8e76c7f5039ee87ea4c519c23 100644 (file)
@@ -156,8 +156,7 @@ macro_rules! early_lint_methods {
             fn check_generic_arg(a: &ast::GenericArg);
             fn check_generic_param(a: &ast::GenericParam);
             fn check_generics(a: &ast::Generics);
-            fn check_poly_trait_ref(a: &ast::PolyTraitRef,
-                                    b: &ast::TraitBoundModifier);
+            fn check_poly_trait_ref(a: &ast::PolyTraitRef);
             fn check_fn(a: rustc_ast::visit::FnKind<'_>, c: Span, d_: ast::NodeId);
             fn check_trait_item(a: &ast::AssocItem);
             fn check_impl_item(a: &ast::AssocItem);
index 53269d18527033a8fbb0eb75c0afc0a6380e61ca..58b2f0a44161c273b62d6079aebfdd70acc55e00 100644 (file)
@@ -11,7 +11,7 @@
 use rustc_middle::ty::{self, Ty};
 use rustc_span::symbol::Symbol;
 use rustc_span::symbol::{kw, sym};
-use rustc_span::{BytePos, Span, DUMMY_SP};
+use rustc_span::{BytePos, Span};
 
 declare_lint! {
     /// The `unused_must_use` lint detects unused result of a type flagged as
@@ -396,6 +396,7 @@ enum UnusedDelimsCtx {
     LetScrutineeExpr,
     ArrayLenExpr,
     AnonConst,
+    MatchArmExpr,
 }
 
 impl From<UnusedDelimsCtx> for &'static str {
@@ -414,6 +415,7 @@ fn from(ctx: UnusedDelimsCtx) -> &'static str {
             UnusedDelimsCtx::BlockRetValue => "block return value",
             UnusedDelimsCtx::LetScrutineeExpr => "`let` scrutinee expression",
             UnusedDelimsCtx::ArrayLenExpr | UnusedDelimsCtx::AnonConst => "const expression",
+            UnusedDelimsCtx::MatchArmExpr => "match arm expression",
         }
     }
 }
@@ -502,23 +504,23 @@ fn emit_unused_delims_expr(
             ast::ExprKind::Block(ref block, None) if block.stmts.len() > 0 => {
                 let start = block.stmts[0].span;
                 let end = block.stmts[block.stmts.len() - 1].span;
-                if value.span.from_expansion() || start.from_expansion() || end.from_expansion() {
-                    (
-                        value.span.with_hi(value.span.lo() + BytePos(1)),
-                        value.span.with_lo(value.span.hi() - BytePos(1)),
-                    )
+                if let Some(start) = start.find_ancestor_inside(value.span)
+                    && let Some(end) = end.find_ancestor_inside(value.span)
+                {
+                    Some((
+                        value.span.with_hi(start.lo()),
+                        value.span.with_lo(end.hi()),
+                    ))
                 } else {
-                    (value.span.with_hi(start.lo()), value.span.with_lo(end.hi()))
+                    None
                 }
             }
             ast::ExprKind::Paren(ref expr) => {
-                if value.span.from_expansion() || expr.span.from_expansion() {
-                    (
-                        value.span.with_hi(value.span.lo() + BytePos(1)),
-                        value.span.with_lo(value.span.hi() - BytePos(1)),
-                    )
+                let expr_span = expr.span.find_ancestor_inside(value.span);
+                if let Some(expr_span) = expr_span {
+                    Some((value.span.with_hi(expr_span.lo()), value.span.with_lo(expr_span.hi())))
                 } else {
-                    (value.span.with_hi(expr.span.lo()), value.span.with_lo(expr.span.hi()))
+                    None
                 }
             }
             _ => return,
@@ -527,36 +529,38 @@ fn emit_unused_delims_expr(
             left_pos.map_or(false, |s| s >= value.span.lo()),
             right_pos.map_or(false, |s| s <= value.span.hi()),
         );
-        self.emit_unused_delims(cx, spans, ctx.into(), keep_space);
+        self.emit_unused_delims(cx, value.span, spans, ctx.into(), keep_space);
     }
 
     fn emit_unused_delims(
         &self,
         cx: &EarlyContext<'_>,
-        spans: (Span, Span),
+        value_span: Span,
+        spans: Option<(Span, Span)>,
         msg: &str,
         keep_space: (bool, bool),
     ) {
-        // FIXME(flip1995): Quick and dirty fix for #70814. This should be fixed in rustdoc
-        // properly.
-        if spans.0 == DUMMY_SP || spans.1 == DUMMY_SP {
-            return;
-        }
-
-        cx.struct_span_lint(self.lint(), MultiSpan::from(vec![spans.0, spans.1]), |lint| {
-            let replacement = vec![
-                (spans.0, if keep_space.0 { " ".into() } else { "".into() }),
-                (spans.1, if keep_space.1 { " ".into() } else { "".into() }),
-            ];
-            lint.build(fluent::lint::unused_delim)
-                .set_arg("delim", Self::DELIM_STR)
-                .set_arg("item", msg)
-                .multipart_suggestion(
+        let primary_span = if let Some((lo, hi)) = spans {
+            MultiSpan::from(vec![lo, hi])
+        } else {
+            MultiSpan::from(value_span)
+        };
+        cx.struct_span_lint(self.lint(), primary_span, |lint| {
+            let mut db = lint.build(fluent::lint::unused_delim);
+            db.set_arg("delim", Self::DELIM_STR);
+            db.set_arg("item", msg);
+            if let Some((lo, hi)) = spans {
+                let replacement = vec![
+                    (lo, if keep_space.0 { " ".into() } else { "".into() }),
+                    (hi, if keep_space.1 { " ".into() } else { "".into() }),
+                ];
+                db.multipart_suggestion(
                     fluent::lint::suggestion,
                     replacement,
                     Applicability::MachineApplicable,
-                )
-                .emit();
+                );
+            }
+            db.emit();
         });
     }
 
@@ -604,8 +608,7 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
             ref call_or_other => {
                 let (args_to_check, ctx) = match *call_or_other {
                     Call(_, ref args) => (&args[..], UnusedDelimsCtx::FunctionArg),
-                    // first "argument" is self (which sometimes needs delims)
-                    MethodCall(_, ref args, _) => (&args[1..], UnusedDelimsCtx::MethodArg),
+                    MethodCall(_, _, ref args, _) => (&args[..], UnusedDelimsCtx::MethodArg),
                     // actual catch-all arm
                     _ => {
                         return;
@@ -764,15 +767,12 @@ fn check_unused_parens_pat(
                 // Otherwise proceed with linting.
                 _ => {}
             }
-            let spans = if value.span.from_expansion() || inner.span.from_expansion() {
-                (
-                    value.span.with_hi(value.span.lo() + BytePos(1)),
-                    value.span.with_lo(value.span.hi() - BytePos(1)),
-                )
+            let spans = if let Some(inner) = inner.span.find_ancestor_inside(value.span) {
+                Some((value.span.with_hi(inner.lo()), value.span.with_lo(inner.hi())))
             } else {
-                (value.span.with_hi(inner.span.lo()), value.span.with_lo(inner.span.hi()))
+                None
             };
-            self.emit_unused_delims(cx, spans, "pattern", (false, false));
+            self.emit_unused_delims(cx, value.span, spans, "pattern", (false, false));
         }
     }
 }
@@ -805,6 +805,18 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
                 }
                 return;
             }
+            ExprKind::Match(ref _expr, ref arm) => {
+                for a in arm {
+                    self.check_unused_delims_expr(
+                        cx,
+                        &a.body,
+                        UnusedDelimsCtx::MatchArmExpr,
+                        false,
+                        None,
+                        None,
+                    );
+                }
+            }
             _ => {}
         }
 
@@ -865,15 +877,12 @@ fn check_ty(&mut self, cx: &EarlyContext<'_>, ty: &ast::Ty) {
                     );
                 }
                 _ => {
-                    let spans = if ty.span.from_expansion() || r.span.from_expansion() {
-                        (
-                            ty.span.with_hi(ty.span.lo() + BytePos(1)),
-                            ty.span.with_lo(ty.span.hi() - BytePos(1)),
-                        )
+                    let spans = if let Some(r) = r.span.find_ancestor_inside(ty.span) {
+                        Some((ty.span.with_hi(r.lo()), ty.span.with_lo(r.hi())))
                     } else {
-                        (ty.span.with_hi(r.span.lo()), ty.span.with_lo(r.span.hi()))
+                        None
                     };
-                    self.emit_unused_delims(cx, spans, "type", (false, false));
+                    self.emit_unused_delims(cx, ty.span, spans, "type", (false, false));
                 }
             }
         }
index 39690851d1ea831589a35723a5db416b1ec5da7c..f00165cd3b370c2637906c6023ffec452bb04be8 100644 (file)
     "detects attributes that were not used by the compiler"
 }
 
+declare_lint! {
+    /// The `unused_tuple_struct_fields` lint detects fields of tuple structs
+    /// that are never read.
+    ///
+    /// ### Example
+    ///
+    /// ```
+    /// #[warn(unused_tuple_struct_fields)]
+    /// struct S(i32, i32, i32);
+    /// let s = S(1, 2, 3);
+    /// let _ = (s.0, s.2);
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Tuple struct fields that are never read anywhere may indicate a
+    /// mistake or unfinished code. To silence this warning, consider
+    /// removing the unused field(s) or, to preserve the numbering of the
+    /// remaining fields, change the unused field(s) to have unit type.
+    pub UNUSED_TUPLE_STRUCT_FIELDS,
+    Allow,
+    "detects tuple struct fields that are never read"
+}
+
 declare_lint! {
     /// The `unreachable_code` lint detects unreachable code paths.
     ///
         UNSUPPORTED_CALLING_CONVENTIONS,
         BREAK_WITH_LABEL_AND_LOOP,
         UNUSED_ATTRIBUTES,
+        UNUSED_TUPLE_STRUCT_FIELDS,
         NON_EXHAUSTIVE_OMITTED_PATTERNS,
         TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
         DEREF_INTO_DYN_SUPERTRAIT,
index 4fd57ed8533795502ec2a652822b6d0939a92a14..6acbe97a7a118d13093351c045ccd54a90f41ac5 100644 (file)
@@ -467,7 +467,19 @@ pub enum BuiltinLintDiagnostics {
         /// If true, the lifetime will be fully elided.
         use_span: Option<(Span, bool)>,
     },
-    NamedArgumentUsedPositionally(Option<Span>, Span, String),
+    NamedArgumentUsedPositionally {
+        /// Span where the named argument is used by position and will be replaced with the named
+        /// argument name
+        position_sp_to_replace: Option<Span>,
+        /// Span where the named argument is used by position and is used for lint messages
+        position_sp_for_msg: Option<Span>,
+        /// Span where the named argument's name is (so we know where to put the warning message)
+        named_arg_sp: Span,
+        /// String containing the named arguments name
+        named_arg_name: String,
+        /// Indicates if the named argument is used as a width/precision for formatting
+        is_formatting_arg: bool,
+    },
 }
 
 /// Lints that are buffered up early on in the `Session` before the
index 62ef5804dce6d7491f1a8c79620d4986114ed745..abb68f3afe5274ec06f362c2e25e506326542b78 100644 (file)
@@ -242,6 +242,13 @@ fn main() {
         println!("cargo:rustc-link-lib=uuid");
     } else if target.contains("netbsd") || target.contains("haiku") || target.contains("darwin") {
         println!("cargo:rustc-link-lib=z");
+    } else if target.starts_with("arm")
+        || target.starts_with("mips-")
+        || target.starts_with("mipsel-")
+        || target.starts_with("powerpc-")
+    {
+        // 32-bit targets need to link libatomic.
+        println!("cargo:rustc-link-lib=atomic");
     }
     cmd.args(&components);
 
index c333738ded4582f6fe35854ddc68ee43238e16b3..5f5b5de790e430e4e2823c491c0536325638c793 100644 (file)
@@ -1311,10 +1311,15 @@ extern "C" LLVMTypeKind LLVMRustGetTypeKind(LLVMTypeRef Ty) {
     return LLVMBFloatTypeKind;
   case Type::X86_AMXTyID:
     return LLVMX86_AMXTypeKind;
-#if LLVM_VERSION_GE(15, 0)
+#if LLVM_VERSION_GE(15, 0) && LLVM_VERSION_LT(16, 0)
   case Type::DXILPointerTyID:
     report_fatal_error("Rust does not support DirectX typed pointers.");
     break;
+#endif
+#if LLVM_VERSION_GE(16, 0)
+  case Type::TypedPointerTyID:
+    report_fatal_error("Rust does not support typed pointers.");
+    break;
 #endif
   }
   report_fatal_error("Unhandled TypeID.");
index 25b3aadc1c527c6e241a4e3a91f6067f7fcfc247..547c8debb505db657a21b4a4ff323d42c0ff37e9 100644 (file)
@@ -7,7 +7,7 @@ edition = "2021"
 proc-macro = true
 
 [dependencies]
-annotate-snippets = "0.8.0"
+annotate-snippets = "0.9"
 fluent-bundle = "0.15.2"
 fluent-syntax = "0.11"
 synstructure = "0.12.1"
index c33219e4700501eb326dfabfe7838414de4f259c..c5e39507d7e4d806ae1a3fd50ab7aa35b10b5351 100644 (file)
@@ -328,7 +328,31 @@ fn process_item(&mut self, id: rustc_hir::ItemId) {
                         .map(|child_item| self.build_dll_import(abi, child_item))
                         .collect()
                 }
-                _ => Vec::new(),
+                _ => {
+                    for child_item in foreign_mod_items {
+                        if self.tcx.def_kind(child_item.id.def_id).has_codegen_attrs()
+                            && self
+                                .tcx
+                                .codegen_fn_attrs(child_item.id.def_id)
+                                .link_ordinal
+                                .is_some()
+                        {
+                            let link_ordinal_attr = self
+                                .tcx
+                                .hir()
+                                .attrs(self.tcx.hir().local_def_id_to_hir_id(child_item.id.def_id))
+                                .iter()
+                                .find(|a| a.has_name(sym::link_ordinal))
+                                .unwrap();
+                            sess.span_err(
+                                link_ordinal_attr.span,
+                                "`#[link_ordinal]` is only supported if link kind is `raw-dylib`",
+                            );
+                        }
+                    }
+
+                    Vec::new()
+                }
             };
             self.libs.push(NativeLib {
                 name: name.map(|(name, _)| name),
@@ -472,7 +496,9 @@ fn build_dll_import(&self, abi: Abi, item: &hir::ForeignItemRef) -> DllImport {
                 Abi::Fastcall { .. } => {
                     DllCallingConvention::Fastcall(self.i686_arg_list_size(item))
                 }
-                // Vectorcall is intentionally not supported at this time.
+                Abi::Vectorcall { .. } => {
+                    DllCallingConvention::Vectorcall(self.i686_arg_list_size(item))
+                }
                 _ => {
                     self.tcx.sess.span_fatal(
                         item.span,
index 6b0b5ac7da9a18d2d5d0611c9652ef16b9601a02..40dc4fb052d9652767243e185465767954979847 100644 (file)
@@ -1114,7 +1114,7 @@ fn module_expansion(self, id: DefIndex, sess: &Session) -> ExpnId {
 
     fn get_fn_has_self_parameter(self, id: DefIndex) -> bool {
         match self.kind(id) {
-            EntryKind::AssocFn(data) => data.decode(self).has_self,
+            EntryKind::AssocFn { has_self, .. } => has_self,
             _ => false,
         }
     }
@@ -1134,28 +1134,21 @@ fn get_associated_item_def_ids(
     }
 
     fn get_associated_item(self, id: DefIndex) -> ty::AssocItem {
-        let def_key = self.def_key(id);
-        let parent = self.local_def_id(def_key.parent.unwrap());
         let name = self.item_name(id);
 
         let (kind, container, has_self) = match self.kind(id) {
             EntryKind::AssocConst(container) => (ty::AssocKind::Const, container, false),
-            EntryKind::AssocFn(data) => {
-                let data = data.decode(self);
-                (ty::AssocKind::Fn, data.container, data.has_self)
-            }
+            EntryKind::AssocFn { container, has_self } => (ty::AssocKind::Fn, container, has_self),
             EntryKind::AssocType(container) => (ty::AssocKind::Type, container, false),
-            _ => bug!("cannot get associated-item of `{:?}`", def_key),
+            _ => bug!("cannot get associated-item of `{:?}`", id),
         };
 
         ty::AssocItem {
             name,
             kind,
-            vis: self.get_visibility(id),
-            defaultness: container.defaultness(),
             def_id: self.local_def_id(id),
             trait_item_def_id: self.get_trait_item_def_id(id),
-            container: container.with_def_id(parent),
+            container,
             fn_has_self_parameter: has_self,
         }
     }
@@ -1310,19 +1303,6 @@ fn get_implementations_of_trait(
         }
     }
 
-    fn get_trait_of_item(self, id: DefIndex) -> Option<DefId> {
-        let def_key = self.def_key(id);
-        match def_key.disambiguated_data.data {
-            DefPathData::TypeNs(..) | DefPathData::ValueNs(..) => (),
-            // Not an associated item
-            _ => return None,
-        }
-        def_key.parent.and_then(|parent_index| match self.kind(parent_index) {
-            EntryKind::Trait | EntryKind::TraitAlias => Some(self.local_def_id(parent_index)),
-            _ => None,
-        })
-    }
-
     fn get_native_libraries(self, sess: &'a Session) -> impl Iterator<Item = NativeLib> + 'a {
         self.root.native_libraries.decode((self, sess))
     }
index 6bf237b8ed5dfc5482e3fa76b1408b050768980b..61f16be1d6b24016c21c851a9dad358bd69cb72f 100644 (file)
@@ -207,6 +207,7 @@ fn into_args(self) -> (DefId, SimplifiedType) {
     def_ident_span => { table }
     lookup_stability => { table }
     lookup_const_stability => { table }
+    lookup_default_body_stability => { table }
     lookup_deprecation_entry => { table }
     visibility => { table }
     unused_generic_params => { table }
@@ -235,7 +236,6 @@ fn into_args(self) -> (DefId, SimplifiedType) {
     inherent_impls => { cdata.get_inherent_implementations_for_type(tcx, def_id.index) }
     is_foreign_item => { cdata.is_foreign_item(def_id.index) }
     item_attrs => { tcx.arena.alloc_from_iter(cdata.get_item_attrs(def_id.index, tcx.sess)) }
-    trait_of_item => { cdata.get_trait_of_item(def_id.index) }
     is_mir_available => { cdata.is_item_mir_available(def_id.index) }
     is_ctfe_mir_available => { cdata.is_ctfe_mir_available(def_id.index) }
 
index f0886036899a2f4cd8797f65799013f57288ebe2..f68005c0526350192a1d19c4a9e3d27c5df9ab3c 100644 (file)
@@ -1029,6 +1029,7 @@ fn encode_def_ids(&mut self) {
             if should_encode_stability(def_kind) {
                 self.encode_stability(def_id);
                 self.encode_const_stability(def_id);
+                self.encode_default_body_stability(def_id);
                 self.encode_deprecation(def_id);
             }
             if should_encode_variances(def_kind) {
@@ -1212,14 +1213,9 @@ fn encode_info_for_trait_item(&mut self, def_id: DefId) {
         let tcx = self.tcx;
 
         let ast_item = tcx.hir().expect_trait_item(def_id.expect_local());
+        self.tables.impl_defaultness.set(def_id.index, ast_item.defaultness);
         let trait_item = tcx.associated_item(def_id);
 
-        let container = match trait_item.defaultness {
-            hir::Defaultness::Default { has_value: true } => AssocContainer::TraitWithDefault,
-            hir::Defaultness::Default { has_value: false } => AssocContainer::TraitRequired,
-            hir::Defaultness::Final => span_bug!(ast_item.span, "traits cannot have final items"),
-        };
-
         match trait_item.kind {
             ty::AssocKind::Const => {
                 let rendered = rustc_hir_pretty::to_string(
@@ -1227,7 +1223,7 @@ fn encode_info_for_trait_item(&mut self, def_id: DefId) {
                     |s| s.print_trait_item(ast_item),
                 );
 
-                record!(self.tables.kind[def_id] <- EntryKind::AssocConst(container));
+                record!(self.tables.kind[def_id] <- EntryKind::AssocConst(ty::AssocItemContainer::TraitContainer));
                 record!(self.tables.mir_const_qualif[def_id] <- mir::ConstQualifs::default());
                 record!(self.tables.rendered_const[def_id] <- rendered);
             }
@@ -1243,14 +1239,14 @@ fn encode_info_for_trait_item(&mut self, def_id: DefId) {
                 };
                 self.tables.asyncness.set(def_id.index, m_sig.header.asyncness);
                 self.tables.constness.set(def_id.index, hir::Constness::NotConst);
-                record!(self.tables.kind[def_id] <- EntryKind::AssocFn(self.lazy(AssocFnData {
-                    container,
+                record!(self.tables.kind[def_id] <- EntryKind::AssocFn {
+                    container: ty::AssocItemContainer::TraitContainer,
                     has_self: trait_item.fn_has_self_parameter,
-                })));
+                });
             }
             ty::AssocKind::Type => {
                 self.encode_explicit_item_bounds(def_id);
-                record!(self.tables.kind[def_id] <- EntryKind::AssocType(container));
+                record!(self.tables.kind[def_id] <- EntryKind::AssocType(ty::AssocItemContainer::TraitContainer));
             }
         }
         match trait_item.kind {
@@ -1258,7 +1254,7 @@ fn encode_info_for_trait_item(&mut self, def_id: DefId) {
                 self.encode_item_type(def_id);
             }
             ty::AssocKind::Type => {
-                if trait_item.defaultness.has_value() {
+                if ast_item.defaultness.has_value() {
                     self.encode_item_type(def_id);
                 }
             }
@@ -1273,23 +1269,16 @@ fn encode_info_for_impl_item(&mut self, def_id: DefId) {
         let tcx = self.tcx;
 
         let ast_item = self.tcx.hir().expect_impl_item(def_id.expect_local());
+        self.tables.impl_defaultness.set(def_id.index, ast_item.defaultness);
         let impl_item = self.tcx.associated_item(def_id);
 
-        let container = match impl_item.defaultness {
-            hir::Defaultness::Default { has_value: true } => AssocContainer::ImplDefault,
-            hir::Defaultness::Final => AssocContainer::ImplFinal,
-            hir::Defaultness::Default { has_value: false } => {
-                span_bug!(ast_item.span, "impl items always have values (currently)")
-            }
-        };
-
         match impl_item.kind {
             ty::AssocKind::Const => {
                 if let hir::ImplItemKind::Const(_, body_id) = ast_item.kind {
                     let qualifs = self.tcx.at(ast_item.span).mir_const_qualif(def_id);
                     let const_data = self.encode_rendered_const_for_body(body_id);
 
-                    record!(self.tables.kind[def_id] <- EntryKind::AssocConst(container));
+                    record!(self.tables.kind[def_id] <- EntryKind::AssocConst(ty::AssocItemContainer::ImplContainer));
                     record!(self.tables.mir_const_qualif[def_id] <- qualifs);
                     record!(self.tables.rendered_const[def_id] <- const_data);
                 } else {
@@ -1307,13 +1296,13 @@ fn encode_info_for_impl_item(&mut self, def_id: DefId) {
                     hir::Constness::NotConst
                 };
                 self.tables.constness.set(def_id.index, constness);
-                record!(self.tables.kind[def_id] <- EntryKind::AssocFn(self.lazy(AssocFnData {
-                    container,
+                record!(self.tables.kind[def_id] <- EntryKind::AssocFn {
+                    container: ty::AssocItemContainer::ImplContainer,
                     has_self: impl_item.fn_has_self_parameter,
-                })));
+                });
             }
             ty::AssocKind::Type => {
-                record!(self.tables.kind[def_id] <- EntryKind::AssocType(container));
+                record!(self.tables.kind[def_id] <- EntryKind::AssocType(ty::AssocItemContainer::ImplContainer));
             }
         }
         self.encode_item_type(def_id);
@@ -1397,6 +1386,18 @@ fn encode_const_stability(&mut self, def_id: DefId) {
         }
     }
 
+    fn encode_default_body_stability(&mut self, def_id: DefId) {
+        debug!("EncodeContext::encode_default_body_stability({:?})", def_id);
+
+        // The query lookup can take a measurable amount of time in crates with many items. Check if
+        // the stability attributes are even enabled before using their queries.
+        if self.feat.staged_api || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked {
+            if let Some(stab) = self.tcx.lookup_default_body_stability(def_id) {
+                record!(self.tables.lookup_default_body_stability[def_id] <- stab)
+            }
+        }
+    }
+
     fn encode_deprecation(&mut self, def_id: DefId) {
         debug!("EncodeContext::encode_deprecation({:?})", def_id);
         if let Some(depr) = self.tcx.lookup_deprecation(def_id) {
index 23198a8536933ef5e0a08213752b55669ec75174..8efe5051b01cb928031bcffde1ed85dfb2667508 100644 (file)
@@ -343,6 +343,7 @@ fn encode(&self, buf: &mut FileEncoder) -> LazyTables {
     def_ident_span: Table<DefIndex, LazyValue<Span>>,
     lookup_stability: Table<DefIndex, LazyValue<attr::Stability>>,
     lookup_const_stability: Table<DefIndex, LazyValue<attr::ConstStability>>,
+    lookup_default_body_stability: Table<DefIndex, LazyValue<attr::DefaultBodyStability>>,
     lookup_deprecation_entry: Table<DefIndex, LazyValue<attr::Deprecation>>,
     // As an optimization, a missing entry indicates an empty `&[]`.
     explicit_item_bounds: Table<DefIndex, LazyArray<(ty::Predicate<'static>, Span)>>,
@@ -419,9 +420,9 @@ enum EntryKind {
     Generator,
     Trait,
     Impl,
-    AssocFn(LazyValue<AssocFnData>),
-    AssocType(AssocContainer),
-    AssocConst(AssocContainer),
+    AssocFn { container: ty::AssocItemContainer, has_self: bool },
+    AssocType(ty::AssocItemContainer),
+    AssocConst(ty::AssocItemContainer),
     TraitAlias,
 }
 
@@ -434,47 +435,6 @@ struct VariantData {
     is_non_exhaustive: bool,
 }
 
-/// Describes whether the container of an associated item
-/// is a trait or an impl and whether, in a trait, it has
-/// a default, or an in impl, whether it's marked "default".
-#[derive(Copy, Clone, TyEncodable, TyDecodable)]
-enum AssocContainer {
-    TraitRequired,
-    TraitWithDefault,
-    ImplDefault,
-    ImplFinal,
-}
-
-impl AssocContainer {
-    fn with_def_id(&self, def_id: DefId) -> ty::AssocItemContainer {
-        match *self {
-            AssocContainer::TraitRequired | AssocContainer::TraitWithDefault => {
-                ty::TraitContainer(def_id)
-            }
-
-            AssocContainer::ImplDefault | AssocContainer::ImplFinal => ty::ImplContainer(def_id),
-        }
-    }
-
-    fn defaultness(&self) -> hir::Defaultness {
-        match *self {
-            AssocContainer::TraitRequired => hir::Defaultness::Default { has_value: false },
-
-            AssocContainer::TraitWithDefault | AssocContainer::ImplDefault => {
-                hir::Defaultness::Default { has_value: true }
-            }
-
-            AssocContainer::ImplFinal => hir::Defaultness::Final,
-        }
-    }
-}
-
-#[derive(MetadataEncodable, MetadataDecodable)]
-struct AssocFnData {
-    container: AssocContainer,
-    has_self: bool,
-}
-
 #[derive(TyEncodable, TyDecodable)]
 struct GeneratorData<'tcx> {
     layout: mir::GeneratorLayout<'tcx>,
@@ -492,7 +452,6 @@ pub fn provide(providers: &mut Providers) {
 
 trivially_parameterized_over_tcx! {
     VariantData,
-    AssocFnData,
     EntryKind,
     RawDefId,
     TraitImpls,
index c6fe3e721032f4e7957adc198d282ceaac78d40c..200de9079c2188b95b8796917d14c05250547065 100644 (file)
@@ -105,7 +105,7 @@ pub fn is_existential(&self) -> bool {
             CanonicalVarKind::Region(_) => true,
             CanonicalVarKind::PlaceholderRegion(..) => false,
             CanonicalVarKind::Const(..) => true,
-            CanonicalVarKind::PlaceholderConst(_) => false,
+            CanonicalVarKind::PlaceholderConst(_, _) => false,
         }
     }
 }
@@ -133,7 +133,7 @@ pub enum CanonicalVarKind<'tcx> {
     Const(ty::UniverseIndex, Ty<'tcx>),
 
     /// A "placeholder" that represents "any const".
-    PlaceholderConst(ty::PlaceholderConst<'tcx>),
+    PlaceholderConst(ty::PlaceholderConst<'tcx>, Ty<'tcx>),
 }
 
 impl<'tcx> CanonicalVarKind<'tcx> {
@@ -148,7 +148,7 @@ pub fn universe(self) -> ty::UniverseIndex {
             CanonicalVarKind::Region(ui) => ui,
             CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe,
             CanonicalVarKind::Const(ui, _) => ui,
-            CanonicalVarKind::PlaceholderConst(placeholder) => placeholder.universe,
+            CanonicalVarKind::PlaceholderConst(placeholder, _) => placeholder.universe,
         }
     }
 }
index 45c6468bc24e577a975432279a924932b73e37d3..4e1254efd179fa7f4b4f9f3578e18d731914083d 100644 (file)
@@ -26,7 +26,6 @@
 #![feature(allocator_api)]
 #![feature(array_windows)]
 #![feature(assert_matches)]
-#![feature(backtrace)]
 #![feature(box_patterns)]
 #![feature(core_intrinsics)]
 #![feature(discriminant_kind)]
index 414912dd0f7d897bdbaee48eda11d8b733be1519..7a9ad44d1d9ae86cec2b46303159c13950e95674 100644 (file)
@@ -5,7 +5,7 @@
 
 use crate::ty::{self, DefIdTree, TyCtxt};
 use rustc_ast::NodeId;
-use rustc_attr::{self as attr, ConstStability, Deprecation, Stability};
+use rustc_attr::{self as attr, ConstStability, DefaultBodyStability, Deprecation, Stability};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{Applicability, Diagnostic};
 use rustc_feature::GateIssue;
@@ -61,6 +61,7 @@ pub struct Index {
     /// are filled by the annotator.
     pub stab_map: FxHashMap<LocalDefId, Stability>,
     pub const_stab_map: FxHashMap<LocalDefId, ConstStability>,
+    pub default_body_stab_map: FxHashMap<LocalDefId, DefaultBodyStability>,
     pub depr_map: FxHashMap<LocalDefId, DeprecationEntry>,
     /// Mapping from feature name to feature name based on the `implied_by` field of `#[unstable]`
     /// attributes. If a `#[unstable(feature = "implier", implied_by = "impliee")]` attribute
@@ -86,6 +87,10 @@ pub fn local_const_stability(&self, def_id: LocalDefId) -> Option<ConstStability
         self.const_stab_map.get(&def_id).copied()
     }
 
+    pub fn local_default_body_stability(&self, def_id: LocalDefId) -> Option<DefaultBodyStability> {
+        self.default_body_stab_map.get(&def_id).copied()
+    }
+
     pub fn local_deprecation_entry(&self, def_id: LocalDefId) -> Option<DeprecationEntry> {
         self.depr_map.get(&def_id).cloned()
     }
@@ -416,6 +421,12 @@ pub fn eval_stability_allow_unstable(
             return EvalResult::Allow;
         }
 
+        // Only the cross-crate scenario matters when checking unstable APIs
+        let cross_crate = !def_id.is_local();
+        if !cross_crate {
+            return EvalResult::Allow;
+        }
+
         let stability = self.lookup_stability(def_id);
         debug!(
             "stability: \
@@ -423,12 +434,6 @@ pub fn eval_stability_allow_unstable(
             def_id, span, stability
         );
 
-        // Only the cross-crate scenario matters when checking unstable APIs
-        let cross_crate = !def_id.is_local();
-        if !cross_crate {
-            return EvalResult::Allow;
-        }
-
         // Issue #38412: private items lack stability markers.
         if skip_stability_check_due_to_privacy(self, def_id) {
             return EvalResult::Allow;
@@ -492,6 +497,62 @@ pub fn eval_stability_allow_unstable(
         }
     }
 
+    /// Evaluates the default-impl stability of an item.
+    ///
+    /// Returns `EvalResult::Allow` if the item's default implementation is stable, or unstable but the corresponding
+    /// `#![feature]` has been provided. Returns `EvalResult::Deny` which describes the offending
+    /// unstable feature otherwise.
+    pub fn eval_default_body_stability(self, def_id: DefId, span: Span) -> EvalResult {
+        let is_staged_api = self.lookup_stability(def_id.krate.as_def_id()).is_some();
+        if !is_staged_api {
+            return EvalResult::Allow;
+        }
+
+        // Only the cross-crate scenario matters when checking unstable APIs
+        let cross_crate = !def_id.is_local();
+        if !cross_crate {
+            return EvalResult::Allow;
+        }
+
+        let stability = self.lookup_default_body_stability(def_id);
+        debug!(
+            "body stability: inspecting def_id={def_id:?} span={span:?} of stability={stability:?}"
+        );
+
+        // Issue #38412: private items lack stability markers.
+        if skip_stability_check_due_to_privacy(self, def_id) {
+            return EvalResult::Allow;
+        }
+
+        match stability {
+            Some(DefaultBodyStability {
+                level: attr::Unstable { reason, issue, is_soft, .. },
+                feature,
+            }) => {
+                if span.allows_unstable(feature) {
+                    debug!("body stability: skipping span={:?} since it is internal", span);
+                    return EvalResult::Allow;
+                }
+                if self.features().active(feature) {
+                    return EvalResult::Allow;
+                }
+
+                EvalResult::Deny {
+                    feature,
+                    reason: reason.to_opt_reason(),
+                    issue,
+                    suggestion: None,
+                    is_soft,
+                }
+            }
+            Some(_) => {
+                // Stable APIs are always ok to call
+                EvalResult::Allow
+            }
+            None => EvalResult::Unmarked,
+        }
+    }
+
     /// Checks if an item is stable or error out.
     ///
     /// If the item defined by `def_id` is unstable and the corresponding `#![feature]` does not
index 64e158ba348fcb6327c8dfbab17a27f370b92df7..7ab71f9009d04a3320c5ea642c00512ac890a01a 100644 (file)
@@ -431,6 +431,12 @@ pub fn return_ty(&self) -> Ty<'tcx> {
         self.local_decls[RETURN_PLACE].ty
     }
 
+    /// Returns the return type; it always return first element from `local_decls` array.
+    #[inline]
+    pub fn bound_return_ty(&self) -> ty::EarlyBinder<Ty<'tcx>> {
+        ty::EarlyBinder(self.local_decls[RETURN_PLACE].ty)
+    }
+
     /// Gets the location of the terminator for the given block.
     #[inline]
     pub fn terminator_loc(&self, bb: BasicBlock) -> Location {
index c1e1cfef9f89d8008d502e45f3e99a1575fc145b..15496842d905daff01b32001ee38b4ef6936a5a3 100644 (file)
@@ -11,7 +11,8 @@ pub struct MirPatch<'tcx> {
     new_blocks: Vec<BasicBlockData<'tcx>>,
     new_statements: Vec<(Location, StatementKind<'tcx>)>,
     new_locals: Vec<LocalDecl<'tcx>>,
-    resume_block: BasicBlock,
+    resume_block: Option<BasicBlock>,
+    body_span: Span,
     next_local: usize,
 }
 
@@ -23,47 +24,36 @@ pub fn new(body: &Body<'tcx>) -> Self {
             new_statements: vec![],
             new_locals: vec![],
             next_local: body.local_decls.len(),
-            resume_block: START_BLOCK,
+            resume_block: None,
+            body_span: body.span,
         };
 
-        // make sure the MIR we create has a resume block. It is
-        // completely legal to convert jumps to the resume block
-        // to jumps to None, but we occasionally have to add
-        // instructions just before that.
-
-        let mut resume_block = None;
-        let mut resume_stmt_block = None;
+        // Check if we already have a resume block
         for (bb, block) in body.basic_blocks().iter_enumerated() {
-            if let TerminatorKind::Resume = block.terminator().kind {
-                if !block.statements.is_empty() {
-                    assert!(resume_stmt_block.is_none());
-                    resume_stmt_block = Some(bb);
-                } else {
-                    resume_block = Some(bb);
-                }
+            if let TerminatorKind::Resume = block.terminator().kind && block.statements.is_empty() {
+                result.resume_block = Some(bb);
                 break;
             }
         }
-        let resume_block = resume_block.unwrap_or_else(|| {
-            result.new_block(BasicBlockData {
-                statements: vec![],
-                terminator: Some(Terminator {
-                    source_info: SourceInfo::outermost(body.span),
-                    kind: TerminatorKind::Resume,
-                }),
-                is_cleanup: true,
-            })
-        });
-        result.resume_block = resume_block;
-        if let Some(resume_stmt_block) = resume_stmt_block {
-            result
-                .patch_terminator(resume_stmt_block, TerminatorKind::Goto { target: resume_block });
-        }
+
         result
     }
 
-    pub fn resume_block(&self) -> BasicBlock {
-        self.resume_block
+    pub fn resume_block(&mut self) -> BasicBlock {
+        if let Some(bb) = self.resume_block {
+            return bb;
+        }
+
+        let bb = self.new_block(BasicBlockData {
+            statements: vec![],
+            terminator: Some(Terminator {
+                source_info: SourceInfo::outermost(self.body_span),
+                kind: TerminatorKind::Resume,
+            }),
+            is_cleanup: true,
+        });
+        self.resume_block = Some(bb);
+        bb
     }
 
     pub fn is_patched(&self, bb: BasicBlock) -> bool {
@@ -138,12 +128,17 @@ pub fn apply(self, body: &mut Body<'tcx>) {
             self.new_blocks.len(),
             body.basic_blocks().len()
         );
-        body.basic_blocks_mut().extend(self.new_blocks);
+        let bbs = if self.patch_map.is_empty() && self.new_blocks.is_empty() {
+            body.basic_blocks.as_mut_preserves_cfg()
+        } else {
+            body.basic_blocks.as_mut()
+        };
+        bbs.extend(self.new_blocks);
         body.local_decls.extend(self.new_locals);
         for (src, patch) in self.patch_map.into_iter_enumerated() {
             if let Some(patch) = patch {
                 debug!("MirPatch: patching block {:?}", src);
-                body[src].terminator_mut().kind = patch;
+                bbs[src].terminator_mut().kind = patch;
             }
         }
 
index 8e3c2283efc6d4413fc1ed21f63c4f015311c1a5..eb90169d0e3141acbbab8408bf7482c8d1ac3a04 100644 (file)
@@ -800,9 +800,6 @@ pub struct Place<'tcx> {
     pub projection: &'tcx List<PlaceElem<'tcx>>,
 }
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(Place<'_>, 16);
-
 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
 #[derive(TyEncodable, TyDecodable, HashStable)]
 pub enum ProjectionElem<V, T> {
@@ -866,11 +863,6 @@ pub enum ProjectionElem<V, T> {
 /// and the index is a local.
 pub type PlaceElem<'tcx> = ProjectionElem<Local, Ty<'tcx>>;
 
-// This type is fairly frequently used, so we shouldn't unintentionally increase
-// its size.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(PlaceElem<'_>, 24);
-
 ///////////////////////////////////////////////////////////////////////////
 // Operands
 
@@ -913,9 +905,6 @@ pub enum Operand<'tcx> {
     Constant(Box<Constant<'tcx>>),
 }
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(Operand<'_>, 24);
-
 ///////////////////////////////////////////////////////////////////////////
 // Rvalues
 
@@ -1067,9 +1056,6 @@ pub enum Rvalue<'tcx> {
     CopyForDeref(Place<'tcx>),
 }
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(Rvalue<'_>, 40);
-
 #[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
 pub enum CastKind {
     /// An exposing pointer to address cast. A cast between a pointer and an integer type, or
@@ -1105,9 +1091,6 @@ pub enum AggregateKind<'tcx> {
     Generator(LocalDefId, SubstsRef<'tcx>, hir::Movability),
 }
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(AggregateKind<'_>, 48);
-
 #[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
 pub enum NullOp {
     /// Returns the size of a value of that type
@@ -1171,3 +1154,15 @@ pub enum BinOp {
     /// The `ptr.offset` operator
     Offset,
 }
+
+// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+mod size_asserts {
+    use super::*;
+    // These are in alphabetical order, which is easy to maintain.
+    static_assert_size!(AggregateKind<'_>, 48);
+    static_assert_size!(Operand<'_>, 24);
+    static_assert_size!(Place<'_>, 16);
+    static_assert_size!(PlaceElem<'_>, 24);
+    static_assert_size!(Rvalue<'_>, 40);
+}
index 891608764017c57ba720b703b529920e6141ced0..4a85defb1ed84518d20c48c301375235c2ba93c8 100644 (file)
@@ -80,6 +80,8 @@ fn visit_body(
                 self.super_body(body);
             }
 
+            extra_body_methods!($($mutability)?);
+
             fn visit_basic_block_data(
                 &mut self,
                 block: BasicBlock,
@@ -287,63 +289,7 @@ fn super_body(
                 &mut self,
                 body: &$($mutability)? Body<'tcx>,
             ) {
-                let span = body.span;
-                if let Some(gen) = &$($mutability)? body.generator {
-                    if let Some(yield_ty) = $(& $mutability)? gen.yield_ty {
-                        self.visit_ty(
-                            yield_ty,
-                            TyContext::YieldTy(SourceInfo::outermost(span))
-                        );
-                    }
-                }
-
-                // for best performance, we want to use an iterator rather
-                // than a for-loop, to avoid calling `body::Body::invalidate` for
-                // each basic block.
-                #[allow(unused_macro_rules)]
-                macro_rules! basic_blocks {
-                    (mut) => (body.basic_blocks_mut().iter_enumerated_mut());
-                    () => (body.basic_blocks().iter_enumerated());
-                }
-                for (bb, data) in basic_blocks!($($mutability)?) {
-                    self.visit_basic_block_data(bb, data);
-                }
-
-                for scope in &$($mutability)? body.source_scopes {
-                    self.visit_source_scope_data(scope);
-                }
-
-                self.visit_ty(
-                    $(& $mutability)? body.return_ty(),
-                    TyContext::ReturnTy(SourceInfo::outermost(body.span))
-                );
-
-                for local in body.local_decls.indices() {
-                    self.visit_local_decl(local, & $($mutability)? body.local_decls[local]);
-                }
-
-                #[allow(unused_macro_rules)]
-                macro_rules! type_annotations {
-                    (mut) => (body.user_type_annotations.iter_enumerated_mut());
-                    () => (body.user_type_annotations.iter_enumerated());
-                }
-
-                for (index, annotation) in type_annotations!($($mutability)?) {
-                    self.visit_user_type_annotation(
-                        index, annotation
-                    );
-                }
-
-                for var_debug_info in &$($mutability)? body.var_debug_info {
-                    self.visit_var_debug_info(var_debug_info);
-                }
-
-                self.visit_span($(& $mutability)? body.span);
-
-                for const_ in &$($mutability)? body.required_consts {
-                    let location = START_BLOCK.start_location();
-                    self.visit_constant(const_, location);
-                }
+                super_body!(self, body, $($mutability, true)?);
             }
 
             fn super_basic_block_data(&mut self,
@@ -982,12 +928,7 @@ fn visit_location(
                 body: &$($mutability)? Body<'tcx>,
                 location: Location
             ) {
-                #[allow(unused_macro_rules)]
-                macro_rules! basic_blocks {
-                    (mut) => (body.basic_blocks_mut());
-                    () => (body.basic_blocks());
-                }
-                let basic_block = & $($mutability)? basic_blocks!($($mutability)?)[location.block];
+                let basic_block = & $($mutability)? basic_blocks!(body, $($mutability, true)?)[location.block];
                 if basic_block.statements.len() == location.statement_index {
                     if let Some(ref $($mutability)? terminator) = basic_block.terminator {
                         self.visit_terminator(terminator, location)
@@ -1002,6 +943,94 @@ macro_rules! basic_blocks {
     }
 }
 
+macro_rules! basic_blocks {
+    ($body:ident, mut, true) => {
+        $body.basic_blocks.as_mut()
+    };
+    ($body:ident, mut, false) => {
+        $body.basic_blocks.as_mut_preserves_cfg()
+    };
+    ($body:ident,) => {
+        $body.basic_blocks()
+    };
+}
+
+macro_rules! basic_blocks_iter {
+    ($body:ident, mut, $invalidate:tt) => {
+        basic_blocks!($body, mut, $invalidate).iter_enumerated_mut()
+    };
+    ($body:ident,) => {
+        basic_blocks!($body,).iter_enumerated()
+    };
+}
+
+macro_rules! extra_body_methods {
+    (mut) => {
+        fn visit_body_preserves_cfg(&mut self, body: &mut Body<'tcx>) {
+            self.super_body_preserves_cfg(body);
+        }
+
+        fn super_body_preserves_cfg(&mut self, body: &mut Body<'tcx>) {
+            super_body!(self, body, mut, false);
+        }
+    };
+    () => {};
+}
+
+macro_rules! super_body {
+    ($self:ident, $body:ident, $($mutability:ident, $invalidate:tt)?) => {
+        let span = $body.span;
+        if let Some(gen) = &$($mutability)? $body.generator {
+            if let Some(yield_ty) = $(& $mutability)? gen.yield_ty {
+                $self.visit_ty(
+                    yield_ty,
+                    TyContext::YieldTy(SourceInfo::outermost(span))
+                );
+            }
+        }
+
+        for (bb, data) in basic_blocks_iter!($body, $($mutability, $invalidate)?) {
+            $self.visit_basic_block_data(bb, data);
+        }
+
+        for scope in &$($mutability)? $body.source_scopes {
+            $self.visit_source_scope_data(scope);
+        }
+
+        $self.visit_ty(
+            $(& $mutability)? $body.return_ty(),
+            TyContext::ReturnTy(SourceInfo::outermost($body.span))
+        );
+
+        for local in $body.local_decls.indices() {
+            $self.visit_local_decl(local, & $($mutability)? $body.local_decls[local]);
+        }
+
+        #[allow(unused_macro_rules)]
+        macro_rules! type_annotations {
+            (mut) => ($body.user_type_annotations.iter_enumerated_mut());
+            () => ($body.user_type_annotations.iter_enumerated());
+        }
+
+        for (index, annotation) in type_annotations!($($mutability)?) {
+            $self.visit_user_type_annotation(
+                index, annotation
+            );
+        }
+
+        for var_debug_info in &$($mutability)? $body.var_debug_info {
+            $self.visit_var_debug_info(var_debug_info);
+        }
+
+        $self.visit_span($(& $mutability)? $body.span);
+
+        for const_ in &$($mutability)? $body.required_consts {
+            let location = START_BLOCK.start_location();
+            $self.visit_constant(const_, location);
+        }
+    }
+}
+
 macro_rules! visit_place_fns {
     (mut) => {
         fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
index ffa66b79dbf825fcb2a21f7cb4034a156413ee4a..cfc75f673c8f5bb047a051662ef550d5b52edf0c 100644 (file)
         separate_provide_extern
     }
 
+    query lookup_default_body_stability(def_id: DefId) -> Option<attr::DefaultBodyStability> {
+        desc { |tcx| "looking up default body stability of `{}`", tcx.def_path_str(def_id) }
+        separate_provide_extern
+    }
+
     query should_inherit_track_caller(def_id: DefId) -> bool {
         desc { |tcx| "computing should_inherit_track_caller of `{}`", tcx.def_path_str(def_id) }
     }
         separate_provide_extern
     }
 
-    /// Given an `associated_item`, find the trait it belongs to.
-    /// Return `None` if the `DefId` is not an associated item.
-    query trait_of_item(associated_item: DefId) -> Option<DefId> {
-        desc { |tcx| "finding trait defining `{}`", tcx.def_path_str(associated_item) }
-        cache_on_disk_if { associated_item.is_local() }
-        separate_provide_extern
-    }
-
     query is_ctfe_mir_available(key: DefId) -> bool {
         desc { |tcx| "checking if item has ctfe mir available: `{}`", tcx.def_path_str(key) }
         cache_on_disk_if { key.is_local() }
         }
     }
 
+    query is_impossible_method(key: (DefId, DefId)) -> bool {
+        desc { |tcx|
+            "checking if {} is impossible to call within {}",
+            tcx.def_path_str(key.1),
+            tcx.def_path_str(key.0),
+        }
+    }
+
     query method_autoderef_steps(
         goal: CanonicalTyGoal<'tcx>
     ) -> MethodAutoderefStepsResult<'tcx> {
index 8b27ca570469766bb7732919bf594694abb02240..5e26a52900eaf404ce2e4f819ddaf64bd116f7f6 100644 (file)
@@ -190,10 +190,6 @@ pub enum StmtKind<'tcx> {
     },
 }
 
-// `Expr` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Expr<'_>, 104);
-
 #[derive(Clone, Debug, Copy, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)]
 #[derive(TypeFoldable, TypeVisitable)]
 pub struct LocalVarId(pub hir::HirId);
@@ -812,3 +808,14 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         }
     }
 }
+
+// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+mod size_asserts {
+    use super::*;
+    // These are in alphabetical order, which is easy to maintain.
+    static_assert_size!(Block, 56);
+    static_assert_size!(Expr<'_>, 104);
+    static_assert_size!(Pat<'_>, 24);
+    static_assert_size!(Stmt<'_>, 120);
+}
index 0ca5a532b754269c9faf40ff63eb1c63db326841..e836ba47eed7a31fab3bbbe1eae5bf7fd92869a1 100644 (file)
@@ -109,6 +109,10 @@ pub enum SelectionCandidate<'tcx> {
         /// `false` if there are no *further* obligations.
         has_nested: bool,
     },
+
+    /// Implementation of transmutability trait.
+    TransmutabilityCandidate,
+
     ParamCandidate(ty::PolyTraitPredicate<'tcx>),
     ImplCandidate(DefId),
     AutoImplCandidate(DefId),
index 3c1d0061ae1279c7ea281d2eb2f38744b3995de7..2465f8e2533e80caa36077c63815cf6b45a3a6f3 100644 (file)
@@ -217,7 +217,7 @@ pub fn leaf_def(mut self, tcx: TyCtxt<'tcx>, trait_item_def_id: DefId) -> Option
         self.find_map(|node| {
             if let Some(item) = node.item(tcx, trait_item_def_id) {
                 if finalizing_node.is_none() {
-                    let is_specializable = item.defaultness.is_default()
+                    let is_specializable = item.defaultness(tcx).is_default()
                         || tcx.impl_defaultness(node.def_id()).is_default();
 
                     if !is_specializable {
index 809406aff1878879802042e00a5db620c572f206..2e596b275276e3bb86478e64552b3adf03dc66d6 100644 (file)
@@ -563,7 +563,7 @@ pub fn destructor(self, tcx: TyCtxt<'tcx>) -> Option<Destructor> {
     ///
     /// Due to normalization being eager, this applies even if
     /// the associated type is behind a pointer (e.g., issue #31299).
-    pub fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> &'tcx [Ty<'tcx>] {
-        tcx.adt_sized_constraint(self.did()).0
+    pub fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> ty::EarlyBinder<&'tcx [Ty<'tcx>]> {
+        ty::EarlyBinder(tcx.adt_sized_constraint(self.did()).0)
     }
 }
index eb732148e3eb4ad7f1122de80a3799d3cbe27318..c97156ac17ff6067ed1f5298bf417f5678a895da 100644 (file)
@@ -1,6 +1,6 @@
 pub use self::AssocItemContainer::*;
 
-use crate::ty;
+use crate::ty::{self, DefIdTree};
 use rustc_data_structures::sorted_map::SortedIndexMultiMap;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Namespace};
 
 #[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable, Hash, Encodable, Decodable)]
 pub enum AssocItemContainer {
-    TraitContainer(DefId),
-    ImplContainer(DefId),
-}
-
-impl AssocItemContainer {
-    pub fn impl_def_id(&self) -> Option<DefId> {
-        match *self {
-            ImplContainer(id) => Some(id),
-            _ => None,
-        }
-    }
-
-    /// Asserts that this is the `DefId` of an associated item declared
-    /// in a trait, and returns the trait `DefId`.
-    pub fn assert_trait(&self) -> DefId {
-        match *self {
-            TraitContainer(id) => id,
-            _ => bug!("associated item has wrong container type: {:?}", self),
-        }
-    }
-
-    pub fn id(&self) -> DefId {
-        match *self {
-            TraitContainer(id) => id,
-            ImplContainer(id) => id,
-        }
-    }
+    TraitContainer,
+    ImplContainer,
 }
 
 /// Information about an associated item
@@ -46,8 +21,6 @@ pub struct AssocItem {
     pub def_id: DefId,
     pub name: Symbol,
     pub kind: AssocKind,
-    pub vis: Visibility,
-    pub defaultness: hir::Defaultness,
     pub container: AssocItemContainer,
 
     /// If this is an item in an impl of a trait then this is the `DefId` of
@@ -64,6 +37,36 @@ pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident {
         Ident::new(self.name, tcx.def_ident_span(self.def_id).unwrap())
     }
 
+    pub fn defaultness(&self, tcx: TyCtxt<'_>) -> hir::Defaultness {
+        tcx.impl_defaultness(self.def_id)
+    }
+
+    #[inline]
+    pub fn visibility(&self, tcx: TyCtxt<'_>) -> Visibility {
+        tcx.visibility(self.def_id)
+    }
+
+    #[inline]
+    pub fn container_id(&self, tcx: TyCtxt<'_>) -> DefId {
+        tcx.parent(self.def_id)
+    }
+
+    #[inline]
+    pub fn trait_container(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
+        match self.container {
+            AssocItemContainer::ImplContainer => None,
+            AssocItemContainer::TraitContainer => Some(tcx.parent(self.def_id)),
+        }
+    }
+
+    #[inline]
+    pub fn impl_container(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
+        match self.container {
+            AssocItemContainer::ImplContainer => Some(tcx.parent(self.def_id)),
+            AssocItemContainer::TraitContainer => None,
+        }
+    }
+
     pub fn signature(&self, tcx: TyCtxt<'_>) -> String {
         match self.kind {
             ty::AssocKind::Fn => {
index 2714493b9fc611592acb8e446552faaa76c979f4..0a0f45ce1a0d2091642da147042835f753d4fe79 100644 (file)
@@ -1459,11 +1459,11 @@ pub fn def_path_debug_str(self, def_id: DefId) -> String {
         };
 
         format!(
-            "{}[{}]{}",
+            "{}[{:04x}]{}",
             crate_name,
             // Don't print the whole stable crate id. That's just
             // annoying in debug output.
-            &(format!("{:08x}", stable_crate_id.to_u64()))[..4],
+            stable_crate_id.to_u64() >> 8 * 6,
             self.def_path(def_id).to_string_no_crate_verbose()
         )
     }
@@ -1668,8 +1668,7 @@ pub fn return_type_impl_trait(self, scope_def_id: LocalDefId) -> Option<(Ty<'tcx
 
     // Checks if the bound region is in Impl Item.
     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();
+        let container_id = self.parent(suitable_region_binding_scope.to_def_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
index 91246051316fa42ec6cb440f78323913af29e240..4b0bc3c1114de5905c9cfea75c8659cca92029da 100644 (file)
@@ -673,7 +673,7 @@ fn expected_projection(
             // the associated type or calling a method that returns the associated type".
             let point_at_assoc_fn = self.point_at_methods_that_satisfy_associated_type(
                 diag,
-                assoc.container.id(),
+                assoc.container_id(self),
                 current_method_ident,
                 proj_ty.item_def_id,
                 values.expected,
@@ -844,7 +844,8 @@ fn point_at_associated_type(
                         hir::AssocItemKind::Type => {
                             // FIXME: account for returning some type in a trait fn impl that has
                             // an assoc type as a return type (#72076).
-                            if let hir::Defaultness::Default { has_value: true } = item.defaultness
+                            if let hir::Defaultness::Default { has_value: true } =
+                                self.impl_defaultness(item.id.def_id)
                             {
                                 if self.type_of(item.id.def_id) == found {
                                     diag.span_label(
index 33a46f809b0d34c55f867f2d827900366f70c14f..53218225d53b82805cad1d7473ccdcc08083b9ac 100644 (file)
@@ -460,7 +460,7 @@ pub fn resolve_for_vtable(
                             && !matches!(
                                 tcx.opt_associated_item(def.did),
                                 Some(ty::AssocItem {
-                                    container: ty::AssocItemContainer::TraitContainer(_),
+                                    container: ty::AssocItemContainer::TraitContainer,
                                     ..
                                 })
                             )
index ad78d24e954653f80791612914f822a0dbbd9851..f5505590168d2927dd1fb8ffaa3b6830e2cb1e60 100644 (file)
@@ -2,7 +2,10 @@
 use crate::mir::{GeneratorLayout, GeneratorSavedLocal};
 use crate::ty::normalize_erasing_regions::NormalizationError;
 use crate::ty::subst::Subst;
-use crate::ty::{self, subst::SubstsRef, EarlyBinder, ReprOptions, Ty, TyCtxt, TypeVisitable};
+use crate::ty::{
+    self, layout_sanity_check::sanity_check_layout, subst::SubstsRef, EarlyBinder, ReprOptions, Ty,
+    TyCtxt, TypeVisitable,
+};
 use rustc_ast as ast;
 use rustc_attr as attr;
 use rustc_hir as hir;
@@ -221,114 +224,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
-/// Enforce some basic invariants on layouts.
-fn sanity_check_layout<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    layout: &TyAndLayout<'tcx>,
-) {
-    // Type-level uninhabitedness should always imply ABI uninhabitedness.
-    if tcx.conservative_is_privately_uninhabited(param_env.and(layout.ty)) {
-        assert!(layout.abi.is_uninhabited());
-    }
-
-    if layout.size.bytes() % layout.align.abi.bytes() != 0 {
-        bug!("size is not a multiple of align, in the following layout:\n{layout:#?}");
-    }
-
-    if cfg!(debug_assertions) {
-        fn check_layout_abi<'tcx>(tcx: TyCtxt<'tcx>, layout: Layout<'tcx>) {
-            match layout.abi() {
-                Abi::Scalar(scalar) => {
-                    // No padding in scalars.
-                    assert_eq!(
-                        layout.align().abi,
-                        scalar.align(&tcx).abi,
-                        "alignment mismatch between ABI and layout in {layout:#?}"
-                    );
-                    assert_eq!(
-                        layout.size(),
-                        scalar.size(&tcx),
-                        "size mismatch between ABI and layout in {layout:#?}"
-                    );
-                }
-                Abi::Vector { count, element } => {
-                    // No padding in vectors. Alignment can be strengthened, though.
-                    assert!(
-                        layout.align().abi >= element.align(&tcx).abi,
-                        "alignment mismatch between ABI and layout in {layout:#?}"
-                    );
-                    let size = element.size(&tcx) * count;
-                    assert_eq!(
-                        layout.size(),
-                        size.align_to(tcx.data_layout().vector_align(size).abi),
-                        "size mismatch between ABI and layout in {layout:#?}"
-                    );
-                }
-                Abi::ScalarPair(scalar1, scalar2) => {
-                    // Sanity-check scalar pairs. These are a bit more flexible and support
-                    // padding, but we can at least ensure both fields actually fit into the layout
-                    // and the alignment requirement has not been weakened.
-                    let align1 = scalar1.align(&tcx).abi;
-                    let align2 = scalar2.align(&tcx).abi;
-                    assert!(
-                        layout.align().abi >= cmp::max(align1, align2),
-                        "alignment mismatch between ABI and layout in {layout:#?}",
-                    );
-                    let field2_offset = scalar1.size(&tcx).align_to(align2);
-                    assert!(
-                        layout.size() >= field2_offset + scalar2.size(&tcx),
-                        "size mismatch between ABI and layout in {layout:#?}"
-                    );
-                }
-                Abi::Uninhabited | Abi::Aggregate { .. } => {} // Nothing to check.
-            }
-        }
-
-        check_layout_abi(tcx, layout.layout);
-
-        if let Variants::Multiple { variants, .. } = &layout.variants {
-            for variant in variants {
-                check_layout_abi(tcx, *variant);
-                // No nested "multiple".
-                assert!(matches!(variant.variants(), Variants::Single { .. }));
-                // Skip empty variants.
-                if variant.size() == Size::ZERO
-                    || variant.fields().count() == 0
-                    || variant.abi().is_uninhabited()
-                {
-                    // These are never actually accessed anyway, so we can skip them. (Note that
-                    // sometimes, variants with fields have size 0, and sometimes, variants without
-                    // fields have non-0 size.)
-                    continue;
-                }
-                // Variants should have the same or a smaller size as the full thing.
-                if variant.size() > layout.size {
-                    bug!(
-                        "Type with size {} bytes has variant with size {} bytes: {layout:#?}",
-                        layout.size.bytes(),
-                        variant.size().bytes(),
-                    )
-                }
-                // The top-level ABI and the ABI of the variants should be coherent.
-                let abi_coherent = match (layout.abi, variant.abi()) {
-                    (Abi::Scalar(..), Abi::Scalar(..)) => true,
-                    (Abi::ScalarPair(..), Abi::ScalarPair(..)) => true,
-                    (Abi::Uninhabited, _) => true,
-                    (Abi::Aggregate { .. }, _) => true,
-                    _ => false,
-                };
-                if !abi_coherent {
-                    bug!(
-                        "Variant ABI is incompatible with top-level ABI:\nvariant={:#?}\nTop-level: {layout:#?}",
-                        variant
-                    );
-                }
-            }
-        }
-    }
-}
-
 #[instrument(skip(tcx, query), level = "debug")]
 fn layout_of<'tcx>(
     tcx: TyCtxt<'tcx>,
@@ -372,7 +267,7 @@ fn layout_of<'tcx>(
 
             cx.record_layout_for_printing(layout);
 
-            sanity_check_layout(tcx, param_env, &layout);
+            sanity_check_layout(&cx, &layout);
 
             Ok(layout)
         })
diff --git a/compiler/rustc_middle/src/ty/layout_sanity_check.rs b/compiler/rustc_middle/src/ty/layout_sanity_check.rs
new file mode 100644 (file)
index 0000000..87c85dc
--- /dev/null
@@ -0,0 +1,303 @@
+use crate::ty::{
+    layout::{LayoutCx, TyAndLayout},
+    TyCtxt,
+};
+use rustc_target::abi::*;
+
+use std::cmp;
+
+/// Enforce some basic invariants on layouts.
+pub(super) fn sanity_check_layout<'tcx>(
+    cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
+    layout: &TyAndLayout<'tcx>,
+) {
+    // Type-level uninhabitedness should always imply ABI uninhabitedness.
+    if cx.tcx.conservative_is_privately_uninhabited(cx.param_env.and(layout.ty)) {
+        assert!(layout.abi.is_uninhabited());
+    }
+
+    if layout.size.bytes() % layout.align.abi.bytes() != 0 {
+        bug!("size is not a multiple of align, in the following layout:\n{layout:#?}");
+    }
+
+    if cfg!(debug_assertions) {
+        /// Yields non-ZST fields of the type
+        fn non_zst_fields<'tcx, 'a>(
+            cx: &'a LayoutCx<'tcx, TyCtxt<'tcx>>,
+            layout: &'a TyAndLayout<'tcx>,
+        ) -> impl Iterator<Item = (Size, TyAndLayout<'tcx>)> + 'a {
+            (0..layout.layout.fields().count()).filter_map(|i| {
+                let field = layout.field(cx, i);
+                // Also checking `align == 1` here leads to test failures in
+                // `layout/zero-sized-array-union.rs`, where a type has a zero-size field with
+                // alignment 4 that still gets ignored during layout computation (which is okay
+                // since other fields already force alignment 4).
+                let zst = field.is_zst();
+                (!zst).then(|| (layout.fields.offset(i), field))
+            })
+        }
+
+        fn skip_newtypes<'tcx>(
+            cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
+            layout: &TyAndLayout<'tcx>,
+        ) -> TyAndLayout<'tcx> {
+            if matches!(layout.layout.variants(), Variants::Multiple { .. }) {
+                // Definitely not a newtype of anything.
+                return *layout;
+            }
+            let mut fields = non_zst_fields(cx, layout);
+            let Some(first) = fields.next() else {
+                // No fields here, so this could be a primitive or enum -- either way it's not a newtype around a thing
+                return *layout
+            };
+            if fields.next().is_none() {
+                let (offset, first) = first;
+                if offset == Size::ZERO && first.layout.size() == layout.size {
+                    // This is a newtype, so keep recursing.
+                    // FIXME(RalfJung): I don't think it would be correct to do any checks for
+                    // alignment here, so we don't. Is that correct?
+                    return skip_newtypes(cx, &first);
+                }
+            }
+            // No more newtypes here.
+            *layout
+        }
+
+        fn check_layout_abi<'tcx>(cx: &LayoutCx<'tcx, TyCtxt<'tcx>>, layout: &TyAndLayout<'tcx>) {
+            match layout.layout.abi() {
+                Abi::Scalar(scalar) => {
+                    // No padding in scalars.
+                    let size = scalar.size(cx);
+                    let align = scalar.align(cx).abi;
+                    assert_eq!(
+                        layout.layout.size(),
+                        size,
+                        "size mismatch between ABI and layout in {layout:#?}"
+                    );
+                    assert_eq!(
+                        layout.layout.align().abi,
+                        align,
+                        "alignment mismatch between ABI and layout in {layout:#?}"
+                    );
+                    // Check that this matches the underlying field.
+                    let inner = skip_newtypes(cx, layout);
+                    assert!(
+                        matches!(inner.layout.abi(), Abi::Scalar(_)),
+                        "`Scalar` type {} is newtype around non-`Scalar` type {}",
+                        layout.ty,
+                        inner.ty
+                    );
+                    match inner.layout.fields() {
+                        FieldsShape::Primitive => {
+                            // Fine.
+                        }
+                        FieldsShape::Union(..) => {
+                            // FIXME: I guess we could also check something here? Like, look at all fields?
+                            return;
+                        }
+                        FieldsShape::Arbitrary { .. } => {
+                            // Should be an enum, the only field is the discriminant.
+                            assert!(
+                                inner.ty.is_enum(),
+                                "`Scalar` layout for non-primitive non-enum type {}",
+                                inner.ty
+                            );
+                            assert_eq!(
+                                inner.layout.fields().count(),
+                                1,
+                                "`Scalar` layout for multiple-field type in {inner:#?}",
+                            );
+                            let offset = inner.layout.fields().offset(0);
+                            let field = inner.field(cx, 0);
+                            // The field should be at the right offset, and match the `scalar` layout.
+                            assert_eq!(
+                                offset,
+                                Size::ZERO,
+                                "`Scalar` field at non-0 offset in {inner:#?}",
+                            );
+                            assert_eq!(
+                                field.size, size,
+                                "`Scalar` field with bad size in {inner:#?}",
+                            );
+                            assert_eq!(
+                                field.align.abi, align,
+                                "`Scalar` field with bad align in {inner:#?}",
+                            );
+                            assert!(
+                                matches!(field.abi, Abi::Scalar(_)),
+                                "`Scalar` field with bad ABI in {inner:#?}",
+                            );
+                        }
+                        _ => {
+                            panic!("`Scalar` layout for non-primitive non-enum type {}", inner.ty);
+                        }
+                    }
+                }
+                Abi::ScalarPair(scalar1, scalar2) => {
+                    // Sanity-check scalar pairs. These are a bit more flexible and support
+                    // padding, but we can at least ensure both fields actually fit into the layout
+                    // and the alignment requirement has not been weakened.
+                    let size1 = scalar1.size(cx);
+                    let align1 = scalar1.align(cx).abi;
+                    let size2 = scalar2.size(cx);
+                    let align2 = scalar2.align(cx).abi;
+                    assert!(
+                        layout.layout.align().abi >= cmp::max(align1, align2),
+                        "alignment mismatch between ABI and layout in {layout:#?}",
+                    );
+                    let field2_offset = size1.align_to(align2);
+                    assert!(
+                        layout.layout.size() >= field2_offset + size2,
+                        "size mismatch between ABI and layout in {layout:#?}"
+                    );
+                    // Check that the underlying pair of fields matches.
+                    let inner = skip_newtypes(cx, layout);
+                    assert!(
+                        matches!(inner.layout.abi(), Abi::ScalarPair(..)),
+                        "`ScalarPair` type {} is newtype around non-`ScalarPair` type {}",
+                        layout.ty,
+                        inner.ty
+                    );
+                    if matches!(inner.layout.variants(), Variants::Multiple { .. }) {
+                        // FIXME: ScalarPair for enums is enormously complicated and it is very hard
+                        // to check anything about them.
+                        return;
+                    }
+                    match inner.layout.fields() {
+                        FieldsShape::Arbitrary { .. } => {
+                            // Checked below.
+                        }
+                        FieldsShape::Union(..) => {
+                            // FIXME: I guess we could also check something here? Like, look at all fields?
+                            return;
+                        }
+                        _ => {
+                            panic!("`ScalarPair` layout with unexpected field shape in {inner:#?}");
+                        }
+                    }
+                    let mut fields = non_zst_fields(cx, &inner);
+                    let (offset1, field1) = fields.next().unwrap_or_else(|| {
+                        panic!("`ScalarPair` layout for type with not even one non-ZST field: {inner:#?}")
+                    });
+                    let (offset2, field2) = fields.next().unwrap_or_else(|| {
+                        panic!("`ScalarPair` layout for type with less than two non-ZST fields: {inner:#?}")
+                    });
+                    assert!(
+                        fields.next().is_none(),
+                        "`ScalarPair` layout for type with at least three non-ZST fields: {inner:#?}"
+                    );
+                    // The fields might be in opposite order.
+                    let (offset1, field1, offset2, field2) = if offset1 <= offset2 {
+                        (offset1, field1, offset2, field2)
+                    } else {
+                        (offset2, field2, offset1, field1)
+                    };
+                    // The fields should be at the right offset, and match the `scalar` layout.
+                    assert_eq!(
+                        offset1,
+                        Size::ZERO,
+                        "`ScalarPair` first field at non-0 offset in {inner:#?}",
+                    );
+                    assert_eq!(
+                        field1.size, size1,
+                        "`ScalarPair` first field with bad size in {inner:#?}",
+                    );
+                    assert_eq!(
+                        field1.align.abi, align1,
+                        "`ScalarPair` first field with bad align in {inner:#?}",
+                    );
+                    assert!(
+                        matches!(field1.abi, Abi::Scalar(_)),
+                        "`ScalarPair` first field with bad ABI in {inner:#?}",
+                    );
+                    assert_eq!(
+                        offset2, field2_offset,
+                        "`ScalarPair` second field at bad offset in {inner:#?}",
+                    );
+                    assert_eq!(
+                        field2.size, size2,
+                        "`ScalarPair` second field with bad size in {inner:#?}",
+                    );
+                    assert_eq!(
+                        field2.align.abi, align2,
+                        "`ScalarPair` second field with bad align in {inner:#?}",
+                    );
+                    assert!(
+                        matches!(field2.abi, Abi::Scalar(_)),
+                        "`ScalarPair` second field with bad ABI in {inner:#?}",
+                    );
+                }
+                Abi::Vector { count, element } => {
+                    // No padding in vectors. Alignment can be strengthened, though.
+                    assert!(
+                        layout.layout.align().abi >= element.align(cx).abi,
+                        "alignment mismatch between ABI and layout in {layout:#?}"
+                    );
+                    let size = element.size(cx) * count;
+                    assert_eq!(
+                        layout.layout.size(),
+                        size.align_to(cx.data_layout().vector_align(size).abi),
+                        "size mismatch between ABI and layout in {layout:#?}"
+                    );
+                }
+                Abi::Uninhabited | Abi::Aggregate { .. } => {} // Nothing to check.
+            }
+        }
+
+        check_layout_abi(cx, layout);
+
+        if let Variants::Multiple { variants, .. } = &layout.variants {
+            for variant in variants.iter() {
+                // No nested "multiple".
+                assert!(matches!(variant.variants(), Variants::Single { .. }));
+                // Variants should have the same or a smaller size as the full thing,
+                // and same for alignment.
+                if variant.size() > layout.size {
+                    bug!(
+                        "Type with size {} bytes has variant with size {} bytes: {layout:#?}",
+                        layout.size.bytes(),
+                        variant.size().bytes(),
+                    )
+                }
+                if variant.align().abi > layout.align.abi {
+                    bug!(
+                        "Type with alignment {} bytes has variant with alignment {} bytes: {layout:#?}",
+                        layout.align.abi.bytes(),
+                        variant.align().abi.bytes(),
+                    )
+                }
+                // Skip empty variants.
+                if variant.size() == Size::ZERO
+                    || variant.fields().count() == 0
+                    || variant.abi().is_uninhabited()
+                {
+                    // These are never actually accessed anyway, so we can skip the coherence check
+                    // for them. They also fail that check, since they have
+                    // `Aggregate`/`Uninhbaited` ABI even when the main type is
+                    // `Scalar`/`ScalarPair`. (Note that sometimes, variants with fields have size
+                    // 0, and sometimes, variants without fields have non-0 size.)
+                    continue;
+                }
+                // The top-level ABI and the ABI of the variants should be coherent.
+                let scalar_coherent = |s1: Scalar, s2: Scalar| {
+                    s1.size(cx) == s2.size(cx) && s1.align(cx) == s2.align(cx)
+                };
+                let abi_coherent = match (layout.abi, variant.abi()) {
+                    (Abi::Scalar(s1), Abi::Scalar(s2)) => scalar_coherent(s1, s2),
+                    (Abi::ScalarPair(a1, b1), Abi::ScalarPair(a2, b2)) => {
+                        scalar_coherent(a1, a2) && scalar_coherent(b1, b2)
+                    }
+                    (Abi::Uninhabited, _) => true,
+                    (Abi::Aggregate { .. }, _) => true,
+                    _ => false,
+                };
+                if !abi_coherent {
+                    bug!(
+                        "Variant ABI is incompatible with top-level ABI:\nvariant={:#?}\nTop-level: {layout:#?}",
+                        variant
+                    );
+                }
+            }
+        }
+    }
+}
index da9d51a29b18c45d79caa7a03597dff9118cd403..a7833ab64310fc29513aac6f9c7eb015cc1f29ba 100644 (file)
@@ -48,7 +48,7 @@
 pub use vtable::*;
 
 use std::fmt::Debug;
-use std::hash::Hash;
+use std::hash::{Hash, Hasher};
 use std::ops::ControlFlow;
 use std::{fmt, str};
 
 mod generics;
 mod impls_ty;
 mod instance;
+mod layout_sanity_check;
 mod list;
 mod parameterized;
 mod rvalue_scopes;
@@ -177,6 +178,11 @@ pub struct ResolverAstLowering {
     pub label_res_map: NodeMap<ast::NodeId>,
     /// Resolutions for lifetimes.
     pub lifetimes_res_map: NodeMap<LifetimeRes>,
+    /// Mapping from generics `def_id`s to TAIT generics `def_id`s.
+    /// For each captured lifetime (e.g., 'a), we create a new lifetime parameter that is a generic
+    /// defined on the TAIT, so we have type Foo<'a1> = ... and we establish a mapping in this
+    /// field from the original parameter 'a to the new parameter 'a1.
+    pub generics_def_id_map: Vec<FxHashMap<LocalDefId, LocalDefId>>,
     /// Lifetime parameters that lowering will have to introduce.
     pub extra_lifetime_params_map: NodeMap<Vec<(Ident, ast::NodeId, LifetimeRes)>>,
 
@@ -588,6 +594,29 @@ pub fn without_const(mut self, tcx: TyCtxt<'tcx>) -> Self {
         }
         self
     }
+
+    /// Whether this projection can be soundly normalized.
+    ///
+    /// Wf predicates must not be normalized, as normalization
+    /// can remove required bounds which would cause us to
+    /// unsoundly accept some programs. See #91068.
+    #[inline]
+    pub fn allow_normalization(self) -> bool {
+        match self.kind().skip_binder() {
+            PredicateKind::WellFormed(_) => false,
+            PredicateKind::Trait(_)
+            | PredicateKind::RegionOutlives(_)
+            | PredicateKind::TypeOutlives(_)
+            | PredicateKind::Projection(_)
+            | PredicateKind::ObjectSafe(_)
+            | PredicateKind::ClosureKind(_, _, _)
+            | PredicateKind::Subtype(_)
+            | PredicateKind::Coerce(_)
+            | PredicateKind::ConstEvaluatable(_)
+            | PredicateKind::ConstEquate(_, _)
+            | PredicateKind::TypeWellFormedFromEnv(_) => true,
+        }
+    }
 }
 
 impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Predicate<'tcx> {
@@ -1200,7 +1229,7 @@ pub struct BoundConst<'tcx> {
     pub ty: Ty<'tcx>,
 }
 
-pub type PlaceholderConst<'tcx> = Placeholder<BoundConst<'tcx>>;
+pub type PlaceholderConst<'tcx> = Placeholder<BoundVar>;
 
 /// A `DefId` which, in case it is a const argument, is potentially bundled with
 /// the `DefId` of the generic parameter it instantiates.
@@ -1704,6 +1733,59 @@ pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident {
     }
 }
 
+impl PartialEq for VariantDef {
+    #[inline]
+    fn eq(&self, other: &Self) -> bool {
+        // There should be only one `VariantDef` for each `def_id`, therefore
+        // it is fine to implement `PartialEq` only based on `def_id`.
+        //
+        // Below, we exhaustively destructure `self` and `other` so that if the
+        // definition of `VariantDef` changes, a compile-error will be produced,
+        // reminding us to revisit this assumption.
+
+        let Self {
+            def_id: lhs_def_id,
+            ctor_def_id: _,
+            name: _,
+            discr: _,
+            fields: _,
+            ctor_kind: _,
+            flags: _,
+        } = &self;
+
+        let Self {
+            def_id: rhs_def_id,
+            ctor_def_id: _,
+            name: _,
+            discr: _,
+            fields: _,
+            ctor_kind: _,
+            flags: _,
+        } = other;
+
+        lhs_def_id == rhs_def_id
+    }
+}
+
+impl Eq for VariantDef {}
+
+impl Hash for VariantDef {
+    #[inline]
+    fn hash<H: Hasher>(&self, s: &mut H) {
+        // There should be only one `VariantDef` for each `def_id`, therefore
+        // it is fine to implement `Hash` only based on `def_id`.
+        //
+        // Below, we exhaustively destructure `self` so that if the definition
+        // of `VariantDef` changes, a compile-error will be produced, reminding
+        // us to revisit this assumption.
+
+        let Self { def_id, ctor_def_id: _, name: _, discr: _, fields: _, ctor_kind: _, flags: _ } =
+            &self;
+
+        def_id.hash(s)
+    }
+}
+
 #[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
 pub enum VariantDiscr {
     /// Explicit value for this variant, i.e., `X = 123`.
@@ -1724,6 +1806,42 @@ pub struct FieldDef {
     pub vis: Visibility,
 }
 
+impl PartialEq for FieldDef {
+    #[inline]
+    fn eq(&self, other: &Self) -> bool {
+        // There should be only one `FieldDef` for each `did`, therefore it is
+        // fine to implement `PartialEq` only based on `did`.
+        //
+        // Below, we exhaustively destructure `self` so that if the definition
+        // of `FieldDef` changes, a compile-error will be produced, reminding
+        // us to revisit this assumption.
+
+        let Self { did: lhs_did, name: _, vis: _ } = &self;
+
+        let Self { did: rhs_did, name: _, vis: _ } = other;
+
+        lhs_did == rhs_did
+    }
+}
+
+impl Eq for FieldDef {}
+
+impl Hash for FieldDef {
+    #[inline]
+    fn hash<H: Hasher>(&self, s: &mut H) {
+        // There should be only one `FieldDef` for each `did`, therefore it is
+        // fine to implement `Hash` only based on `did`.
+        //
+        // Below, we exhaustively destructure `self` so that if the definition
+        // of `FieldDef` changes, a compile-error will be produced, reminding
+        // us to revisit this assumption.
+
+        let Self { did, name: _, vis: _ } = &self;
+
+        did.hash(s)
+    }
+}
+
 bitflags! {
     #[derive(TyEncodable, TyDecodable, Default, HashStable)]
     pub struct ReprFlags: u8 {
@@ -1945,7 +2063,7 @@ pub fn typeck_body(self, body: hir::BodyId) -> &'tcx TypeckResults<'tcx> {
     pub fn provided_trait_methods(self, id: DefId) -> impl 'tcx + Iterator<Item = &'tcx AssocItem> {
         self.associated_items(id)
             .in_definition_order()
-            .filter(|item| item.kind == AssocKind::Fn && item.defaultness.has_value())
+            .filter(move |item| item.kind == AssocKind::Fn && item.defaultness(self).has_value())
     }
 
     /// Look up the name of a definition across crates. This does not look at HIR.
@@ -2191,13 +2309,29 @@ pub fn trait_id_of_impl(self, def_id: DefId) -> Option<DefId> {
         self.impl_trait_ref(def_id).map(|tr| tr.def_id)
     }
 
+    /// If the given `DefId` describes an item belonging to a trait,
+    /// returns the `DefId` of the trait that the trait item belongs to;
+    /// otherwise, returns `None`.
+    pub fn trait_of_item(self, def_id: DefId) -> Option<DefId> {
+        if let DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy = self.def_kind(def_id) {
+            let parent = self.parent(def_id);
+            if let DefKind::Trait | DefKind::TraitAlias = self.def_kind(parent) {
+                return Some(parent);
+            }
+        }
+        None
+    }
+
     /// If the given `DefId` describes a method belonging to an impl, returns the
     /// `DefId` of the impl that the method belongs to; otherwise, returns `None`.
     pub fn impl_of_method(self, def_id: DefId) -> Option<DefId> {
-        self.opt_associated_item(def_id).and_then(|trait_item| match trait_item.container {
-            TraitContainer(_) => None,
-            ImplContainer(def_id) => Some(def_id),
-        })
+        if let DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy = self.def_kind(def_id) {
+            let parent = self.parent(def_id);
+            if let DefKind::Impl = self.def_kind(parent) {
+                return Some(parent);
+            }
+        }
+        None
     }
 
     /// If the given `DefId` belongs to a trait that was automatically derived, returns `true`.
index e189ee2fc4db12023454c91fe5aa1669da6b487a..ae6e2eecbffb5f46516c54904a487f75c2d8ca9b 100644 (file)
@@ -64,6 +64,7 @@ impl $crate::ty::ParameterizedOverTcx for $ty {
     rustc_ast::Attribute,
     rustc_ast::MacArgs,
     rustc_attr::ConstStability,
+    rustc_attr::DefaultBodyStability,
     rustc_attr::Deprecation,
     rustc_attr::Stability,
     rustc_hir::Constness,
index 7f2e81a71a93d16cd773eeb221339fa8eeca15df..cc55b7e8611af2b6562a2904b5d1c42687aef7c3 100644 (file)
@@ -1513,6 +1513,10 @@ fn pretty_print_const_valtree(
                 }
                 return Ok(self);
             }
+            (ty::ValTree::Leaf(leaf), ty::Ref(_, inner_ty, _)) => {
+                p!(write("&"));
+                return self.pretty_print_const_scalar_int(leaf, *inner_ty, print_ty);
+            }
             (ty::ValTree::Leaf(leaf), _) => {
                 return self.pretty_print_const_scalar_int(leaf, ty, print_ty);
             }
index 411d5c55829bd9c1df666247865de40e232a1198..52c3a38861e6531984603dc86497ea220e98bab1 100644 (file)
@@ -1179,13 +1179,14 @@ pub struct ProjectionTy<'tcx> {
     /// The `DefId` of the `TraitItem` for the associated type `N`.
     ///
     /// Note that this is not the `DefId` of the `TraitRef` containing this
-    /// associated type, which is in `tcx.associated_item(item_def_id).container`.
+    /// associated type, which is in `tcx.associated_item(item_def_id).container`,
+    /// aka. `tcx.parent(item_def_id).unwrap()`.
     pub item_def_id: DefId,
 }
 
 impl<'tcx> ProjectionTy<'tcx> {
     pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId {
-        tcx.associated_item(self.item_def_id).container.id()
+        tcx.parent(self.item_def_id)
     }
 
     /// Extracts the underlying trait reference and own substs from this projection.
@@ -1195,7 +1196,7 @@ pub fn trait_ref_and_own_substs(
         &self,
         tcx: TyCtxt<'tcx>,
     ) -> (ty::TraitRef<'tcx>, &'tcx [ty::GenericArg<'tcx>]) {
-        let def_id = tcx.associated_item(self.item_def_id).container.id();
+        let def_id = tcx.parent(self.item_def_id);
         let trait_generics = tcx.generics_of(def_id);
         (
             ty::TraitRef { def_id, substs: self.substs.truncate_to(tcx, trait_generics) },
@@ -1433,7 +1434,7 @@ impl<'tcx> ExistentialProjection<'tcx> {
     /// then this function would return an `exists T. T: Iterator` existential trait
     /// reference.
     pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::ExistentialTraitRef<'tcx> {
-        let def_id = tcx.associated_item(self.item_def_id).container.id();
+        let def_id = tcx.parent(self.item_def_id);
         let subst_count = tcx.generics_of(def_id).count() - 1;
         let substs = tcx.intern_substs(&self.substs[..subst_count]);
         ty::ExistentialTraitRef { def_id, substs }
@@ -2190,7 +2191,7 @@ pub fn is_trivially_sized(self, tcx: TyCtxt<'tcx>) -> bool {
 
             ty::Tuple(tys) => tys.iter().all(|ty| ty.is_trivially_sized(tcx)),
 
-            ty::Adt(def, _substs) => def.sized_constraint(tcx).is_empty(),
+            ty::Adt(def, _substs) => def.sized_constraint(tcx).0.is_empty(),
 
             ty::Projection(_) | ty::Param(_) | ty::Opaque(..) => false,
 
index 4d2f69b23fa09adbe47a2a06f75dcce5b9d91c3f..591bb7831b5b6375ab98b17f28ecfb389dc26e5a 100644 (file)
@@ -402,7 +402,7 @@ pub fn destructor_constraints(self, def: ty::AdtDef<'tcx>) -> Vec<ty::subst::Gen
             Some(dtor) => dtor.did,
         };
 
-        let impl_def_id = self.associated_item(dtor).container.id();
+        let impl_def_id = self.parent(dtor);
         let impl_generics = self.generics_of(impl_def_id);
 
         // We have a destructor - all the parameters that are not
@@ -680,6 +680,24 @@ pub fn bound_item_bounds(
     pub fn bound_const_param_default(self, def_id: DefId) -> ty::EarlyBinder<ty::Const<'tcx>> {
         ty::EarlyBinder(self.const_param_default(def_id))
     }
+
+    pub fn bound_predicates_of(
+        self,
+        def_id: DefId,
+    ) -> ty::EarlyBinder<ty::generics::GenericPredicates<'tcx>> {
+        ty::EarlyBinder(self.predicates_of(def_id))
+    }
+
+    pub fn bound_explicit_predicates_of(
+        self,
+        def_id: DefId,
+    ) -> ty::EarlyBinder<ty::generics::GenericPredicates<'tcx>> {
+        ty::EarlyBinder(self.explicit_predicates_of(def_id))
+    }
+
+    pub fn bound_impl_subject(self, def_id: DefId) -> ty::EarlyBinder<ty::ImplSubject<'tcx>> {
+        ty::EarlyBinder(self.impl_subject(def_id))
+    }
 }
 
 struct OpaqueTypeExpander<'tcx> {
index 58b1564cc5d8ce3d600e1e5be4d57ffa6af65e7f..ce38283724dac892e7ebd5c3200f4c417d012b52 100644 (file)
@@ -170,7 +170,7 @@ pub(crate) fn match_expr(
 
         let mut arm_candidates = self.create_match_candidates(scrutinee_place.clone(), &arms);
 
-        let match_has_guard = arms.iter().copied().any(|arm| self.thir[arm].guard.is_some());
+        let match_has_guard = arm_candidates.iter().any(|(_, candidate)| candidate.has_guard);
         let mut candidates =
             arm_candidates.iter_mut().map(|(_, candidate)| candidate).collect::<Vec<_>>();
 
@@ -2334,7 +2334,7 @@ pub(crate) fn ast_let_else(
         // This place is not really used because this destination place
         // should never be used to take values at the end of the failure
         // block.
-        let dummy_place = Place { local: RETURN_PLACE, projection: ty::List::empty() };
+        let dummy_place = self.temp(self.tcx.types.never, else_block.span);
         let failure_block;
         unpack!(
             failure_block = self.ast_block(
index d21a8c4f9b9a3e2a410d32e1d067046b7f3e501e..54d549fd66c95b2ce39cf40c8be61858cda61825 100644 (file)
@@ -1,10 +1,10 @@
 use rustc_data_structures::graph::iterate::{
     NodeStatus, TriColorDepthFirstSearch, TriColorVisitor,
 };
-use rustc_hir::intravisit::FnKind;
+use rustc_hir::def::DefKind;
 use rustc_middle::mir::{BasicBlock, BasicBlocks, Body, Operand, TerminatorKind};
 use rustc_middle::ty::subst::{GenericArg, InternalSubsts};
-use rustc_middle::ty::{self, AssocItem, AssocItemContainer, Instance, TyCtxt};
+use rustc_middle::ty::{self, Instance, TyCtxt};
 use rustc_session::lint::builtin::UNCONDITIONAL_RECURSION;
 use rustc_span::Span;
 use std::ops::ControlFlow;
 pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
     let def_id = body.source.def_id().expect_local();
 
-    if let Some(fn_kind) = tcx.hir().get_by_def_id(def_id).fn_kind() {
-        if let FnKind::Closure = fn_kind {
-            // closures can't recur, so they don't matter.
-            return;
-        }
-
+    if let DefKind::Fn | DefKind::AssocFn = tcx.def_kind(def_id) {
         // If this is trait/impl method, extract the trait's substs.
-        let trait_substs = match tcx.opt_associated_item(def_id.to_def_id()) {
-            Some(AssocItem {
-                container: AssocItemContainer::TraitContainer(trait_def_id), ..
-            }) => {
-                let trait_substs_count = tcx.generics_of(*trait_def_id).count();
+        let trait_substs = match tcx.trait_of_item(def_id.to_def_id()) {
+            Some(trait_def_id) => {
+                let trait_substs_count = tcx.generics_of(trait_def_id).count();
                 &InternalSubsts::identity_for_item(tcx, def_id.to_def_id())[..trait_substs_count]
             }
             _ => &[],
@@ -41,8 +34,8 @@ pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
 
         vis.reachable_recursive_calls.sort();
 
+        let sp = tcx.def_span(def_id);
         let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-        let sp = tcx.sess.source_map().guess_head_span(tcx.hir().span_with_body(hir_id));
         tcx.struct_span_lint_hir(UNCONDITIONAL_RECURSION, hir_id, sp, |lint| {
             let mut db = lint.build("function cannot return without recursing");
             db.span_label(sp, "cannot return without recursing");
index 063c076474e9027661b9be18d1e35c5885c379c4..69a8c98b27a3d76b72ef1c8e5bfb647b923c0279 100644 (file)
@@ -849,22 +849,22 @@ fn non_exhaustive_match<'p, 'tcx>(
             ));
         }
         [.., prev, last] if prev.span.eq_ctxt(last.span) => {
-            if let Ok(snippet) = sm.span_to_snippet(prev.span.between(last.span)) {
-                let comma = if matches!(last.body.kind, hir::ExprKind::Block(..))
-                    && last.span.eq_ctxt(last.body.span)
-                {
-                    ""
-                } else {
-                    ","
-                };
+            let comma = if matches!(last.body.kind, hir::ExprKind::Block(..))
+                && last.span.eq_ctxt(last.body.span)
+            {
+                ""
+            } else {
+                ","
+            };
+            let spacing = if sm.is_multiline(prev.span.between(last.span)) {
+                sm.indentation_before(last.span).map(|indent| format!("\n{indent}"))
+            } else {
+                Some(" ".to_string())
+            };
+            if let Some(spacing) = spacing {
                 suggestion = Some((
                     last.span.shrink_to_hi(),
-                    format!(
-                        "{}{}{} => todo!()",
-                        comma,
-                        snippet.strip_prefix(',').unwrap_or(&snippet),
-                        pattern
-                    ),
+                    format!("{}{}{} => todo!()", comma, spacing, pattern),
                 ));
             }
         }
index d6dd0f017941a74aa2a8f84ee5b9eff18412cdcb..f2045ac19cac42920293ecc3b71d865cf5cb29a9 100644 (file)
@@ -168,7 +168,12 @@ fn to_pat(
         // once indirect_structural_match is a full fledged error, this
         // level of indirection can be eliminated
 
-        let inlined_const_as_pat = self.recur(cv, mir_structural_match_violation).unwrap();
+        let inlined_const_as_pat =
+            self.recur(cv, mir_structural_match_violation).unwrap_or_else(|_| Pat {
+                span: self.span,
+                ty: cv.ty(),
+                kind: Box::new(PatKind::Constant { value: cv }),
+            });
 
         if self.include_lint_checks && !self.saw_const_match_error.get() {
             // If we were able to successfully convert the const to some pat,
index 60db98073a3b91776504b854718a6f88ffb494ad..8d6f8efb6003f9fd7745b02e331859f14cc3ab77 100644 (file)
@@ -261,7 +261,7 @@ fn to_pat<'tcx>(&self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Pat<'tcx> {
     /// Lint on likely incorrect range patterns (#63987)
     pub(super) fn lint_overlapping_range_endpoints<'a, 'p: 'a, 'tcx: 'a>(
         &self,
-        pcx: PatCtxt<'_, 'p, 'tcx>,
+        pcx: &PatCtxt<'_, 'p, 'tcx>,
         pats: impl Iterator<Item = &'a DeconstructedPat<'p, 'tcx>>,
         column_count: usize,
         hir_id: HirId,
@@ -617,7 +617,7 @@ fn iter<'a>(&'a self) -> impl Iterator<Item = Slice> + Captures<'a> {
             // The only admissible fixed-length slice is one of the array size. Whether `max_slice`
             // is fixed-length or variable-length, it will be the only relevant slice to output
             // here.
-            Some(_) => (0..0), // empty range
+            Some(_) => 0..0, // empty range
             // We cover all arities in the range `(self.arity..infinity)`. We split that range into
             // two: lengths smaller than `max_slice.arity()` are treated independently as
             // fixed-lengths slices, and lengths above are captured by `max_slice`.
@@ -696,7 +696,7 @@ fn as_slice(&self) -> Option<Slice> {
     /// `EvalResult::Deny { .. }`.
     ///
     /// This means that the variant has a stdlib unstable feature marking it.
-    pub(super) fn is_unstable_variant(&self, pcx: PatCtxt<'_, '_, 'tcx>) -> bool {
+    pub(super) fn is_unstable_variant(&self, pcx: &PatCtxt<'_, '_, 'tcx>) -> bool {
         if let Constructor::Variant(idx) = self && let ty::Adt(adt, _) = pcx.ty.kind() {
             let variant_def_id = adt.variant(*idx).def_id;
             // Filter variants that depend on a disabled unstable feature.
@@ -710,7 +710,7 @@ pub(super) fn is_unstable_variant(&self, pcx: PatCtxt<'_, '_, 'tcx>) -> bool {
 
     /// Checks if the `Constructor` is a `Constructor::Variant` with a `#[doc(hidden)]`
     /// attribute from a type not local to the current crate.
-    pub(super) fn is_doc_hidden_variant(&self, pcx: PatCtxt<'_, '_, 'tcx>) -> bool {
+    pub(super) fn is_doc_hidden_variant(&self, pcx: &PatCtxt<'_, '_, 'tcx>) -> bool {
         if let Constructor::Variant(idx) = self && let ty::Adt(adt, _) = pcx.ty.kind() {
             let variant_def_id = adt.variants()[*idx].def_id;
             return pcx.cx.tcx.is_doc_hidden(variant_def_id) && !variant_def_id.is_local();
@@ -731,7 +731,7 @@ fn variant_index_for_adt(&self, adt: ty::AdtDef<'tcx>) -> VariantIdx {
 
     /// The number of fields for this constructor. This must be kept in sync with
     /// `Fields::wildcards`.
-    pub(super) fn arity(&self, pcx: PatCtxt<'_, '_, 'tcx>) -> usize {
+    pub(super) fn arity(&self, pcx: &PatCtxt<'_, '_, 'tcx>) -> usize {
         match self {
             Single | Variant(_) => match pcx.ty.kind() {
                 ty::Tuple(fs) => fs.len(),
@@ -775,7 +775,7 @@ pub(super) fn arity(&self, pcx: PatCtxt<'_, '_, 'tcx>) -> usize {
     /// matrix, unless all of them are.
     pub(super) fn split<'a>(
         &self,
-        pcx: PatCtxt<'_, '_, 'tcx>,
+        pcx: &PatCtxt<'_, '_, 'tcx>,
         ctors: impl Iterator<Item = &'a Constructor<'tcx>> + Clone,
     ) -> SmallVec<[Self; 1]>
     where
@@ -811,7 +811,7 @@ pub(super) fn split<'a>(
     /// this checks for inclusion.
     // We inline because this has a single call site in `Matrix::specialize_constructor`.
     #[inline]
-    pub(super) fn is_covered_by<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>, other: &Self) -> bool {
+    pub(super) fn is_covered_by<'p>(&self, pcx: &PatCtxt<'_, 'p, 'tcx>, other: &Self) -> bool {
         // This must be kept in sync with `is_covered_by_any`.
         match (self, other) {
             // Wildcards cover anything
@@ -865,7 +865,7 @@ pub(super) fn is_covered_by<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>, other: &Self)
     /// assumed to have been split from a wildcard.
     fn is_covered_by_any<'p>(
         &self,
-        pcx: PatCtxt<'_, 'p, 'tcx>,
+        pcx: &PatCtxt<'_, 'p, 'tcx>,
         used_ctors: &[Constructor<'tcx>],
     ) -> bool {
         if used_ctors.is_empty() {
@@ -918,7 +918,7 @@ pub(super) struct SplitWildcard<'tcx> {
 }
 
 impl<'tcx> SplitWildcard<'tcx> {
-    pub(super) fn new<'p>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Self {
+    pub(super) fn new<'p>(pcx: &PatCtxt<'_, 'p, 'tcx>) -> Self {
         debug!("SplitWildcard::new({:?})", pcx.ty);
         let cx = pcx.cx;
         let make_range = |start, end| {
@@ -1044,7 +1044,7 @@ pub(super) fn new<'p>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Self {
     /// do what you want.
     pub(super) fn split<'a>(
         &mut self,
-        pcx: PatCtxt<'_, '_, 'tcx>,
+        pcx: &PatCtxt<'_, '_, 'tcx>,
         ctors: impl Iterator<Item = &'a Constructor<'tcx>> + Clone,
     ) where
         'tcx: 'a,
@@ -1056,21 +1056,21 @@ pub(super) fn split<'a>(
     }
 
     /// Whether there are any value constructors for this type that are not present in the matrix.
-    fn any_missing(&self, pcx: PatCtxt<'_, '_, 'tcx>) -> bool {
+    fn any_missing(&self, pcx: &PatCtxt<'_, '_, 'tcx>) -> bool {
         self.iter_missing(pcx).next().is_some()
     }
 
     /// Iterate over the constructors for this type that are not present in the matrix.
     pub(super) fn iter_missing<'a, 'p>(
         &'a self,
-        pcx: PatCtxt<'a, 'p, 'tcx>,
+        pcx: &'a PatCtxt<'a, 'p, 'tcx>,
     ) -> impl Iterator<Item = &'a Constructor<'tcx>> + Captures<'p> {
         self.all_ctors.iter().filter(move |ctor| !ctor.is_covered_by_any(pcx, &self.matrix_ctors))
     }
 
     /// Return the set of constructors resulting from splitting the wildcard. As explained at the
     /// top of the file, if any constructors are missing we can ignore the present ones.
-    fn into_ctors(self, pcx: PatCtxt<'_, '_, 'tcx>) -> SmallVec<[Constructor<'tcx>; 1]> {
+    fn into_ctors(self, pcx: &PatCtxt<'_, '_, 'tcx>) -> SmallVec<[Constructor<'tcx>; 1]> {
         if self.any_missing(pcx) {
             // Some constructors are missing, thus we can specialize with the special `Missing`
             // constructor, which stands for those constructors that are not seen in the matrix,
@@ -1202,35 +1202,32 @@ fn list_variant_nonhidden_fields<'a>(
 
     /// Creates a new list of wildcard fields for a given constructor. The result must have a
     /// length of `constructor.arity()`.
-    pub(super) fn wildcards(
-        cx: &MatchCheckCtxt<'p, 'tcx>,
-        ty: Ty<'tcx>,
-        constructor: &Constructor<'tcx>,
-    ) -> Self {
+    #[instrument(level = "trace")]
+    pub(super) fn wildcards(pcx: &PatCtxt<'_, 'p, 'tcx>, constructor: &Constructor<'tcx>) -> Self {
         let ret = match constructor {
-            Single | Variant(_) => match ty.kind() {
-                ty::Tuple(fs) => Fields::wildcards_from_tys(cx, fs.iter()),
-                ty::Ref(_, rty, _) => Fields::wildcards_from_tys(cx, once(*rty)),
+            Single | Variant(_) => match pcx.ty.kind() {
+                ty::Tuple(fs) => Fields::wildcards_from_tys(pcx.cx, fs.iter()),
+                ty::Ref(_, rty, _) => Fields::wildcards_from_tys(pcx.cx, once(*rty)),
                 ty::Adt(adt, substs) => {
                     if adt.is_box() {
                         // The only legal patterns of type `Box` (outside `std`) are `_` and box
                         // patterns. If we're here we can assume this is a box pattern.
-                        Fields::wildcards_from_tys(cx, once(substs.type_at(0)))
+                        Fields::wildcards_from_tys(pcx.cx, once(substs.type_at(0)))
                     } else {
                         let variant = &adt.variant(constructor.variant_index_for_adt(*adt));
-                        let tys = Fields::list_variant_nonhidden_fields(cx, ty, variant)
+                        let tys = Fields::list_variant_nonhidden_fields(pcx.cx, pcx.ty, variant)
                             .map(|(_, ty)| ty);
-                        Fields::wildcards_from_tys(cx, tys)
+                        Fields::wildcards_from_tys(pcx.cx, tys)
                     }
                 }
-                _ => bug!("Unexpected type for `Single` constructor: {:?}", ty),
+                _ => bug!("Unexpected type for `Single` constructor: {:?}", pcx),
             },
-            Slice(slice) => match *ty.kind() {
+            Slice(slice) => match *pcx.ty.kind() {
                 ty::Slice(ty) | ty::Array(ty, _) => {
                     let arity = slice.arity();
-                    Fields::wildcards_from_tys(cx, (0..arity).map(|_| ty))
+                    Fields::wildcards_from_tys(pcx.cx, (0..arity).map(|_| ty))
                 }
-                _ => bug!("bad slice pattern {:?} {:?}", constructor, ty),
+                _ => bug!("bad slice pattern {:?} {:?}", constructor, pcx),
             },
             Str(..)
             | FloatRange(..)
@@ -1243,7 +1240,7 @@ pub(super) fn wildcards(
                 bug!("called `Fields::wildcards` on an `Or` ctor")
             }
         };
-        debug!("Fields::wildcards({:?}, {:?}) = {:#?}", constructor, ty, ret);
+        debug!(?ret);
         ret
     }
 
@@ -1285,8 +1282,8 @@ pub(super) fn new(
     /// Construct a pattern that matches everything that starts with this constructor.
     /// For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get the pattern
     /// `Some(_)`.
-    pub(super) fn wild_from_ctor(pcx: PatCtxt<'_, 'p, 'tcx>, ctor: Constructor<'tcx>) -> Self {
-        let fields = Fields::wildcards(pcx.cx, pcx.ty, &ctor);
+    pub(super) fn wild_from_ctor(pcx: &PatCtxt<'_, 'p, 'tcx>, ctor: Constructor<'tcx>) -> Self {
+        let fields = Fields::wildcards(pcx, &ctor);
         DeconstructedPat::new(ctor, fields, pcx.ty, DUMMY_SP)
     }
 
@@ -1553,13 +1550,13 @@ pub(super) fn iter_fields<'a>(
     /// `other_ctor` can be different from `self.ctor`, but must be covered by it.
     pub(super) fn specialize<'a>(
         &'a self,
-        cx: &MatchCheckCtxt<'p, 'tcx>,
+        pcx: &PatCtxt<'_, 'p, 'tcx>,
         other_ctor: &Constructor<'tcx>,
     ) -> SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]> {
         match (&self.ctor, other_ctor) {
             (Wildcard, _) => {
                 // We return a wildcard for each field of `other_ctor`.
-                Fields::wildcards(cx, self.ty, other_ctor).iter_patterns().collect()
+                Fields::wildcards(pcx, other_ctor).iter_patterns().collect()
             }
             (Slice(self_slice), Slice(other_slice))
                 if self_slice.arity() != other_slice.arity() =>
@@ -1578,7 +1575,7 @@ pub(super) fn specialize<'a>(
                         let prefix = &self.fields.fields[..prefix];
                         let suffix = &self.fields.fields[self_slice.arity() - suffix..];
                         let wildcard: &_ =
-                            cx.pattern_arena.alloc(DeconstructedPat::wildcard(inner_ty));
+                            pcx.cx.pattern_arena.alloc(DeconstructedPat::wildcard(inner_ty));
                         let extra_wildcards = other_slice.arity() - self_slice.arity();
                         let extra_wildcards = (0..extra_wildcards).map(|_| wildcard);
                         prefix.iter().chain(extra_wildcards).chain(suffix).collect()
index 9e7a267ecbd7fc86dd9d057324d9595f21ac5b74..0a660ef30c88ee333bfc4cf6fc58bc77bc0b711a 100644 (file)
@@ -411,12 +411,12 @@ fn expand_or_pat<'a>(&'a self) -> impl Iterator<Item = PatStack<'p, 'tcx>> + Cap
     /// This is roughly the inverse of `Constructor::apply`.
     fn pop_head_constructor(
         &self,
-        cx: &MatchCheckCtxt<'p, 'tcx>,
+        pcx: &PatCtxt<'_, 'p, 'tcx>,
         ctor: &Constructor<'tcx>,
     ) -> PatStack<'p, 'tcx> {
         // We pop the head pattern and push the new fields extracted from the arguments of
         // `self.head()`.
-        let mut new_fields: SmallVec<[_; 2]> = self.head().specialize(cx, ctor);
+        let mut new_fields: SmallVec<[_; 2]> = self.head().specialize(pcx, ctor);
         new_fields.extend_from_slice(&self.pats[1..]);
         PatStack::from_vec(new_fields)
     }
@@ -469,13 +469,13 @@ fn heads<'a>(
     /// This computes `S(constructor, self)`. See top of the file for explanations.
     fn specialize_constructor(
         &self,
-        pcx: PatCtxt<'_, 'p, 'tcx>,
+        pcx: &PatCtxt<'_, 'p, 'tcx>,
         ctor: &Constructor<'tcx>,
     ) -> Matrix<'p, 'tcx> {
         let mut matrix = Matrix::empty();
         for row in &self.patterns {
             if ctor.is_covered_by(pcx, row.head().ctor()) {
-                let new_row = row.pop_head_constructor(pcx.cx, ctor);
+                let new_row = row.pop_head_constructor(pcx, ctor);
                 matrix.push(new_row);
             }
         }
@@ -575,7 +575,7 @@ fn extend(&mut self, other: Self) {
     /// with the results of specializing with the other constructors.
     fn apply_constructor(
         self,
-        pcx: PatCtxt<'_, 'p, 'tcx>,
+        pcx: &PatCtxt<'_, 'p, 'tcx>,
         matrix: &Matrix<'p, 'tcx>, // used to compute missing ctors
         ctor: &Constructor<'tcx>,
     ) -> Self {
@@ -713,7 +713,7 @@ fn single_pattern(self) -> DeconstructedPat<'p, 'tcx> {
     ///
     /// left_ty: struct X { a: (bool, &'static str), b: usize}
     /// pats: [(false, "foo"), 42]  => X { a: (false, "foo"), b: 42 }
-    fn apply_constructor(mut self, pcx: PatCtxt<'_, 'p, 'tcx>, ctor: &Constructor<'tcx>) -> Self {
+    fn apply_constructor(mut self, pcx: &PatCtxt<'_, 'p, 'tcx>, ctor: &Constructor<'tcx>) -> Self {
         let pat = {
             let len = self.0.len();
             let arity = ctor.arity(pcx);
@@ -786,7 +786,7 @@ fn is_useful<'p, 'tcx>(
     is_under_guard: bool,
     is_top_level: bool,
 ) -> Usefulness<'p, 'tcx> {
-    debug!("matrix,v={:?}{:?}", matrix, v);
+    debug!(?matrix, ?v);
     let Matrix { patterns: rows, .. } = matrix;
 
     // The base case. We are pattern-matching on () and the return value is
@@ -806,11 +806,6 @@ fn is_useful<'p, 'tcx>(
 
     debug_assert!(rows.iter().all(|r| r.len() == v.len()));
 
-    let ty = v.head().ty();
-    let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty);
-    debug!("v.head: {:?}, v.span: {:?}", v.head(), v.head().span());
-    let pcx = PatCtxt { cx, ty, span: v.head().span(), is_top_level, is_non_exhaustive };
-
     // If the first pattern is an or-pattern, expand it.
     let mut ret = Usefulness::new_not_useful(witness_preference);
     if v.head().is_or_pat() {
@@ -832,6 +827,11 @@ fn is_useful<'p, 'tcx>(
             }
         }
     } else {
+        let ty = v.head().ty();
+        let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty);
+        debug!("v.head: {:?}, v.span: {:?}", v.head(), v.head().span());
+        let pcx = &PatCtxt { cx, ty, span: v.head().span(), is_top_level, is_non_exhaustive };
+
         let v_ctor = v.head().ctor();
         debug!(?v_ctor);
         if let Constructor::IntRange(ctor_range) = &v_ctor {
@@ -853,7 +853,7 @@ fn is_useful<'p, 'tcx>(
             debug!("specialize({:?})", ctor);
             // We cache the result of `Fields::wildcards` because it is used a lot.
             let spec_matrix = start_matrix.specialize_constructor(pcx, &ctor);
-            let v = v.pop_head_constructor(cx, &ctor);
+            let v = v.pop_head_constructor(pcx, &ctor);
             let usefulness = ensure_sufficient_stack(|| {
                 is_useful(cx, &spec_matrix, &v, witness_preference, hir_id, is_under_guard, false)
             });
index e64136928cce8af34e7712b95160b7c993982a5d..21132eb991fd5c69fdeb25495bc3ef24660ee5be 100644 (file)
@@ -222,18 +222,6 @@ fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) {
     }
 }
 
-struct TransferWrapper<'a>(&'a mut ChunkedBitSet<Local>);
-
-impl<'a> GenKill<Local> for TransferWrapper<'a> {
-    fn gen(&mut self, l: Local) {
-        self.0.insert(l);
-    }
-
-    fn kill(&mut self, l: Local) {
-        self.0.remove(l);
-    }
-}
-
 impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
     fn apply_statement_effect(
         &self,
@@ -271,7 +259,7 @@ fn apply_statement_effect(
                 return;
             }
         }
-        TransferFunction(&mut TransferWrapper(trans)).visit_statement(statement, location);
+        TransferFunction(trans).visit_statement(statement, location);
     }
 
     fn apply_terminator_effect(
@@ -280,7 +268,7 @@ fn apply_terminator_effect(
         terminator: &mir::Terminator<'tcx>,
         location: Location,
     ) {
-        TransferFunction(&mut TransferWrapper(trans)).visit_terminator(terminator, location);
+        TransferFunction(trans).visit_terminator(terminator, location);
     }
 
     fn apply_call_return_effect(
index 611d29a4ee29a3400d60ed14f3cc47820cbf75b5..3378923c22c367c1a9396ab54e07d0ba3279e282 100644 (file)
@@ -33,7 +33,7 @@ pub struct DeleteNonCodegenStatements<'tcx> {
 impl<'tcx> MirPass<'tcx> for CleanupNonCodegenStatements {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let mut delete = DeleteNonCodegenStatements { tcx };
-        delete.visit_body(body);
+        delete.visit_body_preserves_cfg(body);
         body.user_type_annotations.raw.clear();
 
         for decl in &mut body.local_decls {
index 85ad6b8f2feff052b70b19c74fb2a3244a1f5226..98016659a05f7bc268938bbfc0d7a66fc98ed218 100644 (file)
@@ -18,9 +18,7 @@
 };
 use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
 use rustc_middle::ty::subst::{InternalSubsts, Subst};
-use rustc_middle::ty::{
-    self, ConstKind, EarlyBinder, Instance, ParamEnv, Ty, TyCtxt, TypeVisitable,
-};
+use rustc_middle::ty::{self, ConstKind, Instance, ParamEnv, Ty, TyCtxt, TypeVisitable};
 use rustc_span::{def_id::DefId, Span};
 use rustc_target::abi::{self, HasDataLayout, Size, TargetDataLayout};
 use rustc_target::spec::abi::Abi as CallAbi;
@@ -387,7 +385,7 @@ fn new(
         );
 
         let ret_layout = ecx
-            .layout_of(EarlyBinder(body.return_ty()).subst(tcx, substs))
+            .layout_of(body.bound_return_ty().subst(tcx, substs))
             .ok()
             // Don't bother allocating memory for large values.
             // I don't know how return types can seem to be unsized but this happens in the
@@ -953,7 +951,7 @@ fn tcx(&self) -> TyCtxt<'tcx> {
     }
 
     fn visit_body(&mut self, body: &mut Body<'tcx>) {
-        for (bb, data) in body.basic_blocks_mut().iter_enumerated_mut() {
+        for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() {
             self.visit_basic_block_data(bb, data);
         }
     }
index 3ae6a88a140ead840ecbe322b11078fa74ad0202..c2ea55af48a1e781e0ea83a6dab425a5d68d764d 100644 (file)
@@ -23,8 +23,7 @@
 use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
 use rustc_middle::ty::subst::{InternalSubsts, Subst};
 use rustc_middle::ty::{
-    self, ConstInt, ConstKind, EarlyBinder, Instance, ParamEnv, ScalarInt, Ty, TyCtxt,
-    TypeVisitable,
+    self, ConstInt, ConstKind, Instance, ParamEnv, ScalarInt, Ty, TyCtxt, TypeVisitable,
 };
 use rustc_session::lint;
 use rustc_span::Span;
@@ -196,7 +195,7 @@ fn new(
         );
 
         let ret_layout = ecx
-            .layout_of(EarlyBinder(body.return_ty()).subst(tcx, substs))
+            .layout_of(body.bound_return_ty().subst(tcx, substs))
             .ok()
             // Don't bother allocating memory for large values.
             // I don't know how return types can seem to be unsized but this happens in the
index a00bb16f7ac67c79c32c93c785beab9fb3b9a40c..87d7b664015a9cc939309be93584b7a2af9dcd8e 100644 (file)
@@ -90,7 +90,7 @@ pub fn deref_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
     let patch = MirPatch::new(body);
     let mut checker = DerefChecker { tcx, patcher: patch, local_decls: body.local_decls.clone() };
 
-    for (bb, data) in body.basic_blocks_mut().iter_enumerated_mut() {
+    for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() {
         checker.visit_basic_block_data(bb, data);
     }
 
index 44e3945d6fc8905e1b0bc5023cb7a52793ea16a2..7652223368964290d918b62377e173b57318992d 100644 (file)
@@ -70,7 +70,6 @@ fn visit_place(
                 build_ptr_tys(tcx, base_ty.boxed_ty(), self.unique_did, self.nonnull_did);
 
             let ptr_local = self.patch.new_temp(ptr_ty, source_info.span);
-            self.local_decls.push(LocalDecl::new(ptr_ty, source_info.span));
 
             self.patch.add_statement(location, StatementKind::StorageLive(ptr_local));
 
@@ -116,7 +115,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
                 ElaborateBoxDerefVisitor { tcx, unique_did, nonnull_did, local_decls, patch };
 
             for (block, BasicBlockData { statements, terminator, .. }) in
-                body.basic_blocks.as_mut().iter_enumerated_mut()
+                body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut()
             {
                 let mut index = 0;
                 for statement in statements {
@@ -125,13 +124,6 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
                     index += 1;
                 }
 
-                if let Some(terminator) = terminator
-                && !matches!(terminator.kind, TerminatorKind::Yield{..})
-                {
-                    let location = Location { block, statement_index: index };
-                    visitor.visit_terminator(terminator, location);
-                }
-
                 let location = Location { block, statement_index: index };
                 match terminator {
                     // yielding into a box is handled when lowering generators
index 40dc9fe9a05bb9964dbed5f24a60160076300b62..2a51af582f5854c35d21a27e42f4b583166305f6 100644 (file)
@@ -29,7 +29,6 @@
 use rustc_middle::mir::{traversal, Body, ConstQualifs, MirPass, MirPhase, Promoted};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, TyCtxt, TypeVisitable};
-use rustc_span::{Span, Symbol};
 
 #[macro_use]
 mod pass_manager;
@@ -159,14 +158,7 @@ struct GatherCtors<'a, 'tcx> {
         set: &'a mut FxIndexSet<LocalDefId>,
     }
     impl<'tcx> Visitor<'tcx> for GatherCtors<'_, 'tcx> {
-        fn visit_variant_data(
-            &mut self,
-            v: &'tcx hir::VariantData<'tcx>,
-            _: Symbol,
-            _: &'tcx hir::Generics<'tcx>,
-            _: hir::HirId,
-            _: Span,
-        ) {
+        fn visit_variant_data(&mut self, v: &'tcx hir::VariantData<'tcx>) {
             if let hir::VariantData::Tuple(_, hir_id) = *v {
                 self.set.insert(self.tcx.hir().local_def_id(hir_id));
             }
index bb063915f55a907f8119f617e9c20b5433481e82..42d732730ecccf0b38966919a1b7e16dd6512d20 100644 (file)
@@ -53,10 +53,10 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut mir::Body<'tcx>) {
             def_id, returned_local
         );
 
-        RenameToReturnPlace { tcx, to_rename: returned_local }.visit_body(body);
+        RenameToReturnPlace { tcx, to_rename: returned_local }.visit_body_preserves_cfg(body);
 
         // Clean up the `NOP`s we inserted for statements made useless by our renaming.
-        for block_data in body.basic_blocks_mut() {
+        for block_data in body.basic_blocks.as_mut_preserves_cfg() {
             block_data.statements.retain(|stmt| stmt.kind != mir::StatementKind::Nop);
         }
 
index 89808d3d4cdbd9c9056c358806eb64daf951f34c..5c441c5b194923e7f4ed8427378c054111fd7b50 100644 (file)
@@ -83,9 +83,9 @@ fn is_nop_landing_pad(
     fn remove_nop_landing_pads(&self, body: &mut Body<'_>) {
         debug!("body: {:#?}", body);
 
-        // make sure there's a single resume block
+        // make sure there's a resume block
         let resume_block = {
-            let patch = MirPatch::new(body);
+            let mut patch = MirPatch::new(body);
             let resume_block = patch.resume_block();
             patch.apply(body);
             resume_block
index 4919ad40098cb0f2ae58a211969cca08304d77c5..abe6cb285f50591be8776c03c25319eada650ead 100644 (file)
@@ -19,7 +19,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         }
 
         let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
-        RevealAllVisitor { tcx, param_env }.visit_body(body);
+        RevealAllVisitor { tcx, param_env }.visit_body_preserves_cfg(body);
     }
 }
 
index 180f4c7dcd6e80d1a1dac8e1c0f7c0623147ebff..7a6ca917d0ffd5ca2aac703c6fd31a56967d6320 100644 (file)
@@ -412,7 +412,7 @@ pub fn simplify_locals<'tcx>(body: &mut Body<'tcx>, tcx: TyCtxt<'tcx>) {
     if map.iter().any(Option::is_none) {
         // Update references to all vars and tmps now
         let mut updater = LocalUpdater { map, tcx };
-        updater.visit_body(body);
+        updater.visit_body_preserves_cfg(body);
 
         body.local_decls.shrink_to_fit();
     }
@@ -548,7 +548,7 @@ fn remove_unused_definitions(used_locals: &mut UsedLocals, body: &mut Body<'_>)
     while modified {
         modified = false;
 
-        for data in body.basic_blocks_mut() {
+        for data in body.basic_blocks.as_mut_preserves_cfg() {
             // Remove unnecessary StorageLive and StorageDead annotations.
             data.statements.retain(|statement| {
                 let keep = match &statement.kind {
index e9701ec2d7f456f3b85158c29f481b8be0539e91..848e142e59ce9b4dcc47b41a37fb4d46b073d330 100644 (file)
 
 use unescape_error_reporting::{emit_unescape_error, escaped_char};
 
+// This type is used a lot. Make sure it doesn't unintentionally get bigger.
+//
+// This assertion is in this crate, rather than in `rustc_lexer`, because that
+// crate cannot depend on `rustc_data_structures`.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+rustc_data_structures::static_assert_size!(rustc_lexer::Token, 12);
+
 #[derive(Clone, Debug)]
 pub struct UnmatchedBrace {
     pub expected_delim: Delimiter,
@@ -37,8 +44,7 @@ pub(crate) fn parse_token_trees<'a>(
     start_pos: BytePos,
     override_span: Option<Span>,
 ) -> (PResult<'a, TokenStream>, Vec<UnmatchedBrace>) {
-    StringReader { sess, start_pos, pos: start_pos, end_src_index: src.len(), src, override_span }
-        .into_token_trees()
+    StringReader { sess, start_pos, pos: start_pos, src, override_span }.into_token_trees()
 }
 
 struct StringReader<'a> {
@@ -47,8 +53,6 @@ struct StringReader<'a> {
     start_pos: BytePos,
     /// The absolute offset within the source_map of the current character.
     pos: BytePos,
-    /// Stop reading src at this index.
-    end_src_index: usize,
     /// Source text to tokenize.
     src: &'a str,
     override_span: Option<Span>,
@@ -64,20 +68,17 @@ fn next_token(&mut self) -> (Spacing, Token) {
         let mut spacing = Spacing::Joint;
 
         // Skip `#!` at the start of the file
-        let start_src_index = self.src_index(self.pos);
-        let text: &str = &self.src[start_src_index..self.end_src_index];
-        let is_beginning_of_file = self.pos == self.start_pos;
-        if is_beginning_of_file {
-            if let Some(shebang_len) = rustc_lexer::strip_shebang(text) {
-                self.pos = self.pos + BytePos::from_usize(shebang_len);
-                spacing = Spacing::Alone;
-            }
+        if self.pos == self.start_pos
+            && let Some(shebang_len) = rustc_lexer::strip_shebang(self.src)
+        {
+            self.pos = self.pos + BytePos::from_usize(shebang_len);
+            spacing = Spacing::Alone;
         }
 
         // Skip trivial (whitespace & comments) tokens
         loop {
             let start_src_index = self.src_index(self.pos);
-            let text: &str = &self.src[start_src_index..self.end_src_index];
+            let text: &str = &self.src[start_src_index..];
 
             if text.is_empty() {
                 let span = self.mk_sp(self.pos, self.pos);
@@ -87,7 +88,7 @@ fn next_token(&mut self) -> (Spacing, Token) {
             let token = rustc_lexer::first_token(text);
 
             let start = self.pos;
-            self.pos = self.pos + BytePos::from_usize(token.len);
+            self.pos = self.pos + BytePos(token.len);
 
             debug!("next_token: {:?}({:?})", token.kind, self.str_from(start));
 
@@ -239,7 +240,7 @@ fn cook_lexer_token(&self, token: rustc_lexer::TokenKind, start: BytePos) -> Opt
                 token::Ident(sym, false)
             }
             rustc_lexer::TokenKind::Literal { kind, suffix_start } => {
-                let suffix_start = start + BytePos(suffix_start as u32);
+                let suffix_start = start + BytePos(suffix_start);
                 let (kind, symbol) = self.cook_lexer_literal(start, suffix_start, kind);
                 let suffix = if suffix_start < self.pos {
                     let string = self.str_from(suffix_start);
@@ -404,15 +405,21 @@ fn cook_lexer_literal(
                 }
                 (token::ByteStr, Mode::ByteStr, 2, 1) // b" "
             }
-            rustc_lexer::LiteralKind::RawStr { n_hashes, err } => {
-                self.report_raw_str_error(start, err);
-                let n = u32::from(n_hashes);
-                (token::StrRaw(n_hashes), Mode::RawStr, 2 + n, 1 + n) // r##" "##
+            rustc_lexer::LiteralKind::RawStr { n_hashes } => {
+                if let Some(n_hashes) = n_hashes {
+                    let n = u32::from(n_hashes);
+                    (token::StrRaw(n_hashes), Mode::RawStr, 2 + n, 1 + n) // r##" "##
+                } else {
+                    self.report_raw_str_error(start, 1);
+                }
             }
-            rustc_lexer::LiteralKind::RawByteStr { n_hashes, err } => {
-                self.report_raw_str_error(start, err);
-                let n = u32::from(n_hashes);
-                (token::ByteStrRaw(n_hashes), Mode::RawByteStr, 3 + n, 1 + n) // br##" "##
+            rustc_lexer::LiteralKind::RawByteStr { n_hashes } => {
+                if let Some(n_hashes) = n_hashes {
+                    let n = u32::from(n_hashes);
+                    (token::ByteStrRaw(n_hashes), Mode::RawByteStr, 3 + n, 1 + n) // br##" "##
+                } else {
+                    self.report_raw_str_error(start, 2);
+                }
             }
             rustc_lexer::LiteralKind::Int { base, empty_int } => {
                 return if empty_int {
@@ -483,17 +490,17 @@ fn str_from_to(&self, start: BytePos, end: BytePos) -> &str {
         &self.src[self.src_index(start)..self.src_index(end)]
     }
 
-    fn report_raw_str_error(&self, start: BytePos, opt_err: Option<RawStrError>) {
-        match opt_err {
-            Some(RawStrError::InvalidStarter { bad_char }) => {
+    fn report_raw_str_error(&self, start: BytePos, prefix_len: u32) -> ! {
+        match rustc_lexer::validate_raw_str(self.str_from(start), prefix_len) {
+            Err(RawStrError::InvalidStarter { bad_char }) => {
                 self.report_non_started_raw_string(start, bad_char)
             }
-            Some(RawStrError::NoTerminator { expected, found, possible_terminator_offset }) => self
+            Err(RawStrError::NoTerminator { expected, found, possible_terminator_offset }) => self
                 .report_unterminated_raw_string(start, expected, possible_terminator_offset, found),
-            Some(RawStrError::TooManyDelimiters { found }) => {
+            Err(RawStrError::TooManyDelimiters { found }) => {
                 self.report_too_many_hashes(start, found)
             }
-            None => (),
+            Ok(()) => panic!("no error found for supposedly invalid raw string literal"),
         }
     }
 
@@ -510,9 +517,9 @@ fn report_non_started_raw_string(&self, start: BytePos, bad_char: char) -> ! {
     fn report_unterminated_raw_string(
         &self,
         start: BytePos,
-        n_hashes: usize,
-        possible_offset: Option<usize>,
-        found_terminators: usize,
+        n_hashes: u32,
+        possible_offset: Option<u32>,
+        found_terminators: u32,
     ) -> ! {
         let mut err = self.sess.span_diagnostic.struct_span_fatal_with_code(
             self.mk_sp(start, start),
@@ -525,7 +532,7 @@ fn report_unterminated_raw_string(
         if n_hashes > 0 {
             err.note(&format!(
                 "this raw string should be terminated with `\"{}`",
-                "#".repeat(n_hashes)
+                "#".repeat(n_hashes as usize)
             ));
         }
 
@@ -536,7 +543,7 @@ fn report_unterminated_raw_string(
             err.span_suggestion(
                 span,
                 "consider terminating the string here",
-                "#".repeat(n_hashes),
+                "#".repeat(n_hashes as usize),
                 Applicability::MaybeIncorrect,
             );
         }
@@ -637,7 +644,7 @@ fn report_unknown_prefix(&self, start: BytePos) {
         }
     }
 
-    fn report_too_many_hashes(&self, start: BytePos, found: usize) -> ! {
+    fn report_too_many_hashes(&self, start: BytePos, found: u32) -> ! {
         self.fatal_span_(
             start,
             self.pos,
index 0816bc8deb66f020df5a01b41f8d6ee3de52099c..aa70912dcde4c397c6c66baef1441025dbd95906 100644 (file)
@@ -277,6 +277,7 @@ struct TokenStreamBuilder {
 }
 
 impl TokenStreamBuilder {
+    #[inline(always)]
     fn push(&mut self, tree: TokenTree) {
         if let Some(TokenTree::Token(prev_token, Spacing::Joint)) = self.buf.last()
             && let TokenTree::Token(token, joint) = &tree
@@ -284,9 +285,9 @@ fn push(&mut self, tree: TokenTree) {
         {
             self.buf.pop();
             self.buf.push(TokenTree::Token(glued, *joint));
-            return;
+        } else {
+            self.buf.push(tree)
         }
-        self.buf.push(tree);
     }
 
     fn into_token_stream(self) -> TokenStream {
index 09329f18c679d7c93d596106ccf007d3a2be38c9..f4c6b33a529243872292cfc1cfe15575b602db4e 100644 (file)
@@ -19,7 +19,7 @@
 use rustc_errors::{
     fluent, Applicability, DiagnosticBuilder, DiagnosticMessage, Handler, MultiSpan, PResult,
 };
-use rustc_errors::{pluralize, struct_span_err, Diagnostic, EmissionGuarantee, ErrorGuaranteed};
+use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorGuaranteed};
 use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic};
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, Ident};
@@ -228,13 +228,13 @@ struct MultiSugg {
 }
 
 impl MultiSugg {
-    fn emit<G: EmissionGuarantee>(self, err: &mut DiagnosticBuilder<'_, G>) {
+    fn emit(self, err: &mut Diagnostic) {
         err.multipart_suggestion(&self.msg, self.patches, self.applicability);
     }
 
     /// Overrides individual messages and applicabilities.
-    fn emit_many<G: EmissionGuarantee>(
-        err: &mut DiagnosticBuilder<'_, G>,
+    fn emit_many(
+        err: &mut Diagnostic,
         msg: &str,
         applicability: Applicability,
         suggestions: impl Iterator<Item = Self>,
@@ -560,7 +560,8 @@ fn is_ident_eq_keyword(found: &TokenKind, expected: &TokenType) -> bool {
                     || (sm.is_multiline(
                         self.prev_token.span.shrink_to_hi().until(self.token.span.shrink_to_lo())
                     ) && t == &token::Pound)
-            }) {
+            }) && !expected.contains(&TokenType::Token(token::Comma))
+            {
                 // Missing semicolon typo. This is triggered if the next token could either start a
                 // new statement or is a block close. For example:
                 //
index c0f661f7dbbf9519d2af1981740608d48556c045..2880ef78c8d276b278057052904696ef131bd809 100644 (file)
@@ -850,7 +850,7 @@ fn parse_and_disallow_postfix_after_cast(
                     ExprKind::Index(_, _) => "indexing",
                     ExprKind::Try(_) => "`?`",
                     ExprKind::Field(_, _) => "a field access",
-                    ExprKind::MethodCall(_, _, _) => "a method call",
+                    ExprKind::MethodCall(_, _, _, _) => "a method call",
                     ExprKind::Call(_, _) => "a function call",
                     ExprKind::Await(_) => "`.await`",
                     ExprKind::Err => return Ok(with_postfix),
@@ -859,7 +859,7 @@ fn parse_and_disallow_postfix_after_cast(
             );
             let mut err = self.struct_span_err(span, &msg);
 
-            let suggest_parens = |err: &mut DiagnosticBuilder<'_, _>| {
+            let suggest_parens = |err: &mut Diagnostic| {
                 let suggestions = vec![
                     (span.shrink_to_lo(), "(".to_string()),
                     (span.shrink_to_hi(), ")".to_string()),
@@ -1258,8 +1258,11 @@ fn maybe_recover_struct_lit_bad_delims(
 
     /// Parse an indexing expression `expr[...]`.
     fn parse_index_expr(&mut self, lo: Span, base: P<Expr>) -> PResult<'a, P<Expr>> {
+        let prev_span = self.prev_token.span;
+        let open_delim_span = self.token.span;
         self.bump(); // `[`
         let index = self.parse_expr()?;
+        self.suggest_missing_semicolon_before_array(prev_span, open_delim_span)?;
         self.expect(&token::CloseDelim(Delimiter::Bracket))?;
         Ok(self.mk_expr(lo.to(self.prev_token.span), self.mk_index(base, index), AttrVec::new()))
     }
@@ -1277,12 +1280,14 @@ fn parse_dot_suffix(&mut self, self_arg: P<Expr>, lo: Span) -> PResult<'a, P<Exp
 
         if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
             // Method call `expr.f()`
-            let mut args = self.parse_paren_expr_seq()?;
-            args.insert(0, self_arg);
-
+            let args = self.parse_paren_expr_seq()?;
             let fn_span = fn_span_lo.to(self.prev_token.span);
             let span = lo.to(self.prev_token.span);
-            Ok(self.mk_expr(span, ExprKind::MethodCall(segment, args, fn_span), AttrVec::new()))
+            Ok(self.mk_expr(
+                span,
+                ExprKind::MethodCall(segment, self_arg, args, fn_span),
+                AttrVec::new(),
+            ))
         } else {
             // Field access `expr.f`
             if let Some(args) = segment.args {
@@ -1391,8 +1396,6 @@ fn parse_bottom_expr(&mut self) -> PResult<'a, P<Expr>> {
         } else if self.is_do_yeet() {
             self.parse_yeet_expr(attrs)
         } else if self.check_keyword(kw::Let) {
-            self.manage_let_chains_context();
-            self.bump();
             self.parse_let_expr(attrs)
         } else if self.eat_keyword(kw::Underscore) {
             Ok(self.mk_expr(self.prev_token.span, ExprKind::Underscore, attrs))
@@ -2058,6 +2061,45 @@ fn maybe_suggest_brackets_instead_of_braces(
         }
     }
 
+    fn suggest_missing_semicolon_before_array(
+        &self,
+        prev_span: Span,
+        open_delim_span: Span,
+    ) -> PResult<'a, ()> {
+        if self.token.kind == token::Comma {
+            let mut snapshot = self.create_snapshot_for_diagnostic();
+            snapshot.bump();
+            match snapshot.parse_seq_to_before_end(
+                &token::CloseDelim(Delimiter::Bracket),
+                SeqSep::trailing_allowed(token::Comma),
+                |p| p.parse_expr(),
+            ) {
+                Ok(_)
+                    // When the close delim is `)`, `token.kind` is expected to be `token::CloseDelim(Delimiter::Parenthesis)`,
+                    // but the actual `token.kind` is `token::CloseDelim(Delimiter::Bracket)`.
+                    // This is because the `token.kind` of the close delim is treated as the same as
+                    // that of the open delim in `TokenTreesReader::parse_token_tree`, even if the delimiters of them are different.
+                    // Therefore, `token.kind` should not be compared here.
+                    if snapshot
+                        .span_to_snippet(snapshot.token.span)
+                        .map_or(false, |snippet| snippet == "]") =>
+                {
+                    let mut err = self.struct_span_err(open_delim_span, "expected `;`, found `[`");
+                    err.span_suggestion_verbose(
+                        prev_span.shrink_to_hi(),
+                        "consider adding `;` here",
+                        ';',
+                        Applicability::MaybeIncorrect,
+                    );
+                    return Err(err);
+                }
+                Ok(_) => (),
+                Err(err) => err.cancel(),
+            }
+        }
+        Ok(())
+    }
+
     /// Parses a block or unsafe block.
     pub(super) fn parse_block_expr(
         &mut self,
@@ -2342,32 +2384,24 @@ fn error_missing_if_cond(
 
     /// Parses the condition of a `if` or `while` expression.
     fn parse_cond_expr(&mut self) -> PResult<'a, P<Expr>> {
-        self.with_let_management(true, |local_self| {
-            local_self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)
-        })
+        self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL | Restrictions::ALLOW_LET, None)
     }
 
-    // Checks if `let` is in an invalid position like `let x = let y = 1;` or
-    // if the current `let` is in a let_chains context but nested in another
-    // expression like `if let Some(_) = _opt && [1, 2, 3][let _ = ()] = 1`.
-    //
-    // This method expects that the current token is `let`.
-    fn manage_let_chains_context(&mut self) {
-        debug_assert!(matches!(self.token.kind, TokenKind::Ident(kw::Let, _)));
-        let is_in_a_let_chains_context_but_nested_in_other_expr = self.let_expr_allowed
-            && !matches!(
-                self.prev_token.kind,
-                TokenKind::AndAnd | TokenKind::Ident(kw::If, _) | TokenKind::Ident(kw::While, _)
-            );
-        if !self.let_expr_allowed || is_in_a_let_chains_context_but_nested_in_other_expr {
+    /// Parses a `let $pat = $expr` pseudo-expression.
+    fn parse_let_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
+        // This is a *approximate* heuristic that detects if `let` chains are
+        // being parsed in the right position. It's approximate because it
+        // doesn't deny all invalid `let` expressions, just completely wrong usages.
+        let not_in_chain = !matches!(
+            self.prev_token.kind,
+            TokenKind::AndAnd | TokenKind::Ident(kw::If, _) | TokenKind::Ident(kw::While, _)
+        );
+        if !self.restrictions.contains(Restrictions::ALLOW_LET) || not_in_chain {
             self.struct_span_err(self.token.span, "expected expression, found `let` statement")
                 .emit();
         }
-    }
 
-    /// Parses a `let $pat = $expr` pseudo-expression.
-    /// The `let` token has already been eaten.
-    fn parse_let_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
+        self.bump(); // Eat `let` token
         let lo = self.prev_token.span;
         let pat = self.parse_pat_allow_top_alt(
             None,
@@ -2687,7 +2721,9 @@ pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> {
         // `&&` tokens.
         fn check_let_expr(expr: &Expr) -> bool {
             match expr.kind {
-                ExprKind::Binary(_, ref lhs, ref rhs) => check_let_expr(lhs) || check_let_expr(rhs),
+                ExprKind::Binary(BinOp { node: BinOpKind::And, .. }, ref lhs, ref rhs) => {
+                    check_let_expr(lhs) || check_let_expr(rhs)
+                }
                 ExprKind::Let(..) => true,
                 _ => false,
             }
@@ -2703,9 +2739,8 @@ fn check_let_expr(expr: &Expr) -> bool {
             )?;
             let guard = if this.eat_keyword(kw::If) {
                 let if_span = this.prev_token.span;
-                let cond = this.with_let_management(true, |local_this| local_this.parse_expr())?;
-                let has_let_expr = check_let_expr(&cond);
-                if has_let_expr {
+                let cond = this.parse_expr_res(Restrictions::ALLOW_LET, None)?;
+                if check_let_expr(&cond) {
                     let span = if_span.to(cond.span);
                     this.sess.gated_spans.gate(sym::if_let_guard, span);
                 }
@@ -3279,17 +3314,4 @@ fn collect_tokens_for_expr(
             Ok((res, trailing))
         })
     }
-
-    // Calls `f` with the internal `let_expr_allowed` set to `let_expr_allowed` and then
-    // sets the internal `let_expr_allowed` back to its original value.
-    fn with_let_management<T>(
-        &mut self,
-        let_expr_allowed: bool,
-        f: impl FnOnce(&mut Self) -> T,
-    ) -> T {
-        let last_let_expr_allowed = mem::replace(&mut self.let_expr_allowed, let_expr_allowed);
-        let rslt = f(self);
-        self.let_expr_allowed = last_let_expr_allowed;
-        rslt
-    }
 }
index 2c1e5807aa7f9a7ef656e9e4fcd75a77462ea677..72c23776d339918c69e565fae592b2c287ce6271 100644 (file)
@@ -271,7 +271,10 @@ fn parse_item_kind(
             // MACRO_RULES ITEM
             self.parse_item_macro_rules(vis, has_bang)?
         } else if self.isnt_macro_invocation()
-            && (self.token.is_ident_named(sym::import) || self.token.is_ident_named(sym::using))
+            && (self.token.is_ident_named(sym::import)
+                || self.token.is_ident_named(sym::using)
+                || self.token.is_ident_named(sym::include)
+                || self.token.is_ident_named(sym::require))
         {
             return self.recover_import_as_use();
         } else if self.isnt_macro_invocation() && vis.kind.is_pub() {
@@ -1179,10 +1182,11 @@ fn parse_item_global(
 
         // Parse the type of a `const` or `static mut?` item.
         // That is, the `":" $ty` fragment.
-        let ty = if self.eat(&token::Colon) {
-            self.parse_ty()?
-        } else {
-            self.recover_missing_const_type(id, m)
+        let ty = match (self.eat(&token::Colon), self.check(&token::Eq) | self.check(&token::Semi))
+        {
+            // If there wasn't a `:` or the colon was followed by a `=` or `;` recover a missing type.
+            (true, false) => self.parse_ty()?,
+            (colon, _) => self.recover_missing_const_type(colon, m),
         };
 
         let expr = if self.eat(&token::Eq) { Some(self.parse_expr()?) } else { None };
@@ -1190,9 +1194,9 @@ fn parse_item_global(
         Ok((id, ty, expr))
     }
 
-    /// We were supposed to parse `:` but the `:` was missing.
+    /// We were supposed to parse `":" $ty` but the `:` or the type was missing.
     /// This means that the type is missing.
-    fn recover_missing_const_type(&mut self, id: Ident, m: Option<Mutability>) -> P<Ty> {
+    fn recover_missing_const_type(&mut self, colon_present: bool, m: Option<Mutability>) -> P<Ty> {
         // Construct the error and stash it away with the hope
         // that typeck will later enrich the error with a type.
         let kind = match m {
@@ -1200,22 +1204,48 @@ fn recover_missing_const_type(&mut self, id: Ident, m: Option<Mutability>) -> P<
             Some(Mutability::Not) => "static",
             None => "const",
         };
-        let mut err = self.struct_span_err(id.span, &format!("missing type for `{kind}` item"));
+
+        let colon = match colon_present {
+            true => "",
+            false => ":",
+        };
+
+        let span = self.prev_token.span.shrink_to_hi();
+        let mut err = self.struct_span_err(span, &format!("missing type for `{kind}` item"));
         err.span_suggestion(
-            id.span,
+            span,
             "provide a type for the item",
-            format!("{id}: <type>"),
+            format!("{colon} <type>"),
             Applicability::HasPlaceholders,
         );
-        err.stash(id.span, StashKey::ItemNoType);
+        err.stash(span, StashKey::ItemNoType);
 
         // The user intended that the type be inferred,
         // so treat this as if the user wrote e.g. `const A: _ = expr;`.
-        P(Ty { kind: TyKind::Infer, span: id.span, id: ast::DUMMY_NODE_ID, tokens: None })
+        P(Ty { kind: TyKind::Infer, span, id: ast::DUMMY_NODE_ID, tokens: None })
     }
 
     /// Parses an enum declaration.
     fn parse_item_enum(&mut self) -> PResult<'a, ItemInfo> {
+        if self.token.is_keyword(kw::Struct) {
+            let mut err = self.struct_span_err(
+                self.prev_token.span.to(self.token.span),
+                "`enum` and `struct` are mutually exclusive",
+            );
+            err.span_suggestion(
+                self.prev_token.span.to(self.token.span),
+                "replace `enum struct` with",
+                "enum",
+                Applicability::MachineApplicable,
+            );
+            if self.look_ahead(1, |t| t.is_ident()) {
+                self.bump();
+                err.emit();
+            } else {
+                return Err(err);
+            }
+        }
+
         let id = self.parse_ident()?;
         let mut generics = self.parse_generics()?;
         generics.where_clause = self.parse_where_clause()?;
index 1ac8b224248de1d932ed05977472cf48c25206a7..c088b6e1e0e2e36d688e34fde184e16a33963603 100644 (file)
@@ -47,6 +47,7 @@ struct Restrictions: u8 {
         const STMT_EXPR         = 1 << 0;
         const NO_STRUCT_LITERAL = 1 << 1;
         const CONST_EXPR        = 1 << 2;
+        const ALLOW_LET         = 1 << 3;
     }
 }
 
@@ -147,15 +148,12 @@ pub struct Parser<'a> {
     /// This allows us to recover when the user forget to add braces around
     /// multiple statements in the closure body.
     pub current_closure: Option<ClosureSpans>,
-    /// Used to track where `let`s are allowed. For example, `if true && let 1 = 1` is valid
-    /// but `[1, 2, 3][let _ = ()]` is not.
-    let_expr_allowed: bool,
 }
 
 // This type is used a lot, e.g. it's cloned when matching many declarative macro rules. Make sure
 // it doesn't unintentionally get bigger.
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Parser<'_>, 336);
+rustc_data_structures::static_assert_size!(Parser<'_>, 328);
 
 /// Stores span information about a closure.
 #[derive(Clone)]
@@ -462,7 +460,6 @@ pub fn new(
                 inner_attr_ranges: Default::default(),
             },
             current_closure: None,
-            let_expr_allowed: false,
         };
 
         // Make parser point to the first token.
@@ -1298,7 +1295,11 @@ pub fn parse_visibility(&mut self, fbt: FollowedByType) -> PResult<'a, Visibilit
                 self.bump(); // `in`
                 let path = self.parse_path(PathStyle::Mod)?; // `path`
                 self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)`
-                let vis = VisibilityKind::Restricted { path: P(path), id: ast::DUMMY_NODE_ID };
+                let vis = VisibilityKind::Restricted {
+                    path: P(path),
+                    id: ast::DUMMY_NODE_ID,
+                    shorthand: false,
+                };
                 return Ok(Visibility {
                     span: lo.to(self.prev_token.span),
                     kind: vis,
@@ -1311,7 +1312,11 @@ pub fn parse_visibility(&mut self, fbt: FollowedByType) -> PResult<'a, Visibilit
                 self.bump(); // `(`
                 let path = self.parse_path(PathStyle::Mod)?; // `crate`/`super`/`self`
                 self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)`
-                let vis = VisibilityKind::Restricted { path: P(path), id: ast::DUMMY_NODE_ID };
+                let vis = VisibilityKind::Restricted {
+                    path: P(path),
+                    id: ast::DUMMY_NODE_ID,
+                    shorthand: true,
+                };
                 return Ok(Visibility {
                     span: lo.to(self.prev_token.span),
                     kind: vis,
index 5deb17b8651b6dedbee40a2202455b6b5a48e99b..4890fade50faf8ef6ec57c673d82fd3ab3f80762 100644 (file)
@@ -70,6 +70,9 @@ pub enum Piece<'a> {
 pub struct Argument<'a> {
     /// Where to find this argument
     pub position: Position<'a>,
+    /// The span of the position indicator. Includes any whitespace in implicit
+    /// positions (`{  }`).
+    pub position_span: InnerSpan,
     /// How to format the argument
     pub format: FormatSpec<'a>,
 }
@@ -105,9 +108,9 @@ pub enum Position<'a> {
     /// The argument is implied to be located at an index
     ArgumentImplicitlyIs(usize),
     /// The argument is located at a specific index given in the format,
-    ArgumentIs(usize, Option<InnerSpan>),
+    ArgumentIs(usize),
     /// The argument has a name.
-    ArgumentNamed(&'a str, InnerSpan),
+    ArgumentNamed(&'a str),
 }
 
 impl Position<'_> {
@@ -172,6 +175,7 @@ pub struct ParseError {
     pub label: string::String,
     pub span: InnerSpan,
     pub secondary_label: Option<(string::String, InnerSpan)>,
+    pub should_be_replaced_with_positional_argument: bool,
 }
 
 /// The parser structure for interpreting the input format string. This is
@@ -216,14 +220,15 @@ fn next(&mut self) -> Option<Piece<'a>> {
                 '{' => {
                     let curr_last_brace = self.last_opening_brace;
                     let byte_pos = self.to_span_index(pos);
-                    self.last_opening_brace = Some(byte_pos.to(InnerOffset(byte_pos.0 + 1)));
+                    let lbrace_end = InnerOffset(byte_pos.0 + 1);
+                    self.last_opening_brace = Some(byte_pos.to(lbrace_end));
                     self.cur.next();
                     if self.consume('{') {
                         self.last_opening_brace = curr_last_brace;
 
                         Some(String(self.string(pos + 1)))
                     } else {
-                        let arg = self.argument();
+                        let arg = self.argument(lbrace_end);
                         if let Some(rbrace_byte_idx) = self.must_consume('}') {
                             let lbrace_inner_offset = self.to_span_index(pos);
                             let rbrace_inner_offset = self.to_span_index(rbrace_byte_idx);
@@ -232,6 +237,8 @@ fn next(&mut self) -> Option<Piece<'a>> {
                                     lbrace_inner_offset.to(InnerOffset(rbrace_inner_offset.0 + 1)),
                                 );
                             }
+                        } else {
+                            self.suggest_positional_arg_instead_of_captured_arg(arg);
                         }
                         Some(NextArgument(arg))
                     }
@@ -309,6 +316,7 @@ fn err<S1: Into<string::String>, S2: Into<string::String>>(
             label: label.into(),
             span,
             secondary_label: None,
+            should_be_replaced_with_positional_argument: false,
         });
     }
 
@@ -332,6 +340,7 @@ fn err_with_note<
             label: label.into(),
             span,
             secondary_label: None,
+            should_be_replaced_with_positional_argument: false,
         });
     }
 
@@ -403,6 +412,7 @@ fn must_consume(&mut self, c: char) -> Option<usize> {
                     label,
                     span: pos.to(pos),
                     secondary_label,
+                    should_be_replaced_with_positional_argument: false,
                 });
                 None
             }
@@ -430,6 +440,7 @@ fn must_consume(&mut self, c: char) -> Option<usize> {
                     label,
                     span: pos.to(pos),
                     secondary_label,
+                    should_be_replaced_with_positional_argument: false,
                 });
             } else {
                 self.err(description, format!("expected `{:?}`", c), pos.to(pos));
@@ -477,8 +488,16 @@ fn string(&mut self, start: usize) -> &'a str {
     }
 
     /// Parses an `Argument` structure, or what's contained within braces inside the format string.
-    fn argument(&mut self) -> Argument<'a> {
+    fn argument(&mut self, start: InnerOffset) -> Argument<'a> {
         let pos = self.position();
+
+        let end = self
+            .cur
+            .clone()
+            .find(|(_, ch)| !ch.is_whitespace())
+            .map_or(start, |(end, _)| self.to_span_index(end));
+        let position_span = start.to(end);
+
         let format = match self.mode {
             ParseMode::Format => self.format(),
             ParseMode::InlineAsm => self.inline_asm(),
@@ -494,7 +513,7 @@ fn argument(&mut self) -> Argument<'a> {
             }
         };
 
-        Argument { position: pos, format }
+        Argument { position: pos, position_span, format }
     }
 
     /// Parses a positional argument for a format. This could either be an
@@ -502,23 +521,11 @@ fn argument(&mut self) -> Argument<'a> {
     /// Returns `Some(parsed_position)` if the position is not implicitly
     /// consuming a macro argument, `None` if it's the case.
     fn position(&mut self) -> Option<Position<'a>> {
-        let start_position = self.cur.peek().map(|item| item.0);
         if let Some(i) = self.integer() {
-            let inner_span = start_position.and_then(|start| {
-                self.cur
-                    .peek()
-                    .cloned()
-                    .and_then(|item| Some(self.to_span_index(start).to(self.to_span_index(item.0))))
-            });
-            Some(ArgumentIs(i, inner_span))
+            Some(ArgumentIs(i))
         } else {
             match self.cur.peek() {
-                Some(&(start, c)) if rustc_lexer::is_id_start(c) => {
-                    let word = self.word();
-                    let end = start + word.len();
-                    let span = self.to_span_index(start).to(self.to_span_index(end));
-                    Some(ArgumentNamed(word, span))
-                }
+                Some(&(_, c)) if rustc_lexer::is_id_start(c) => Some(ArgumentNamed(self.word())),
 
                 // This is an `ArgumentNext`.
                 // Record the fact and do the resolution after parsing the
@@ -750,6 +757,34 @@ fn integer(&mut self) -> Option<usize> {
         }
         if found { Some(cur) } else { None }
     }
+
+    fn suggest_positional_arg_instead_of_captured_arg(&mut self, arg: Argument<'a>) {
+        if let Some(end) = self.consume_pos('.') {
+            let byte_pos = self.to_span_index(end);
+            let start = InnerOffset(byte_pos.0 + 1);
+            let field = self.argument(start);
+            // We can only parse `foo.bar` field access, any deeper nesting,
+            // or another type of expression, like method calls, are not supported
+            if !self.consume('}') {
+                return;
+            }
+            if let ArgumentNamed(_) = arg.position {
+                if let ArgumentNamed(_) = field.position {
+                    self.errors.insert(
+                        0,
+                        ParseError {
+                            description: "field access isn't supported".to_string(),
+                            note: None,
+                            label: "not supported".to_string(),
+                            span: InnerSpan::new(arg.position_span.start, field.position_span.end),
+                            secondary_label: None,
+                            should_be_replaced_with_positional_argument: true,
+                        },
+                    );
+                }
+            }
+        }
+    }
 }
 
 /// Finds the indices of all characters that have been processed and differ between the actual
index a98f816644bd69a93abd68fa535de67e67532bb8..578530696105d5595e6ae4e5a324af849f2a0c11 100644 (file)
@@ -58,14 +58,22 @@ fn invalid06() {
 
 #[test]
 fn format_nothing() {
-    same("{}", &[NextArgument(Argument { position: ArgumentImplicitlyIs(0), format: fmtdflt() })]);
+    same(
+        "{}",
+        &[NextArgument(Argument {
+            position: ArgumentImplicitlyIs(0),
+            position_span: InnerSpan { start: 2, end: 2 },
+            format: fmtdflt(),
+        })],
+    );
 }
 #[test]
 fn format_position() {
     same(
         "{3}",
         &[NextArgument(Argument {
-            position: ArgumentIs(3, Some(InnerSpan { start: 2, end: 3 })),
+            position: ArgumentIs(3),
+            position_span: InnerSpan { start: 2, end: 3 },
             format: fmtdflt(),
         })],
     );
@@ -75,17 +83,30 @@ fn format_position_nothing_else() {
     same(
         "{3:}",
         &[NextArgument(Argument {
-            position: ArgumentIs(3, Some(InnerSpan { start: 2, end: 3 })),
+            position: ArgumentIs(3),
+            position_span: InnerSpan { start: 2, end: 3 },
             format: fmtdflt(),
         })],
     );
 }
 #[test]
+fn format_named() {
+    same(
+        "{name}",
+        &[NextArgument(Argument {
+            position: ArgumentNamed("name"),
+            position_span: InnerSpan { start: 2, end: 6 },
+            format: fmtdflt(),
+        })],
+    )
+}
+#[test]
 fn format_type() {
     same(
         "{3:x}",
         &[NextArgument(Argument {
-            position: ArgumentIs(3, Some(InnerSpan { start: 2, end: 3 })),
+            position: ArgumentIs(3),
+            position_span: InnerSpan { start: 2, end: 3 },
             format: FormatSpec {
                 fill: None,
                 align: AlignUnknown,
@@ -105,7 +126,8 @@ fn format_align_fill() {
     same(
         "{3:>}",
         &[NextArgument(Argument {
-            position: ArgumentIs(3, Some(InnerSpan { start: 2, end: 3 })),
+            position: ArgumentIs(3),
+            position_span: InnerSpan { start: 2, end: 3 },
             format: FormatSpec {
                 fill: None,
                 align: AlignRight,
@@ -122,7 +144,8 @@ fn format_align_fill() {
     same(
         "{3:0<}",
         &[NextArgument(Argument {
-            position: ArgumentIs(3, Some(InnerSpan { start: 2, end: 3 })),
+            position: ArgumentIs(3),
+            position_span: InnerSpan { start: 2, end: 3 },
             format: FormatSpec {
                 fill: Some('0'),
                 align: AlignLeft,
@@ -139,7 +162,8 @@ fn format_align_fill() {
     same(
         "{3:*<abcd}",
         &[NextArgument(Argument {
-            position: ArgumentIs(3, Some(InnerSpan { start: 2, end: 3 })),
+            position: ArgumentIs(3),
+            position_span: InnerSpan { start: 2, end: 3 },
             format: FormatSpec {
                 fill: Some('*'),
                 align: AlignLeft,
@@ -160,6 +184,7 @@ fn format_counts() {
         "{:10x}",
         &[NextArgument(Argument {
             position: ArgumentImplicitlyIs(0),
+            position_span: InnerSpan { start: 2, end: 2 },
             format: FormatSpec {
                 fill: None,
                 align: AlignUnknown,
@@ -177,6 +202,7 @@ fn format_counts() {
         "{:10$.10x}",
         &[NextArgument(Argument {
             position: ArgumentImplicitlyIs(0),
+            position_span: InnerSpan { start: 2, end: 2 },
             format: FormatSpec {
                 fill: None,
                 align: AlignUnknown,
@@ -193,7 +219,8 @@ fn format_counts() {
     same(
         "{1:0$.10x}",
         &[NextArgument(Argument {
-            position: ArgumentIs(1, Some(InnerSpan { start: 2, end: 3 })),
+            position: ArgumentIs(1),
+            position_span: InnerSpan { start: 2, end: 3 },
             format: FormatSpec {
                 fill: None,
                 align: AlignUnknown,
@@ -211,6 +238,7 @@ fn format_counts() {
         "{:.*x}",
         &[NextArgument(Argument {
             position: ArgumentImplicitlyIs(1),
+            position_span: InnerSpan { start: 2, end: 2 },
             format: FormatSpec {
                 fill: None,
                 align: AlignUnknown,
@@ -228,6 +256,7 @@ fn format_counts() {
         "{:.10$x}",
         &[NextArgument(Argument {
             position: ArgumentImplicitlyIs(0),
+            position_span: InnerSpan { start: 2, end: 2 },
             format: FormatSpec {
                 fill: None,
                 align: AlignUnknown,
@@ -245,6 +274,7 @@ fn format_counts() {
         "{:a$.b$?}",
         &[NextArgument(Argument {
             position: ArgumentImplicitlyIs(0),
+            position_span: InnerSpan { start: 2, end: 2 },
             format: FormatSpec {
                 fill: None,
                 align: AlignUnknown,
@@ -265,6 +295,7 @@ fn format_flags() {
         "{:-}",
         &[NextArgument(Argument {
             position: ArgumentImplicitlyIs(0),
+            position_span: InnerSpan { start: 2, end: 2 },
             format: FormatSpec {
                 fill: None,
                 align: AlignUnknown,
@@ -282,6 +313,7 @@ fn format_flags() {
         "{:+#}",
         &[NextArgument(Argument {
             position: ArgumentImplicitlyIs(0),
+            position_span: InnerSpan { start: 2, end: 2 },
             format: FormatSpec {
                 fill: None,
                 align: AlignUnknown,
@@ -303,7 +335,8 @@ fn format_mixture() {
         &[
             String("abcd "),
             NextArgument(Argument {
-                position: ArgumentIs(3, Some(InnerSpan { start: 7, end: 8 })),
+                position: ArgumentIs(3),
+                position_span: InnerSpan { start: 7, end: 8 },
                 format: FormatSpec {
                     fill: None,
                     align: AlignUnknown,
@@ -320,3 +353,22 @@ fn format_mixture() {
         ],
     );
 }
+#[test]
+fn format_whitespace() {
+    same(
+        "{ }",
+        &[NextArgument(Argument {
+            position: ArgumentImplicitlyIs(0),
+            position_span: InnerSpan { start: 2, end: 3 },
+            format: fmtdflt(),
+        })],
+    );
+    same(
+        "{  }",
+        &[NextArgument(Argument {
+            position: ArgumentImplicitlyIs(0),
+            position_span: InnerSpan { start: 2, end: 4 },
+            format: fmtdflt(),
+        })],
+    );
+}
index fde12b9eee6b92d0ed4eee7f53f7f758ada4a020..f75fffb6871f73aed9194c51de005b04c80da836 100644 (file)
@@ -53,7 +53,7 @@ pub(crate) fn target_from_impl_item<'tcx>(
 #[derive(Clone, Copy)]
 enum ItemLike<'tcx> {
     Item(&'tcx Item<'tcx>),
-    ForeignItem(&'tcx ForeignItem<'tcx>),
+    ForeignItem,
 }
 
 struct CheckAttrVisitor<'tcx> {
@@ -146,6 +146,7 @@ fn check_attributes(
                 | sym::stable
                 | sym::rustc_allowed_through_unstable_modules
                 | sym::rustc_promotable => self.check_stability_promotable(&attr, span, target),
+                sym::link_ordinal => self.check_link_ordinal(&attr, span, target),
                 _ => true,
             };
             is_valid &= attr_is_valid;
@@ -209,7 +210,14 @@ fn check_attributes(
         }
 
         // FIXME(@lcnr): this doesn't belong here.
-        if matches!(target, Target::Closure | Target::Fn | Target::Method(_) | Target::ForeignFn) {
+        if matches!(
+            target,
+            Target::Closure
+                | Target::Fn
+                | Target::Method(_)
+                | Target::ForeignFn
+                | Target::ForeignStatic
+        ) {
             self.tcx.ensure().codegen_fn_attrs(self.tcx.hir().local_def_id(hir_id));
         }
 
@@ -596,8 +604,6 @@ fn check_doc_alias_value(
 
         let span = meta.span();
         if let Some(location) = match target {
-            Target::Impl => Some("implementation block"),
-            Target::ForeignMod => Some("extern block"),
             Target::AssocTy => {
                 let parent_hir_id = self.tcx.hir().get_parent_item(hir_id);
                 let containing_item = self.tcx.hir().expect_item(parent_hir_id);
@@ -619,7 +625,34 @@ fn check_doc_alias_value(
             }
             // we check the validity of params elsewhere
             Target::Param => return false,
-            _ => None,
+            Target::Expression
+            | Target::Statement
+            | Target::Arm
+            | Target::ForeignMod
+            | Target::Closure
+            | Target::Impl => Some(target.name()),
+            Target::ExternCrate
+            | Target::Use
+            | Target::Static
+            | Target::Const
+            | Target::Fn
+            | Target::Mod
+            | Target::GlobalAsm
+            | Target::TyAlias
+            | Target::OpaqueTy
+            | Target::Enum
+            | Target::Variant
+            | Target::Struct
+            | Target::Field
+            | Target::Union
+            | Target::Trait
+            | Target::TraitAlias
+            | Target::Method(..)
+            | Target::ForeignFn
+            | Target::ForeignStatic
+            | Target::ForeignTy
+            | Target::GenericParam(..)
+            | Target::MacroDef => None,
         } {
             tcx.sess.emit_err(errors::DocAliasBadLocation { span, attr_str, location });
             return false;
@@ -1861,6 +1894,16 @@ fn check_stability_promotable(&self, attr: &Attribute, _span: Span, target: Targ
         }
     }
 
+    fn check_link_ordinal(&self, attr: &Attribute, _span: Span, target: Target) -> bool {
+        match target {
+            Target::ForeignFn | Target::ForeignStatic => true,
+            _ => {
+                self.tcx.sess.emit_err(errors::LinkOrdinal { attr_span: attr.span });
+                false
+            }
+        }
+    }
+
     fn check_deprecated(&self, hir_id: HirId, attr: &Attribute, _span: Span, target: Target) {
         match target {
             Target::Closure | Target::Expression | Target::Statement | Target::Arm => {
@@ -1995,12 +2038,7 @@ fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) {
 
     fn visit_foreign_item(&mut self, f_item: &'tcx ForeignItem<'tcx>) {
         let target = Target::from_foreign_item(f_item);
-        self.check_attributes(
-            f_item.hir_id(),
-            f_item.span,
-            target,
-            Some(ItemLike::ForeignItem(f_item)),
-        );
+        self.check_attributes(f_item.hir_id(), f_item.span, target, Some(ItemLike::ForeignItem));
         intravisit::walk_foreign_item(self, f_item)
     }
 
@@ -2028,14 +2066,9 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
         intravisit::walk_expr(self, expr)
     }
 
-    fn visit_variant(
-        &mut self,
-        variant: &'tcx hir::Variant<'tcx>,
-        generics: &'tcx hir::Generics<'tcx>,
-        item_id: HirId,
-    ) {
+    fn visit_variant(&mut self, variant: &'tcx hir::Variant<'tcx>) {
         self.check_attributes(variant.id, variant.span, Target::Variant, None);
-        intravisit::walk_variant(self, variant, generics, item_id)
+        intravisit::walk_variant(self, variant)
     }
 
     fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
index f1a81b65329afe29529971d16a70c7ea13b0490d..70518284cf91439ce218819084e699fcb79d59c9 100644 (file)
@@ -97,7 +97,7 @@ fn const_check_violated(&self, expr: NonConstExpr, span: Span) {
 
             // If the function belongs to a trait, then it must enable the const_trait_impl
             // feature to use that trait function (with a const default body).
-            if tcx.trait_of_item(def_id).is_some() {
+            if tcx.trait_of_item(def_id.to_def_id()).is_some() {
                 return true;
             }
 
index 58c5e5b4dfe533a0109dac583954e12ca817d535..625c854ea77a5dd7363aff05d995751edc5bf220 100644 (file)
@@ -4,7 +4,7 @@
 
 use itertools::Itertools;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_errors::{pluralize, MultiSpan};
+use rustc_errors::{pluralize, Applicability, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -42,6 +42,7 @@ struct MarkSymbolVisitor<'tcx> {
     maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>,
     live_symbols: FxHashSet<LocalDefId>,
     repr_has_repr_c: bool,
+    repr_has_repr_simd: bool,
     in_pat: bool,
     ignore_variant_stack: Vec<DefId>,
     // maps from tuple struct constructors to tuple struct items
@@ -220,6 +221,32 @@ fn handle_field_pattern_match(
         }
     }
 
+    fn handle_tuple_field_pattern_match(
+        &mut self,
+        lhs: &hir::Pat<'_>,
+        res: Res,
+        pats: &[hir::Pat<'_>],
+        dotdot: Option<usize>,
+    ) {
+        let variant = match self.typeck_results().node_type(lhs.hir_id).kind() {
+            ty::Adt(adt, _) => adt.variant_of_res(res),
+            _ => span_bug!(lhs.span, "non-ADT in tuple struct pattern"),
+        };
+        let first_n = pats.iter().enumerate().take(dotdot.unwrap_or(pats.len()));
+        let missing = variant.fields.len() - pats.len();
+        let last_n = pats
+            .iter()
+            .enumerate()
+            .skip(dotdot.unwrap_or(pats.len()))
+            .map(|(idx, pat)| (idx + missing, pat));
+        for (idx, pat) in first_n.chain(last_n) {
+            if let PatKind::Wild = pat.kind {
+                continue;
+            }
+            self.insert_def_id(variant.fields[idx].did);
+        }
+    }
+
     fn mark_live_symbols(&mut self) {
         let mut scanned = FxHashSet::default();
         while let Some(id) = self.worklist.pop() {
@@ -274,12 +301,15 @@ fn visit_node(&mut self, node: Node<'tcx>) {
         }
 
         let had_repr_c = self.repr_has_repr_c;
+        let had_repr_simd = self.repr_has_repr_simd;
         self.repr_has_repr_c = false;
+        self.repr_has_repr_simd = false;
         match node {
             Node::Item(item) => match item.kind {
                 hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => {
                     let def = self.tcx.adt_def(item.def_id);
                     self.repr_has_repr_c = def.repr().c();
+                    self.repr_has_repr_simd = def.repr().simd();
 
                     intravisit::walk_item(self, &item)
                 }
@@ -315,6 +345,7 @@ fn visit_node(&mut self, node: Node<'tcx>) {
             }
             _ => {}
         }
+        self.repr_has_repr_simd = had_repr_simd;
         self.repr_has_repr_c = had_repr_c;
     }
 
@@ -337,19 +368,13 @@ fn visit_nested_body(&mut self, body: hir::BodyId) {
         self.maybe_typeck_results = old_maybe_typeck_results;
     }
 
-    fn visit_variant_data(
-        &mut self,
-        def: &'tcx hir::VariantData<'tcx>,
-        _: Symbol,
-        _: &hir::Generics<'_>,
-        _: hir::HirId,
-        _: rustc_span::Span,
-    ) {
+    fn visit_variant_data(&mut self, def: &'tcx hir::VariantData<'tcx>) {
         let tcx = self.tcx;
         let has_repr_c = self.repr_has_repr_c;
+        let has_repr_simd = self.repr_has_repr_simd;
         let live_fields = def.fields().iter().filter_map(|f| {
             let def_id = tcx.hir().local_def_id(f.hir_id);
-            if has_repr_c {
+            if has_repr_c || (f.is_positional() && has_repr_simd) {
                 return Some(def_id);
             }
             if !tcx.visibility(f.hir_id.owner).is_public() {
@@ -408,6 +433,10 @@ fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) {
                 let res = self.typeck_results().qpath_res(qpath, pat.hir_id);
                 self.handle_res(res);
             }
+            PatKind::TupleStruct(ref qpath, ref fields, dotdot) => {
+                let res = self.typeck_results().qpath_res(qpath, pat.hir_id);
+                self.handle_tuple_field_pattern_match(pat, res, fields, dotdot);
+            }
             _ => (),
         }
 
@@ -440,7 +469,11 @@ fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
     }
 }
 
-fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
+fn has_allow_dead_code_or_lang_attr_helper(
+    tcx: TyCtxt<'_>,
+    id: hir::HirId,
+    lint: &'static lint::Lint,
+) -> bool {
     let attrs = tcx.hir().attrs(id);
     if tcx.sess.contains_name(attrs, sym::lang) {
         return true;
@@ -470,7 +503,11 @@ fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
         }
     }
 
-    tcx.lint_level_at_node(lint::builtin::DEAD_CODE, id).0 == lint::Allow
+    tcx.lint_level_at_node(lint, id).0 == lint::Allow
+}
+
+fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
+    has_allow_dead_code_or_lang_attr_helper(tcx, id, lint::builtin::DEAD_CODE)
 }
 
 // These check_* functions seeds items that
@@ -623,6 +660,7 @@ fn live_symbols_and_ignored_derived_traits<'tcx>(
         maybe_typeck_results: None,
         live_symbols: Default::default(),
         repr_has_repr_c: false,
+        repr_has_repr_simd: false,
         in_pat: false,
         ignore_variant_stack: vec![],
         struct_constructors,
@@ -644,17 +682,30 @@ struct DeadVisitor<'tcx> {
     ignored_derived_traits: &'tcx FxHashMap<LocalDefId, Vec<(DefId, DefId)>>,
 }
 
+enum ShouldWarnAboutField {
+    Yes(bool), // positional?
+    No,
+}
+
 impl<'tcx> DeadVisitor<'tcx> {
-    fn should_warn_about_field(&mut self, field: &ty::FieldDef) -> bool {
+    fn should_warn_about_field(&mut self, field: &ty::FieldDef) -> ShouldWarnAboutField {
         if self.live_symbols.contains(&field.did.expect_local()) {
-            return false;
+            return ShouldWarnAboutField::No;
+        }
+        let field_type = self.tcx.type_of(field.did);
+        if field_type.is_phantom_data() {
+            return ShouldWarnAboutField::No;
         }
         let is_positional = field.name.as_str().starts_with(|c: char| c.is_ascii_digit());
-        if is_positional {
-            return false;
+        if is_positional
+            && self
+                .tcx
+                .layout_of(self.tcx.param_env(field.did).and(field_type))
+                .map_or(true, |layout| layout.is_zst())
+        {
+            return ShouldWarnAboutField::No;
         }
-        let field_type = self.tcx.type_of(field.did);
-        !field_type.is_phantom_data()
+        ShouldWarnAboutField::Yes(is_positional)
     }
 
     fn warn_multiple_dead_codes(
@@ -662,6 +713,7 @@ fn warn_multiple_dead_codes(
         dead_codes: &[LocalDefId],
         participle: &str,
         parent_item: Option<LocalDefId>,
+        is_positional: bool,
     ) {
         if let Some(&first_id) = dead_codes.first() {
             let tcx = self.tcx;
@@ -669,7 +721,7 @@ fn warn_multiple_dead_codes(
                 .iter()
                 .map(|&def_id| tcx.item_name(def_id.to_def_id()).to_string())
                 .collect();
-            let spans = dead_codes
+            let spans: Vec<_> = dead_codes
                 .iter()
                 .map(|&def_id| match tcx.def_ident_span(def_id) {
                     Some(s) => s.with_ctxt(tcx.def_span(def_id).ctxt()),
@@ -678,9 +730,13 @@ fn warn_multiple_dead_codes(
                 .collect();
 
             tcx.struct_span_lint_hir(
-                lint::builtin::DEAD_CODE,
+                if is_positional {
+                    lint::builtin::UNUSED_TUPLE_STRUCT_FIELDS
+                } else {
+                    lint::builtin::DEAD_CODE
+                },
                 tcx.hir().local_def_id_to_hir_id(first_id),
-                MultiSpan::from_spans(spans),
+                MultiSpan::from_spans(spans.clone()),
                 |lint| {
                     let descr = tcx.def_kind(first_id).descr(first_id.to_def_id());
                     let span_len = dead_codes.len();
@@ -702,6 +758,21 @@ fn warn_multiple_dead_codes(
                         are = pluralize!("is", span_len),
                     ));
 
+                    if is_positional {
+                        err.multipart_suggestion(
+                            &format!(
+                                "consider changing the field{s} to be of unit type to \
+                                      suppress this warning while preserving the field \
+                                      numbering, or remove the field{s}",
+                                s = pluralize!(span_len)
+                            ),
+                            spans.iter().map(|sp| (*sp, "()".to_string())).collect(),
+                            // "HasPlaceholders" because applying this fix by itself isn't
+                            // enough: All constructor calls have to be adjusted as well
+                            Applicability::HasPlaceholders,
+                        );
+                    }
+
                     if let Some(parent_item) = parent_item {
                         let parent_descr = tcx.def_kind(parent_item).descr(parent_item.to_def_id());
                         err.span_label(
@@ -743,6 +814,7 @@ fn warn_dead_fields_and_variants(
         def_id: LocalDefId,
         participle: &str,
         dead_codes: Vec<DeadVariant>,
+        is_positional: bool,
     ) {
         let mut dead_codes = dead_codes
             .iter()
@@ -758,12 +830,13 @@ fn warn_dead_fields_and_variants(
                 &group.map(|v| v.def_id).collect::<Vec<_>>(),
                 participle,
                 Some(def_id),
+                is_positional,
             );
         }
     }
 
     fn warn_dead_code(&mut self, id: LocalDefId, participle: &str) {
-        self.warn_multiple_dead_codes(&[id], participle, None);
+        self.warn_multiple_dead_codes(&[id], participle, None, false);
     }
 
     fn check_definition(&mut self, def_id: LocalDefId) {
@@ -829,24 +902,37 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalDefId) {
                     continue;
                 }
 
+                let mut is_positional = false;
                 let dead_fields = variant
                     .fields
                     .iter()
                     .filter_map(|field| {
                         let def_id = field.did.expect_local();
                         let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-                        if visitor.should_warn_about_field(&field) {
-                            let level = tcx.lint_level_at_node(lint::builtin::DEAD_CODE, hir_id).0;
+                        if let ShouldWarnAboutField::Yes(is_pos) =
+                            visitor.should_warn_about_field(&field)
+                        {
+                            let level = tcx
+                                .lint_level_at_node(
+                                    if is_pos {
+                                        is_positional = true;
+                                        lint::builtin::UNUSED_TUPLE_STRUCT_FIELDS
+                                    } else {
+                                        lint::builtin::DEAD_CODE
+                                    },
+                                    hir_id,
+                                )
+                                .0;
                             Some(DeadVariant { def_id, name: field.name, level })
                         } else {
                             None
                         }
                     })
                     .collect();
-                visitor.warn_dead_fields_and_variants(def_id, "read", dead_fields)
+                visitor.warn_dead_fields_and_variants(def_id, "read", dead_fields, is_positional)
             }
 
-            visitor.warn_dead_fields_and_variants(item.def_id, "constructed", dead_variants);
+            visitor.warn_dead_fields_and_variants(item.def_id, "constructed", dead_variants, false);
         }
     }
 
index 5feb0e2956b74fa55b24e1b0ee8fb7871a35cb78..cd465380867cf5c348b64f9c6e7f745b69fdde97 100644 (file)
@@ -551,6 +551,13 @@ pub struct ConstTrait {
     pub attr_span: Span,
 }
 
+#[derive(SessionDiagnostic)]
+#[error(passes::link_ordinal)]
+pub struct LinkOrdinal {
+    #[primary_span]
+    pub attr_span: Span,
+}
+
 #[derive(SessionDiagnostic)]
 #[error(passes::stability_promotable)]
 pub struct StabilityPromotable {
index a3be827a7ccec3a5f4a1aa16a6dac1bbfdd115cb..399d00b403a6ba784eb5a88791f8ccbf33c25aa1 100644 (file)
@@ -21,21 +21,55 @@ enum Id {
     None,
 }
 
-struct NodeData {
+struct NodeStats {
     count: usize,
     size: usize,
 }
 
+impl NodeStats {
+    fn new() -> NodeStats {
+        NodeStats { count: 0, size: 0 }
+    }
+}
+
+struct Node {
+    stats: NodeStats,
+    subnodes: FxHashMap<&'static str, NodeStats>,
+}
+
+impl Node {
+    fn new() -> Node {
+        Node { stats: NodeStats::new(), subnodes: FxHashMap::default() }
+    }
+}
+
+/// This type measures the size of AST and HIR nodes, by implementing the AST
+/// and HIR `Visitor` traits. But we don't measure every visited type because
+/// that could cause double counting.
+///
+/// For example, `ast::Visitor` has `visit_ident`, but `Ident`s are always
+/// stored inline within other AST nodes, so we don't implement `visit_ident`
+/// here. In constrast, we do implement `visit_expr` because `ast::Expr` is
+/// always stored as `P<ast::Expr>`, and every such expression should be
+/// measured separately.
+///
+/// In general, a `visit_foo` method should be implemented here if the
+/// corresponding `Foo` type is always stored on its own, e.g.: `P<Foo>`,
+/// `Box<Foo>`, `Vec<Foo>`, `Box<[Foo]>`.
+///
+/// There are some types in the AST and HIR tree that the visitors do not have
+/// a `visit_*` method for, and so we cannot measure these, which is
+/// unfortunate.
 struct StatCollector<'k> {
     krate: Option<Map<'k>>,
-    data: FxHashMap<&'static str, NodeData>,
+    nodes: FxHashMap<&'static str, Node>,
     seen: FxHashSet<Id>,
 }
 
 pub fn print_hir_stats(tcx: TyCtxt<'_>) {
     let mut collector = StatCollector {
         krate: Some(tcx.hir()),
-        data: FxHashMap::default(),
+        nodes: FxHashMap::default(),
         seen: FxHashSet::default(),
     };
     tcx.hir().walk_toplevel_module(&mut collector);
@@ -44,49 +78,88 @@ pub fn print_hir_stats(tcx: TyCtxt<'_>) {
 }
 
 pub fn print_ast_stats(krate: &ast::Crate, title: &str) {
+    use rustc_ast::visit::Visitor;
+
     let mut collector =
-        StatCollector { krate: None, data: FxHashMap::default(), seen: FxHashSet::default() };
-    ast_visit::walk_crate(&mut collector, krate);
+        StatCollector { krate: None, nodes: FxHashMap::default(), seen: FxHashSet::default() };
+    collector.visit_crate(krate);
     collector.print(title);
 }
 
 impl<'k> StatCollector<'k> {
-    fn record<T>(&mut self, label: &'static str, id: Id, node: &T) {
+    // Record a top-level node.
+    fn record<T>(&mut self, label: &'static str, id: Id, val: &T) {
+        self.record_inner(label, None, id, val);
+    }
+
+    // Record a two-level entry, with a top-level enum type and a variant.
+    fn record_variant<T>(&mut self, label1: &'static str, label2: &'static str, id: Id, val: &T) {
+        self.record_inner(label1, Some(label2), id, val);
+    }
+
+    fn record_inner<T>(
+        &mut self,
+        label1: &'static str,
+        label2: Option<&'static str>,
+        id: Id,
+        val: &T,
+    ) {
         if id != Id::None && !self.seen.insert(id) {
             return;
         }
 
-        let entry = self.data.entry(label).or_insert(NodeData { count: 0, size: 0 });
+        let node = self.nodes.entry(label1).or_insert(Node::new());
+        node.stats.count += 1;
+        node.stats.size = std::mem::size_of_val(val);
 
-        entry.count += 1;
-        entry.size = std::mem::size_of_val(node);
+        if let Some(label2) = label2 {
+            let subnode = node.subnodes.entry(label2).or_insert(NodeStats::new());
+            subnode.count += 1;
+            subnode.size = std::mem::size_of_val(val);
+        }
     }
 
     fn print(&self, title: &str) {
-        let mut stats: Vec<_> = self.data.iter().collect();
+        let mut nodes: Vec<_> = self.nodes.iter().collect();
+        nodes.sort_by_key(|&(_, ref node)| node.stats.count * node.stats.size);
 
-        stats.sort_by_key(|&(_, ref d)| d.count * d.size);
-
-        let mut total_size = 0;
+        let total_size = nodes.iter().map(|(_, node)| node.stats.count * node.stats.size).sum();
 
         eprintln!("\n{}\n", title);
 
         eprintln!("{:<18}{:>18}{:>14}{:>14}", "Name", "Accumulated Size", "Count", "Item Size");
         eprintln!("----------------------------------------------------------------");
 
-        for (label, data) in stats {
+        let percent = |m, n| (m * 100) as f64 / n as f64;
+
+        for (label, node) in nodes {
+            let size = node.stats.count * node.stats.size;
             eprintln!(
-                "{:<18}{:>18}{:>14}{:>14}",
+                "{:<18}{:>10} ({:4.1}%){:>14}{:>14}",
                 label,
-                to_readable_str(data.count * data.size),
-                to_readable_str(data.count),
-                to_readable_str(data.size)
+                to_readable_str(size),
+                percent(size, total_size),
+                to_readable_str(node.stats.count),
+                to_readable_str(node.stats.size)
             );
-
-            total_size += data.count * data.size;
+            if !node.subnodes.is_empty() {
+                let mut subnodes: Vec<_> = node.subnodes.iter().collect();
+                subnodes.sort_by_key(|&(_, ref subnode)| subnode.count * subnode.size);
+
+                for (label, subnode) in subnodes {
+                    let size = subnode.count * subnode.size;
+                    eprintln!(
+                        "- {:<18}{:>10} ({:4.1}%){:>14}",
+                        label,
+                        to_readable_str(size),
+                        percent(size, total_size),
+                        to_readable_str(subnode.count),
+                    );
+                }
+            }
         }
         eprintln!("----------------------------------------------------------------");
-        eprintln!("{:<18}{:>18}\n", "Total", to_readable_str(total_size));
+        eprintln!("{:<18}{:>10}\n", "Total", to_readable_str(total_size));
     }
 }
 
@@ -203,14 +276,9 @@ fn visit_field_def(&mut self, s: &'v hir::FieldDef<'v>) {
         hir_visit::walk_field_def(self, s)
     }
 
-    fn visit_variant(
-        &mut self,
-        v: &'v hir::Variant<'v>,
-        g: &'v hir::Generics<'v>,
-        item_id: hir::HirId,
-    ) {
+    fn visit_variant(&mut self, v: &'v hir::Variant<'v>) {
         self.record("Variant", Id::None, v);
-        hir_visit::walk_variant(self, v, g, item_id)
+        hir_visit::walk_variant(self, v)
     }
 
     fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) {
@@ -228,6 +296,10 @@ fn visit_path(&mut self, path: &'v hir::Path<'v>, _id: hir::HirId) {
         hir_visit::walk_path(self, path)
     }
 
+    // `PathSegment` has one inline use (in `ast::ExprKind::MethodCall`) and
+    // one non-inline use (in `Path::segments`). The latter case is more common
+    // than the former case, so we implement this visitor and tolerate the
+    // double counting in the former case.
     fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v hir::PathSegment<'v>) {
         self.record("PathSegment", Id::None, path_segment);
         hir_visit::walk_path_segment(self, path_span, path_segment)
@@ -243,14 +315,54 @@ fn visit_attribute(&mut self, attr: &'v ast::Attribute) {
     }
 }
 
+// Used to avoid boilerplate for types with many variants.
+macro_rules! record_variants {
+    (
+        ($self:ident, $val:expr, $kind:expr, $ty:ty, $tykind:ident), // mandatory pieces
+        [$($variant:ident),*]
+    ) => {
+        match $kind {
+            $(
+                ast::$tykind::$variant { .. } => {
+                    $self.record_variant(stringify!($ty), stringify!($variant), Id::None, $val)
+                }
+            )*
+        }
+    };
+}
+
 impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
     fn visit_foreign_item(&mut self, i: &'v ast::ForeignItem) {
-        self.record("ForeignItem", Id::None, i);
+        record_variants!(
+            (self, i, i.kind, ForeignItem, ForeignItemKind),
+            [Static, Fn, TyAlias, MacCall]
+        );
         ast_visit::walk_foreign_item(self, i)
     }
 
     fn visit_item(&mut self, i: &'v ast::Item) {
-        self.record("Item", Id::None, i);
+        record_variants!(
+            (self, i, i.kind, Item, ItemKind),
+            [
+                ExternCrate,
+                Use,
+                Static,
+                Const,
+                Fn,
+                Mod,
+                ForeignMod,
+                GlobalAsm,
+                TyAlias,
+                Enum,
+                Struct,
+                Union,
+                Trait,
+                TraitAlias,
+                Impl,
+                MacCall,
+                MacroDef
+            ]
+        );
         ast_visit::walk_item(self, i)
     }
 
@@ -265,47 +377,116 @@ fn visit_block(&mut self, b: &'v ast::Block) {
     }
 
     fn visit_stmt(&mut self, s: &'v ast::Stmt) {
-        self.record("Stmt", Id::None, s);
+        record_variants!(
+            (self, s, s.kind, Stmt, StmtKind),
+            [Local, Item, Expr, Semi, Empty, MacCall]
+        );
         ast_visit::walk_stmt(self, s)
     }
 
+    fn visit_param(&mut self, p: &'v ast::Param) {
+        self.record("Param", Id::None, p);
+        ast_visit::walk_param(self, p)
+    }
+
     fn visit_arm(&mut self, a: &'v ast::Arm) {
         self.record("Arm", Id::None, a);
         ast_visit::walk_arm(self, a)
     }
 
     fn visit_pat(&mut self, p: &'v ast::Pat) {
-        self.record("Pat", Id::None, p);
+        record_variants!(
+            (self, p, p.kind, Pat, PatKind),
+            [
+                Wild,
+                Ident,
+                Struct,
+                TupleStruct,
+                Or,
+                Path,
+                Tuple,
+                Box,
+                Ref,
+                Lit,
+                Range,
+                Slice,
+                Rest,
+                Paren,
+                MacCall
+            ]
+        );
         ast_visit::walk_pat(self, p)
     }
 
-    fn visit_expr(&mut self, ex: &'v ast::Expr) {
-        self.record("Expr", Id::None, ex);
-        ast_visit::walk_expr(self, ex)
+    fn visit_expr(&mut self, e: &'v ast::Expr) {
+        record_variants!(
+            (self, e, e.kind, Expr, ExprKind),
+            [
+                Box, Array, ConstBlock, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type, Let,
+                If, While, ForLoop, Loop, Match, Closure, Block, Async, Await, TryBlock, Assign,
+                AssignOp, Field, Index, Range, Underscore, Path, AddrOf, Break, Continue, Ret,
+                InlineAsm, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet, Err
+            ]
+        );
+        ast_visit::walk_expr(self, e)
     }
 
     fn visit_ty(&mut self, t: &'v ast::Ty) {
-        self.record("Ty", Id::None, t);
+        record_variants!(
+            (self, t, t.kind, Ty, TyKind),
+            [
+                Slice,
+                Array,
+                Ptr,
+                Rptr,
+                BareFn,
+                Never,
+                Tup,
+                Path,
+                TraitObject,
+                ImplTrait,
+                Paren,
+                Typeof,
+                Infer,
+                ImplicitSelf,
+                MacCall,
+                Err,
+                CVarArgs
+            ]
+        );
+
         ast_visit::walk_ty(self, t)
     }
 
+    fn visit_generic_param(&mut self, g: &'v ast::GenericParam) {
+        self.record("GenericParam", Id::None, g);
+        ast_visit::walk_generic_param(self, g)
+    }
+
+    fn visit_where_predicate(&mut self, p: &'v ast::WherePredicate) {
+        record_variants!(
+            (self, p, p, WherePredicate, WherePredicate),
+            [BoundPredicate, RegionPredicate, EqPredicate]
+        );
+        ast_visit::walk_where_predicate(self, p)
+    }
+
     fn visit_fn(&mut self, fk: ast_visit::FnKind<'v>, s: Span, _: NodeId) {
         self.record("FnDecl", Id::None, fk.decl());
         ast_visit::walk_fn(self, fk, s)
     }
 
-    fn visit_assoc_item(&mut self, item: &'v ast::AssocItem, ctxt: ast_visit::AssocCtxt) {
-        let label = match ctxt {
-            ast_visit::AssocCtxt::Trait => "TraitItem",
-            ast_visit::AssocCtxt::Impl => "ImplItem",
-        };
-        self.record(label, Id::None, item);
-        ast_visit::walk_assoc_item(self, item, ctxt);
+    fn visit_assoc_item(&mut self, i: &'v ast::AssocItem, ctxt: ast_visit::AssocCtxt) {
+        record_variants!(
+            (self, i, i.kind, AssocItem, AssocItemKind),
+            [Const, Fn, TyAlias, MacCall]
+        );
+        ast_visit::walk_assoc_item(self, i, ctxt);
     }
 
-    fn visit_param_bound(&mut self, bounds: &'v ast::GenericBound, _ctxt: BoundKind) {
-        self.record("GenericBound", Id::None, bounds);
-        ast_visit::walk_param_bound(self, bounds)
+    fn visit_param_bound(&mut self, b: &'v ast::GenericBound, _ctxt: BoundKind) {
+        record_variants!((self, b, b, GenericBound, GenericBound), [Trait, Outlives]);
+        ast_visit::walk_param_bound(self, b)
     }
 
     fn visit_field_def(&mut self, s: &'v ast::FieldDef) {
@@ -318,27 +499,42 @@ fn visit_variant(&mut self, v: &'v ast::Variant) {
         ast_visit::walk_variant(self, v)
     }
 
-    fn visit_lifetime(&mut self, lifetime: &'v ast::Lifetime, _: ast_visit::LifetimeCtxt) {
-        self.record("Lifetime", Id::None, lifetime);
-        ast_visit::walk_lifetime(self, lifetime)
-    }
-
-    fn visit_mac_call(&mut self, mac: &'v ast::MacCall) {
-        self.record("MacCall", Id::None, mac);
-        ast_visit::walk_mac(self, mac)
-    }
+    // `UseTree` has one inline use (in `ast::ItemKind::Use`) and one
+    // non-inline use (in `ast::UseTreeKind::Nested). The former case is more
+    // common, so we don't implement `visit_use_tree` and tolerate the missed
+    // coverage in the latter case.
 
     fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v ast::PathSegment) {
         self.record("PathSegment", Id::None, path_segment);
         ast_visit::walk_path_segment(self, path_span, path_segment)
     }
 
-    fn visit_assoc_constraint(&mut self, constraint: &'v ast::AssocConstraint) {
-        self.record("AssocConstraint", Id::None, constraint);
-        ast_visit::walk_assoc_constraint(self, constraint)
+    // `GenericArgs` has one inline use (in `ast::AssocConstraint::gen_args`) and one
+    // non-inline use (in `ast::PathSegment::args`). The latter case is more
+    // common, so we implement `visit_generic_args` and tolerate the double
+    // counting in the former case.
+    fn visit_generic_args(&mut self, sp: Span, g: &'v ast::GenericArgs) {
+        record_variants!((self, g, g, GenericArgs, GenericArgs), [AngleBracketed, Parenthesized]);
+        ast_visit::walk_generic_args(self, sp, g)
     }
 
     fn visit_attribute(&mut self, attr: &'v ast::Attribute) {
-        self.record("Attribute", Id::None, attr);
+        record_variants!((self, attr, attr.kind, Attribute, AttrKind), [Normal, DocComment]);
+        ast_visit::walk_attribute(self, attr)
+    }
+
+    fn visit_expr_field(&mut self, f: &'v ast::ExprField) {
+        self.record("ExprField", Id::None, f);
+        ast_visit::walk_expr_field(self, f)
+    }
+
+    fn visit_crate(&mut self, krate: &'v ast::Crate) {
+        self.record("Crate", Id::None, krate);
+        ast_visit::walk_crate(self, krate)
+    }
+
+    fn visit_inline_asm(&mut self, asm: &'v ast::InlineAsm) {
+        self.record("InlineAsm", Id::None, asm);
+        ast_visit::walk_inline_asm(self, asm)
     }
 }
index e05994f13e4d9b8ef73bc5c8b50ca878cb599636..868887c66cdec7a95e1bc723a460718c5d365c0d 100644 (file)
@@ -29,11 +29,16 @@ fn new(tcx: TyCtxt<'tcx>) -> LibFeatureCollector<'tcx> {
     }
 
     fn extract(&self, attr: &Attribute) -> Option<(Symbol, Option<Symbol>, Span)> {
-        let stab_attrs =
-            [sym::stable, sym::unstable, sym::rustc_const_stable, sym::rustc_const_unstable];
+        let stab_attrs = [
+            sym::stable,
+            sym::unstable,
+            sym::rustc_const_stable,
+            sym::rustc_const_unstable,
+            sym::rustc_default_body_unstable,
+        ];
 
         // Find a stability attribute: one of #[stable(…)], #[unstable(…)],
-        // #[rustc_const_stable(…)], or #[rustc_const_unstable(…)].
+        // #[rustc_const_stable(…)], #[rustc_const_unstable(…)] or #[rustc_default_body_unstable].
         if let Some(stab_attr) = stab_attrs.iter().find(|stab_attr| attr.has_name(**stab_attr)) {
             let meta_kind = attr.meta_kind();
             if let Some(MetaItemKind::List(ref metas)) = meta_kind {
@@ -53,8 +58,12 @@ fn extract(&self, attr: &Attribute) -> Option<(Symbol, Option<Symbol>, Span)> {
                     // This additional check for stability is to make sure we
                     // don't emit additional, irrelevant errors for malformed
                     // attributes.
-                    let is_unstable =
-                        matches!(*stab_attr, sym::unstable | sym::rustc_const_unstable);
+                    let is_unstable = matches!(
+                        *stab_attr,
+                        sym::unstable
+                            | sym::rustc_const_unstable
+                            | sym::rustc_default_body_unstable
+                    );
                     if since.is_some() || is_unstable {
                         return Some((feature, since, attr.span));
                     }
index 20765abf392803f414e18093e03edfec990b1790..296b6ed5d99a69b5e5153a134d578d9218f12a47 100644 (file)
@@ -1,11 +1,12 @@
 //! Checks validity of naked functions.
 
-use rustc_ast::{Attribute, InlineAsmOptions};
+use rustc_ast::InlineAsmOptions;
 use rustc_errors::{struct_span_err, Applicability};
 use rustc_hir as hir;
+use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
-use rustc_hir::intravisit::{FnKind, Visitor};
-use rustc_hir::{ExprKind, HirId, InlineAsmOperand, StmtKind};
+use rustc_hir::intravisit::Visitor;
+use rustc_hir::{ExprKind, InlineAsmOperand, StmtKind};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::lint::builtin::UNDEFINED_NAKED_FUNCTION_ABI;
 use rustc_span::Span;
 use rustc_target::spec::abi::Abi;
 
-fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
-    tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckNakedFunctions { tcx });
-}
-
 pub(crate) fn provide(providers: &mut Providers) {
     *providers = Providers { check_mod_naked_functions, ..*providers };
 }
 
-struct CheckNakedFunctions<'tcx> {
-    tcx: TyCtxt<'tcx>,
-}
-
-impl<'tcx> Visitor<'tcx> for CheckNakedFunctions<'tcx> {
-    fn visit_fn(
-        &mut self,
-        fk: FnKind<'_>,
-        _fd: &'tcx hir::FnDecl<'tcx>,
-        body_id: hir::BodyId,
-        span: Span,
-        hir_id: HirId,
-    ) {
-        let ident_span;
-        let fn_header;
-
-        match fk {
-            FnKind::Closure => {
-                // Closures with a naked attribute are rejected during attribute
-                // check. Don't validate them any further.
-                return;
-            }
-            FnKind::ItemFn(ident, _, ref header, ..) => {
-                ident_span = ident.span;
-                fn_header = header;
-            }
-
-            FnKind::Method(ident, ref sig, ..) => {
-                ident_span = ident.span;
-                fn_header = &sig.header;
-            }
+fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
+    let items = tcx.hir_module_items(module_def_id);
+    for def_id in items.definitions() {
+        if !matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn) {
+            continue;
         }
 
-        let attrs = self.tcx.hir().attrs(hir_id);
-        let naked = attrs.iter().any(|attr| attr.has_name(sym::naked));
-        if naked {
-            let body = self.tcx.hir().body(body_id);
-            check_abi(self.tcx, hir_id, fn_header.abi, ident_span);
-            check_no_patterns(self.tcx, body.params);
-            check_no_parameters_use(self.tcx, body);
-            check_asm(self.tcx, body, span);
-            check_inline(self.tcx, attrs);
+        let naked = tcx.has_attr(def_id.to_def_id(), sym::naked);
+        if !naked {
+            continue;
         }
+
+        let (fn_header, body_id) = match tcx.hir().get_by_def_id(def_id) {
+            hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. })
+            | hir::Node::TraitItem(hir::TraitItem {
+                kind: hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)),
+                ..
+            })
+            | hir::Node::ImplItem(hir::ImplItem {
+                kind: hir::ImplItemKind::Fn(sig, body_id),
+                ..
+            }) => (sig.header, *body_id),
+            _ => continue,
+        };
+
+        let body = tcx.hir().body(body_id);
+        check_abi(tcx, def_id, fn_header.abi);
+        check_no_patterns(tcx, body.params);
+        check_no_parameters_use(tcx, body);
+        check_asm(tcx, def_id, body);
+        check_inline(tcx, def_id);
     }
 }
 
 /// Check that the function isn't inlined.
-fn check_inline(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
-    for attr in attrs.iter().filter(|attr| attr.has_name(sym::inline)) {
+fn check_inline(tcx: TyCtxt<'_>, def_id: LocalDefId) {
+    let attrs = tcx.get_attrs(def_id.to_def_id(), sym::inline);
+    for attr in attrs {
         tcx.sess.struct_span_err(attr.span, "naked functions cannot be inlined").emit();
     }
 }
 
 /// Checks that function uses non-Rust ABI.
-fn check_abi(tcx: TyCtxt<'_>, hir_id: HirId, abi: Abi, fn_ident_span: Span) {
+fn check_abi(tcx: TyCtxt<'_>, def_id: LocalDefId, abi: Abi) {
     if abi == Abi::Rust {
-        tcx.struct_span_lint_hir(UNDEFINED_NAKED_FUNCTION_ABI, hir_id, fn_ident_span, |lint| {
+        let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+        let span = tcx.def_span(def_id);
+        tcx.struct_span_lint_hir(UNDEFINED_NAKED_FUNCTION_ABI, hir_id, span, |lint| {
             lint.build("Rust ABI is unsupported in naked functions").emit();
         });
     }
@@ -141,7 +129,7 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
 }
 
 /// Checks that function body contains a single inline assembly block.
-fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, body: &'tcx hir::Body<'tcx>, fn_span: Span) {
+fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body<'tcx>) {
     let mut this = CheckInlineAssembly { tcx, items: Vec::new() };
     this.visit_body(body);
     if let [(ItemKind::Asm | ItemKind::Err, _)] = this.items[..] {
@@ -149,7 +137,7 @@ fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, body: &'tcx hir::Body<'tcx>, fn_span: Span
     } else {
         let mut diag = struct_span_err!(
             tcx.sess,
-            fn_span,
+            tcx.def_span(def_id),
             E0787,
             "naked functions must contain a single asm block"
         );
index ca6a2ac3db34cde86ea97f27e3333a8c08276473..574e8073d8efd508fdc72891a80805ee56ae0a5d 100644 (file)
@@ -1,8 +1,9 @@
 //! A pass that annotates every item and method with its stability level,
 //! propagating default levels lexically from parent to children ast nodes.
 
-use attr::StabilityLevel;
-use rustc_attr::{self as attr, ConstStability, Stability, Unstable, UnstableReason};
+use rustc_attr::{
+    self as attr, ConstStability, Stability, StabilityLevel, Unstable, UnstableReason,
+};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
 use rustc_errors::{struct_span_err, Applicability};
 use rustc_hir as hir;
@@ -10,7 +11,7 @@
 use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
 use rustc_hir::hir_id::CRATE_HIR_ID;
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{FieldDef, Generics, HirId, Item, ItemKind, TraitRef, Ty, TyKind, Variant};
+use rustc_hir::{FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::privacy::AccessLevels;
 use rustc_middle::middle::stability::{AllowUnstable, DeprecationEntry, Index};
@@ -161,7 +162,7 @@ fn annotate<F>(
             return;
         }
 
-        let (stab, const_stab) = attr::find_stability(&self.tcx.sess, attrs, item_sp);
+        let (stab, const_stab, body_stab) = attr::find_stability(&self.tcx.sess, attrs, item_sp);
         let mut const_span = None;
 
         let const_stab = const_stab.map(|(const_stab, const_span_node)| {
@@ -209,6 +210,13 @@ fn annotate<F>(
             }
         }
 
+        if let Some((body_stab, _span)) = body_stab {
+            // FIXME: check that this item can have body stability
+
+            self.index.default_body_stab_map.insert(def_id, body_stab);
+            debug!(?self.index.default_body_stab_map);
+        }
+
         let stab = stab.map(|(stab, span)| {
             // Error if prohibited, or can't inherit anything from a container.
             if kind == AnnotationKind::Prohibited
@@ -434,7 +442,7 @@ fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
         );
     }
 
-    fn visit_variant(&mut self, var: &'tcx Variant<'tcx>, g: &'tcx Generics<'tcx>, item_id: HirId) {
+    fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) {
         self.annotate(
             self.tcx.hir().local_def_id(var.id),
             var.span,
@@ -457,7 +465,7 @@ fn visit_variant(&mut self, var: &'tcx Variant<'tcx>, g: &'tcx Generics<'tcx>, i
                     );
                 }
 
-                intravisit::walk_variant(v, var, g, item_id)
+                intravisit::walk_variant(v, var)
             },
         )
     }
@@ -590,9 +598,9 @@ fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
         intravisit::walk_impl_item(self, ii);
     }
 
-    fn visit_variant(&mut self, var: &'tcx Variant<'tcx>, g: &'tcx Generics<'tcx>, item_id: HirId) {
+    fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) {
         self.check_missing_stability(self.tcx.hir().local_def_id(var.id), var.span);
-        intravisit::walk_variant(self, var, g, item_id);
+        intravisit::walk_variant(self, var);
     }
 
     fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) {
@@ -613,6 +621,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
     let mut index = Index {
         stab_map: Default::default(),
         const_stab_map: Default::default(),
+        default_body_stab_map: Default::default(),
         depr_map: Default::default(),
         implications: Default::default(),
     };
@@ -673,6 +682,9 @@ pub(crate) fn provide(providers: &mut Providers) {
         stability_implications: |tcx, _| tcx.stability().implications.clone(),
         lookup_stability: |tcx, id| tcx.stability().local_stability(id.expect_local()),
         lookup_const_stability: |tcx, id| tcx.stability().local_const_stability(id.expect_local()),
+        lookup_default_body_stability: |tcx, id| {
+            tcx.stability().local_default_body_stability(id.expect_local())
+        },
         lookup_deprecation_entry: |tcx, id| {
             tcx.stability().local_deprecation_entry(id.expect_local())
         },
@@ -723,7 +735,8 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                 let features = self.tcx.features();
                 if features.staged_api {
                     let attrs = self.tcx.hir().attrs(item.hir_id());
-                    let (stab, const_stab) = attr::find_stability(&self.tcx.sess, attrs, item.span);
+                    let (stab, const_stab, _) =
+                        attr::find_stability(&self.tcx.sess, attrs, item.span);
 
                     // If this impl block has an #[unstable] attribute, give an
                     // error if all involved types and traits are stable, because
index b0fac91f6ebc35831e6790f8406bdf358272d041..aca7d770f3495c0b15a802856fb5b55fca8c6a8a 100644 (file)
@@ -1,3 +1,4 @@
+use rustc_errors::DiagnosticArgFromDisplay;
 use rustc_macros::{LintDiagnostic, SessionDiagnostic, SessionSubdiagnostic};
 use rustc_span::{Span, Symbol};
 
@@ -35,7 +36,7 @@ pub struct ItemIsPrivate<'a> {
     #[label]
     pub span: Span,
     pub kind: &'a str,
-    pub descr: String,
+    pub descr: DiagnosticArgFromDisplay<'a>,
 }
 
 #[derive(SessionDiagnostic)]
@@ -55,7 +56,7 @@ pub struct InPublicInterfaceTraits<'a> {
     pub span: Span,
     pub vis_descr: &'static str,
     pub kind: &'a str,
-    pub descr: String,
+    pub descr: DiagnosticArgFromDisplay<'a>,
     #[label(privacy::visibility_label)]
     pub vis_span: Span,
 }
@@ -69,7 +70,7 @@ pub struct InPublicInterface<'a> {
     pub span: Span,
     pub vis_descr: &'static str,
     pub kind: &'a str,
-    pub descr: String,
+    pub descr: DiagnosticArgFromDisplay<'a>,
     #[label(privacy::visibility_label)]
     pub vis_span: Span,
 }
@@ -78,7 +79,7 @@ pub struct InPublicInterface<'a> {
 #[lint(privacy::from_private_dep_in_public_interface)]
 pub struct FromPrivateDependencyInPublicInterface<'a> {
     pub kind: &'a str,
-    pub descr: String,
+    pub descr: DiagnosticArgFromDisplay<'a>,
     pub krate: Symbol,
 }
 
@@ -87,5 +88,5 @@ pub struct FromPrivateDependencyInPublicInterface<'a> {
 pub struct PrivateInPublicLint<'a> {
     pub vis_descr: &'static str,
     pub kind: &'a str,
-    pub descr: String,
+    pub descr: DiagnosticArgFromDisplay<'a>,
 }
index 390d6f5a856af29ce1f2f35374f8035a807a1677..f7c28eff55b763c4cfc1c6b83fa64b0d7f36fab0 100644 (file)
@@ -212,7 +212,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<V::BreakTy> {
                 // `impl Pub<Priv> { pub fn my_method() {} }` is considered a private type,
                 // so we need to visit the self type additionally.
                 if let Some(assoc_item) = tcx.opt_associated_item(def_id) {
-                    if let ty::ImplContainer(impl_def_id) = assoc_item.container {
+                    if let Some(impl_def_id) = assoc_item.impl_container(tcx) {
                         tcx.type_of(impl_def_id).visit_with(self)?;
                     }
                 }
@@ -734,11 +734,12 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                     self.reach(item.def_id, item_level).generics().predicates();
 
                     for trait_item_ref in trait_item_refs {
+                        let tcx = self.tcx;
                         let mut reach = self.reach(trait_item_ref.id.def_id, item_level);
                         reach.generics().predicates();
 
                         if trait_item_ref.kind == AssocItemKind::Type
-                            && !trait_item_ref.defaultness.has_value()
+                            && !tcx.impl_defaultness(trait_item_ref.id.def_id).has_value()
                         {
                             // No type to visit.
                         } else {
@@ -1078,11 +1079,7 @@ fn check_expr_pat_type(&mut self, id: hir::HirId, span: Span) -> bool {
     fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {
         let is_error = !self.item_is_accessible(def_id);
         if is_error {
-            self.tcx.sess.emit_err(ItemIsPrivate {
-                span: self.span,
-                kind,
-                descr: descr.to_string(),
-            });
+            self.tcx.sess.emit_err(ItemIsPrivate { span: self.span, kind, descr: descr.into() });
         }
         is_error
     }
@@ -1254,7 +1251,9 @@ fn visit_qpath(&mut self, qpath: &'tcx hir::QPath<'tcx>, id: hir::HirId, span: S
                 };
                 let kind = kind.descr(def_id);
                 let _ = match name {
-                    Some(name) => sess.emit_err(ItemIsPrivate { span, kind, descr: name }),
+                    Some(name) => {
+                        sess.emit_err(ItemIsPrivate { span, kind, descr: (&name).into() })
+                    }
                     None => sess.emit_err(UnnamedItemIsPrivate { span, kind }),
                 };
                 return;
@@ -1626,15 +1625,10 @@ fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) {
         intravisit::walk_ty(self, t)
     }
 
-    fn visit_variant(
-        &mut self,
-        v: &'tcx hir::Variant<'tcx>,
-        g: &'tcx hir::Generics<'tcx>,
-        item_id: hir::HirId,
-    ) {
+    fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) {
         if self.access_levels.is_reachable(self.tcx.hir().local_def_id(v.id)) {
             self.in_variant = true;
-            intravisit::walk_variant(self, v, g, item_id);
+            intravisit::walk_variant(self, v);
             self.in_variant = false;
         }
     }
@@ -1722,7 +1716,7 @@ fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display)
                 self.tcx.def_span(self.item_def_id.to_def_id()),
                 FromPrivateDependencyInPublicInterface {
                     kind,
-                    descr: descr.to_string(),
+                    descr: descr.into(),
                     krate: self.tcx.crate_name(def_id.krate),
                 },
             );
@@ -1749,19 +1743,17 @@ fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display)
                 }
             };
             let span = self.tcx.def_span(self.item_def_id.to_def_id());
-            let descr = descr.to_string();
             if self.has_old_errors
                 || self.in_assoc_ty
                 || self.tcx.resolutions(()).has_pub_restricted
             {
-                let vis_span =
-                    self.tcx.sess.source_map().guess_head_span(self.tcx.def_span(def_id));
+                let vis_span = self.tcx.def_span(def_id);
                 if kind == "trait" {
                     self.tcx.sess.emit_err(InPublicInterfaceTraits {
                         span,
                         vis_descr,
                         kind,
-                        descr,
+                        descr: descr.into(),
                         vis_span,
                     });
                 } else {
@@ -1769,7 +1761,7 @@ fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display)
                         span,
                         vis_descr,
                         kind,
-                        descr,
+                        descr: descr.into(),
                         vis_span,
                     });
                 }
@@ -1778,7 +1770,7 @@ fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display)
                     lint::builtin::PRIVATE_IN_PUBLIC,
                     hir_id,
                     span,
-                    PrivateInPublicLint { vis_descr, kind, descr },
+                    PrivateInPublicLint { vis_descr, kind, descr: descr.into() },
                 );
             }
         }
@@ -1840,14 +1832,13 @@ fn check_assoc_item(
         &self,
         def_id: LocalDefId,
         assoc_item_kind: AssocItemKind,
-        defaultness: hir::Defaultness,
         vis: ty::Visibility,
     ) {
         let mut check = self.check(def_id, vis);
 
         let (check_ty, is_assoc_ty) = match assoc_item_kind {
             AssocItemKind::Const | AssocItemKind::Fn { .. } => (true, false),
-            AssocItemKind::Type => (defaultness.has_value(), true),
+            AssocItemKind::Type => (self.tcx.impl_defaultness(def_id).has_value(), true),
         };
         check.in_assoc_ty = is_assoc_ty;
         check.generics().predicates();
@@ -1879,7 +1870,6 @@ pub fn check_item(&mut self, id: ItemId) {
                         self.check_assoc_item(
                             trait_item_ref.id.def_id,
                             trait_item_ref.kind,
-                            trait_item_ref.defaultness,
                             item_visibility,
                         );
 
@@ -1952,7 +1942,6 @@ pub fn check_item(&mut self, id: ItemId) {
                         self.check_assoc_item(
                             impl_item_ref.id.def_id,
                             impl_item_ref.kind,
-                            impl_item_ref.defaultness,
                             impl_item_vis,
                         );
                     }
index 9f5779194afcb0451ce655d577a1a56f8cc38271..6d2aff38172facc9f4a0157dae89a56460442abb 100644 (file)
@@ -1,4 +1,3 @@
-use crate::dep_graph::DepContext;
 use crate::query::plumbing::CycleError;
 use crate::query::{QueryContext, QueryStackFrame};
 use rustc_hir::def::DefKind;
@@ -536,17 +535,13 @@ pub(crate) fn report_cycle<'a>(
 ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
     assert!(!stack.is_empty());
 
-    let fix_span = |span: Span, query: &QueryStackFrame| {
-        sess.source_map().guess_head_span(query.default_span(span))
-    };
-
-    let span = fix_span(stack[1 % stack.len()].span, &stack[0].query);
+    let span = stack[0].query.default_span(stack[1 % stack.len()].span);
     let mut err =
         struct_span_err!(sess, span, E0391, "cycle detected when {}", stack[0].query.description);
 
     for i in 1..stack.len() {
         let query = &stack[i].query;
-        let span = fix_span(stack[(i + 1) % stack.len()].span, query);
+        let span = query.default_span(stack[(i + 1) % stack.len()].span);
         err.span_note(span, &format!("...which requires {}...", query.description));
     }
 
@@ -577,7 +572,7 @@ pub(crate) fn report_cycle<'a>(
     }
 
     if let Some((span, query)) = usage {
-        err.span_note(fix_span(span, &query), &format!("cycle used when {}", query.description));
+        err.span_note(query.default_span(span), &format!("cycle used when {}", query.description));
     }
 
     err
@@ -606,8 +601,7 @@ pub fn print_query_stack<CTX: QueryContext>(
             Level::FailureNote,
             &format!("#{} [{}] {}", i, query_info.query.name, query_info.query.description),
         );
-        diag.span =
-            tcx.dep_context().sess().source_map().guess_head_span(query_info.job.span).into();
+        diag.span = query_info.job.span.into();
         handler.force_print_diagnostic(diag);
 
         current_query = query_info.job.parent;
index 22a307a15edc095bfd98dcb8e2a50d46890e0312..325b0458638af1712904cc1e05edaf0c2259bfc4 100644 (file)
@@ -1587,11 +1587,7 @@ pub(crate) fn add_typo_suggestion(
         };
         let def_span = suggestion.res.opt_def_id().and_then(|def_id| match def_id.krate {
             LOCAL_CRATE => self.opt_span(def_id),
-            _ => Some(
-                self.session
-                    .source_map()
-                    .guess_head_span(self.cstore().get_span_untracked(def_id, self.session)),
-            ),
+            _ => Some(self.cstore().get_span_untracked(def_id, self.session)),
         });
         if let Some(def_span) = def_span {
             if span.overlaps(def_span) {
@@ -2548,12 +2544,15 @@ fn show_candidates(
                 Applicability::MaybeIncorrect,
             );
             if let [first, .., last] = &path[..] {
-                err.span_suggestion_verbose(
-                    first.ident.span.until(last.ident.span),
-                    &format!("if you import `{}`, refer to it directly", last.ident),
-                    "",
-                    Applicability::Unspecified,
-                );
+                let sp = first.ident.span.until(last.ident.span);
+                if sp.can_be_used_for_suggestions() {
+                    err.span_suggestion_verbose(
+                        sp,
+                        &format!("if you import `{}`, refer to it directly", last.ident),
+                        "",
+                        Applicability::Unspecified,
+                    );
+                }
             }
         } else {
             msg.push(':');
index ed65100ae77511584e0c70b190c899be0e15d18a..58a4cff55db7dc906b0522107a92cd9502793285 100644 (file)
@@ -629,7 +629,7 @@ fn visit_ty(&mut self, ty: &'ast Ty) {
                 // Elided lifetime in reference: we resolve as if there was some lifetime `'_` with
                 // NodeId `ty.id`.
                 // This span will be used in case of elision failure.
-                let span = self.r.session.source_map().next_point(ty.span.shrink_to_lo());
+                let span = self.r.session.source_map().start_point(ty.span);
                 self.resolve_elided_lifetime(ty.id, span);
                 visit::walk_ty(self, ty);
             }
@@ -723,7 +723,7 @@ fn visit_ty(&mut self, ty: &'ast Ty) {
         self.diagnostic_metadata.current_trait_object = prev;
         self.diagnostic_metadata.current_type_path = prev_ty;
     }
-    fn visit_poly_trait_ref(&mut self, tref: &'ast PolyTraitRef, _: &'ast TraitBoundModifier) {
+    fn visit_poly_trait_ref(&mut self, tref: &'ast PolyTraitRef) {
         let span = tref.span.shrink_to_lo().to(tref.trait_ref.path.span.shrink_to_lo());
         self.with_generic_param_rib(
             &tref.bound_generic_params,
@@ -1644,14 +1644,30 @@ fn resolve_elided_lifetimes_in_path(
                 continue;
             }
 
-            let missing = match source {
-                PathSource::Trait(..) | PathSource::TraitItem(..) | PathSource::Type => true,
+            let node_ids = self.r.next_node_ids(expected_lifetimes);
+            self.record_lifetime_res(
+                segment_id,
+                LifetimeRes::ElidedAnchor { start: node_ids.start, end: node_ids.end },
+                LifetimeElisionCandidate::Ignore,
+            );
+
+            let inferred = match source {
+                PathSource::Trait(..) | PathSource::TraitItem(..) | PathSource::Type => false,
                 PathSource::Expr(..)
                 | PathSource::Pat
                 | PathSource::Struct
-                | PathSource::TupleStruct(..) => false,
+                | PathSource::TupleStruct(..) => true,
             };
-            if !missing && !segment.has_generic_args {
+            if inferred {
+                // Do not create a parameter for patterns and expressions: type checking can infer
+                // the appropriate lifetime for us.
+                for id in node_ids {
+                    self.record_lifetime_res(
+                        id,
+                        LifetimeRes::Infer,
+                        LifetimeElisionCandidate::Named,
+                    );
+                }
                 continue;
             }
 
@@ -1666,25 +1682,6 @@ fn resolve_elided_lifetimes_in_path(
             };
             let ident = Ident::new(kw::UnderscoreLifetime, elided_lifetime_span);
 
-            let node_ids = self.r.next_node_ids(expected_lifetimes);
-            self.record_lifetime_res(
-                segment_id,
-                LifetimeRes::ElidedAnchor { start: node_ids.start, end: node_ids.end },
-                LifetimeElisionCandidate::Ignore,
-            );
-
-            if !missing {
-                // Do not create a parameter for patterns and expressions.
-                for id in node_ids {
-                    self.record_lifetime_res(
-                        id,
-                        LifetimeRes::Infer,
-                        LifetimeElisionCandidate::Named,
-                    );
-                }
-                continue;
-            }
-
             let missing_lifetime = MissingLifetime {
                 id: node_ids.start,
                 span: elided_lifetime_span,
@@ -3799,9 +3796,8 @@ fn resolve_expr(&mut self, expr: &'ast Expr, parent: Option<&'ast Expr>) {
             ExprKind::Field(ref subexpression, _) => {
                 self.resolve_expr(subexpression, Some(expr));
             }
-            ExprKind::MethodCall(ref segment, ref arguments, _) => {
-                let mut arguments = arguments.iter();
-                self.resolve_expr(arguments.next().unwrap(), Some(expr));
+            ExprKind::MethodCall(ref segment, ref receiver, ref arguments, _) => {
+                self.resolve_expr(receiver, Some(expr));
                 for argument in arguments {
                     self.resolve_expr(argument, None);
                 }
index 6b49c6b1ac63eeaeb66086678a5c6e06d302791e..cb133841bca5a2ac7c9ce97cc322fb280dd34615 100644 (file)
@@ -136,12 +136,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
     fn def_span(&self, def_id: DefId) -> Option<Span> {
         match def_id.krate {
             LOCAL_CRATE => self.r.opt_span(def_id),
-            _ => Some(
-                self.r
-                    .session
-                    .source_map()
-                    .guess_head_span(self.r.cstore().get_span_untracked(def_id, self.r.session)),
-            ),
+            _ => Some(self.r.cstore().get_span_untracked(def_id, self.r.session)),
         }
     }
 
@@ -2026,9 +2021,9 @@ pub(crate) fn emit_undeclared_lifetime_error(
 
     fn suggest_introducing_lifetime(
         &self,
-        err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
+        err: &mut Diagnostic,
         name: Option<&str>,
-        suggest: impl Fn(&mut DiagnosticBuilder<'_, ErrorGuaranteed>, bool, Span, &str, String) -> bool,
+        suggest: impl Fn(&mut Diagnostic, bool, Span, &str, String) -> bool,
     ) {
         let mut suggest_note = true;
         for rib in self.lifetime_ribs.iter().rev() {
@@ -2154,7 +2149,7 @@ pub(crate) fn report_missing_lifetime_specifiers(
 
     pub(crate) fn add_missing_lifetime_specifiers_label(
         &mut self,
-        err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
+        err: &mut Diagnostic,
         lifetime_refs: Vec<MissingLifetime>,
         function_param_lifetimes: Option<(Vec<MissingLifetime>, Vec<ElisionFnParameter>)>,
     ) {
index 31d10008efbfbe8b9278f8c66c4cf356df41d73c..ef3c3da89c572b6b24b3766ff1db0c68d519d7c5 100644 (file)
@@ -913,6 +913,11 @@ pub struct Resolver<'a> {
     label_res_map: NodeMap<NodeId>,
     /// Resolutions for lifetimes.
     lifetimes_res_map: NodeMap<LifetimeRes>,
+    /// Mapping from generics `def_id`s to TAIT generics `def_id`s.
+    /// For each captured lifetime (e.g., 'a), we create a new lifetime parameter that is a generic
+    /// defined on the TAIT, so we have type Foo<'a1> = ... and we establish a mapping in this
+    /// field from the original parameter 'a to the new parameter 'a1.
+    generics_def_id_map: Vec<FxHashMap<LocalDefId, LocalDefId>>,
     /// Lifetime parameters that lowering will have to introduce.
     extra_lifetime_params_map: NodeMap<Vec<(Ident, NodeId, LifetimeRes)>>,
 
@@ -1277,6 +1282,7 @@ pub fn new(
             import_res_map: Default::default(),
             label_res_map: Default::default(),
             lifetimes_res_map: Default::default(),
+            generics_def_id_map: Vec::new(),
             extra_lifetime_params_map: Default::default(),
             extern_crate_map: Default::default(),
             reexport_map: FxHashMap::default(),
@@ -1444,6 +1450,7 @@ pub fn into_outputs(
             import_res_map: self.import_res_map,
             label_res_map: self.label_res_map,
             lifetimes_res_map: self.lifetimes_res_map,
+            generics_def_id_map: self.generics_def_id_map,
             extra_lifetime_params_map: self.extra_lifetime_params_map,
             next_node_id: self.next_node_id,
             node_id_to_def_id: self.node_id_to_def_id,
@@ -1488,6 +1495,7 @@ pub fn clone_outputs(
             import_res_map: self.import_res_map.clone(),
             label_res_map: self.label_res_map.clone(),
             lifetimes_res_map: self.lifetimes_res_map.clone(),
+            generics_def_id_map: self.generics_def_id_map.clone(),
             extra_lifetime_params_map: self.extra_lifetime_params_map.clone(),
             next_node_id: self.next_node_id.clone(),
             node_id_to_def_id: self.node_id_to_def_id.clone(),
index 0a0c674d179e9596ba3f779402297585cab68837..a1a2040bbca143356d62e00ce296a143bc936f72 100644 (file)
@@ -564,8 +564,8 @@ pub fn get_expr_data(&self, expr: &hir::Expr<'_>) -> Option<Data> {
                     return None;
                 };
                 let (def_id, decl_id) = match self.tcx.associated_item(method_id).container {
-                    ty::ImplContainer(_) => (Some(method_id), None),
-                    ty::TraitContainer(_) => (None, Some(method_id)),
+                    ty::ImplContainer => (Some(method_id), None),
+                    ty::TraitContainer => (None, Some(method_id)),
                 };
                 let sub_span = seg.ident.span;
                 filter!(self.span_utils, sub_span);
@@ -697,7 +697,7 @@ fn fn_type(seg: &hir::PathSegment<'_>) -> bool {
             }
             Res::Def(HirDefKind::AssocFn, decl_id) => {
                 let def_id = if decl_id.is_local() {
-                    if self.tcx.associated_item(decl_id).defaultness.has_value() {
+                    if self.tcx.impl_defaultness(decl_id).has_value() {
                         Some(decl_id)
                     } else {
                         None
index 060e7a7b90aeeea7ebefc27679e0912efb05bdcc..2f3519e3edd778b88cb08f09c14c18158bfe7f52 100644 (file)
         repr_packed,
         repr_simd,
         repr_transparent,
+        require,
         residual,
         result,
         rhs,
         rustc_conversion_suggestion,
         rustc_deallocator,
         rustc_def_path,
+        rustc_default_body_unstable,
         rustc_diagnostic_item,
         rustc_diagnostic_macros,
         rustc_dirty,
         trait_alias,
         trait_upcasting,
         transmute,
+        transmute_trait,
         transparent,
         transparent_enums,
         transparent_unions,
index ca1d1302ec68ac8960ff88828d8136c7e3649331..639ce64a9f557c3b404383ea1b78751bb735b8cd 100644 (file)
@@ -14,7 +14,6 @@
 mod mips;
 mod mips64;
 mod msp430;
-mod nvptx;
 mod nvptx64;
 mod powerpc;
 mod powerpc64;
@@ -669,8 +668,10 @@ pub fn adjust_for_foreign_abi<C>(
 
         match &cx.target_spec().arch[..] {
             "x86" => {
-                let flavor = if let spec::abi::Abi::Fastcall { .. } = abi {
-                    x86::Flavor::Fastcall
+                let flavor = if let spec::abi::Abi::Fastcall { .. }
+                | spec::abi::Abi::Vectorcall { .. } = abi
+                {
+                    x86::Flavor::FastcallOrVectorcall
                 } else {
                     x86::Flavor::General
                 };
@@ -700,7 +701,6 @@ pub fn adjust_for_foreign_abi<C>(
             "msp430" => msp430::compute_abi_info(self),
             "sparc" => sparc::compute_abi_info(cx, self),
             "sparc64" => sparc64::compute_abi_info(cx, self),
-            "nvptx" => nvptx::compute_abi_info(self),
             "nvptx64" => {
                 if cx.target_spec().adjust_abi(abi) == spec::abi::Abi::PtxKernel {
                     nvptx64::compute_ptx_kernel_abi_info(cx, self)
diff --git a/compiler/rustc_target/src/abi/call/nvptx.rs b/compiler/rustc_target/src/abi/call/nvptx.rs
deleted file mode 100644 (file)
index 428dd95..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-// Reference: PTX Writer's Guide to Interoperability
-// https://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability
-
-use crate::abi::call::{ArgAbi, FnAbi};
-
-fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
-    if ret.layout.is_aggregate() && ret.layout.size.bits() > 32 {
-        ret.make_indirect();
-    } else {
-        ret.extend_integer_width_to(32);
-    }
-}
-
-fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) {
-    if arg.layout.is_aggregate() && arg.layout.size.bits() > 32 {
-        arg.make_indirect();
-    } else {
-        arg.extend_integer_width_to(32);
-    }
-}
-
-pub fn compute_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) {
-    if !fn_abi.ret.is_ignore() {
-        classify_ret(&mut fn_abi.ret);
-    }
-
-    for arg in &mut fn_abi.args {
-        if arg.is_ignore() {
-            continue;
-        }
-        classify_arg(arg);
-    }
-}
index d169087dfbdab26b81dd502b34d777db1d874130..c7d59baf9191f0667b4650d2ee77b099c4934ccd 100644 (file)
@@ -5,7 +5,7 @@
 #[derive(PartialEq)]
 pub enum Flavor {
     General,
-    Fastcall,
+    FastcallOrVectorcall,
 }
 
 pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, flavor: Flavor)
@@ -60,9 +60,9 @@ pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, flavor: F
         }
     }
 
-    if flavor == Flavor::Fastcall {
+    if flavor == Flavor::FastcallOrVectorcall {
         // Mark arguments as InReg like clang does it,
-        // so our fastcall is compatible with C/C++ fastcall.
+        // so our fastcall/vectorcall is compatible with C/C++ fastcall/vectorcall.
 
         // Clang reference: lib/CodeGen/TargetInfo.cpp
         // See X86_32ABIInfo::shouldPrimitiveUseInReg(), X86_32ABIInfo::updateFreeRegs()
index d4d5674e246d86f0a5e68bfa71e552d1c069d1ad..92ce4d91d84d1baeaf9288d034066107c2b908cb 100644 (file)
@@ -508,6 +508,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 
 impl Align {
     pub const ONE: Align = Align { pow2: 0 };
+    pub const MAX: Align = Align { pow2: 29 };
 
     #[inline]
     pub fn from_bits(bits: u64) -> Result<Align, String> {
@@ -540,7 +541,7 @@ fn too_large(align: u64) -> String {
         if bytes != 1 {
             return Err(not_power_of_2(align));
         }
-        if pow2 > 29 {
+        if pow2 > Self::MAX.pow2 {
             return Err(too_large(align));
         }
 
index 9d36e37d7b82ec5dccc3eb1f7f22d62afad7bacf..6d919a4c2ad2e1221dd7e0bbf010f7ebfecc066f 100644 (file)
@@ -1,20 +1,20 @@
-use crate::spec::{FramePointer, LinkerFlavor, SanitizerSet, Target, TargetOptions};
+use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let mut base = super::apple_base::opts("macos");
+    let arch = "arm64";
+    let mut base = super::apple_base::opts("macos", arch, "");
     base.cpu = "apple-a14".into();
     base.max_atomic_width = Some(128);
 
     // FIXME: The leak sanitizer currently fails the tests, see #88132.
     base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::THREAD;
 
-    base.add_pre_link_args(LinkerFlavor::Gcc, &["-arch", "arm64"]);
     base.link_env_remove.to_mut().extend(super::apple_base::macos_link_env_remove());
 
     // Clang automatically chooses a more specific target based on
     // MACOSX_DEPLOYMENT_TARGET.  To enable cross-language LTO to work
     // correctly, we do too.
-    let llvm_target = super::apple_base::macos_llvm_target("arm64");
+    let llvm_target = super::apple_base::macos_llvm_target(arch);
 
     Target {
         llvm_target: llvm_target.into(),
index 57634cbbfb1e36270ba72ceb2b3ea5265a3c1d55..1dad07a9a42a4012046a6af46a92ff87dcb9c89b 100644 (file)
@@ -1,9 +1,14 @@
 use super::apple_sdk_base::{opts, Arch};
-use crate::spec::{FramePointer, Target, TargetOptions};
+use crate::spec::{FramePointer, LinkerFlavor, Target, TargetOptions};
 
 pub fn target() -> Target {
+    let llvm_target = "arm64-apple-ios14.0-macabi";
+
+    let mut base = opts("ios", Arch::Arm64_macabi);
+    base.add_pre_link_args(LinkerFlavor::Gcc, &["-target", llvm_target]);
+
     Target {
-        llvm_target: "arm64-apple-ios14.0-macabi".into(),
+        llvm_target: llvm_target.into(),
         pointer_width: 64,
         data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".into(),
         arch: "aarch64".into(),
@@ -21,7 +26,7 @@ pub fn target() -> Target {
                 -disable-llvm-passes\0\
                 -Os\0"
                 .into(),
-            ..opts("ios", Arch::Arm64_macabi)
+            ..base
         },
     }
 }
index dc06597db6fd4a99728a837362248300b3b3075a..2bf83a8782a1273a56eeeb04c4b52548bea9260f 100644 (file)
@@ -10,6 +10,6 @@ pub fn opts() -> TargetOptions {
     // for context. (At that time, there was no `-C force-unwind-tables`, so the only solution
     // was to always emit `uwtable`).
     base.default_uwtable = true;
-    base.crt_static_respected = false;
+    base.crt_static_respected = true;
     base
 }
index 9bfae46ef32d2301a4d158278a3121e3633f4e1a..db38ff50c78786212e0a3fba879f921929f4dd80 100644 (file)
@@ -1,8 +1,45 @@
 use std::{borrow::Cow, env};
 
-use crate::spec::{cvs, FramePointer, LldFlavor, SplitDebuginfo, TargetOptions};
+use crate::spec::{cvs, FramePointer, SplitDebuginfo, TargetOptions};
+use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor};
+
+fn pre_link_args(os: &'static str, arch: &'static str, abi: &'static str) -> LinkArgs {
+    let mut args = LinkArgs::new();
+
+    let platform_name = match abi {
+        "sim" => format!("{}-simulator", os),
+        "macabi" => "mac-catalyst".to_string(),
+        _ => os.to_string(),
+    };
+
+    let platform_version = match os.as_ref() {
+        "ios" => ios_lld_platform_version(),
+        "tvos" => tvos_lld_platform_version(),
+        "watchos" => watchos_lld_platform_version(),
+        "macos" => macos_lld_platform_version(arch),
+        _ => unreachable!(),
+    };
+
+    if abi != "macabi" {
+        args.insert(LinkerFlavor::Gcc, vec!["-arch".into(), arch.into()]);
+    }
+
+    args.insert(
+        LinkerFlavor::Lld(LldFlavor::Ld64),
+        vec![
+            "-arch".into(),
+            arch.into(),
+            "-platform_version".into(),
+            platform_name.into(),
+            platform_version.clone().into(),
+            platform_version.into(),
+        ],
+    );
+
+    args
+}
 
-pub fn opts(os: &'static str) -> TargetOptions {
+pub fn opts(os: &'static str, arch: &'static str, abi: &'static str) -> TargetOptions {
     // ELF TLS is only available in macOS 10.7+. If you try to compile for 10.6
     // either the linker will complain if it is used or the binary will end up
     // segfaulting at runtime when run on 10.6. Rust by default supports macOS
@@ -24,6 +61,7 @@ pub fn opts(os: &'static str) -> TargetOptions {
         // macOS has -dead_strip, which doesn't rely on function_sections
         function_sections: false,
         dynamic_linking: true,
+        pre_link_args: pre_link_args(os, arch, abi),
         linker_is_gnu: false,
         families: cvs!["unix"],
         is_like_osx: true,
@@ -73,6 +111,11 @@ fn macos_deployment_target(arch: &str) -> (u32, u32) {
         .unwrap_or_else(|| macos_default_deployment_target(arch))
 }
 
+fn macos_lld_platform_version(arch: &str) -> String {
+    let (major, minor) = macos_deployment_target(arch);
+    format!("{}.{}", major, minor)
+}
+
 pub fn macos_llvm_target(arch: &str) -> String {
     let (major, minor) = macos_deployment_target(arch);
     format!("{}-apple-macosx{}.{}.0", arch, major, minor)
@@ -109,15 +152,34 @@ pub fn ios_llvm_target(arch: &str) -> String {
     format!("{}-apple-ios{}.{}.0", arch, major, minor)
 }
 
+fn ios_lld_platform_version() -> String {
+    let (major, minor) = ios_deployment_target();
+    format!("{}.{}", major, minor)
+}
+
 pub fn ios_sim_llvm_target(arch: &str) -> String {
     let (major, minor) = ios_deployment_target();
     format!("{}-apple-ios{}.{}.0-simulator", arch, major, minor)
 }
 
+fn tvos_deployment_target() -> (u32, u32) {
+    deployment_target("TVOS_DEPLOYMENT_TARGET").unwrap_or((7, 0))
+}
+
+fn tvos_lld_platform_version() -> String {
+    let (major, minor) = tvos_deployment_target();
+    format!("{}.{}", major, minor)
+}
+
 fn watchos_deployment_target() -> (u32, u32) {
     deployment_target("WATCHOS_DEPLOYMENT_TARGET").unwrap_or((5, 0))
 }
 
+fn watchos_lld_platform_version() -> String {
+    let (major, minor) = watchos_deployment_target();
+    format!("{}.{}", major, minor)
+}
+
 pub fn watchos_sim_llvm_target(arch: &str) -> String {
     let (major, minor) = watchos_deployment_target();
     format!("{}-apple-watchos{}.{}.0-simulator", arch, major, minor)
index 0328ea98c48cb62a93ea097fa458081179b31d59..bf3ebaa2840f6810b1caf31c2466d5ec59d8cc06 100644 (file)
@@ -1,4 +1,4 @@
-use crate::{spec::cvs, spec::TargetOptions};
+use crate::spec::{cvs, TargetOptions};
 use std::borrow::Cow;
 
 use Arch::*;
@@ -17,6 +17,18 @@ pub enum Arch {
     Arm64_sim,
 }
 
+fn target_arch_name(arch: Arch) -> &'static str {
+    match arch {
+        Armv7 => "armv7",
+        Armv7k => "armv7k",
+        Armv7s => "armv7s",
+        Arm64 | Arm64_macabi | Arm64_sim => "arm64",
+        Arm64_32 => "arm64_32",
+        I386 => "i386",
+        X86_64 | X86_64_macabi => "x86_64",
+    }
+}
+
 fn target_abi(arch: Arch) -> &'static str {
     match arch {
         Armv7 | Armv7k | Armv7s | Arm64 | Arm64_32 | I386 | X86_64 => "",
@@ -56,6 +68,6 @@ pub fn opts(os: &'static str, arch: Arch) -> TargetOptions {
         dynamic_linking: false,
         link_env_remove: link_env_remove(arch),
         has_thread_local: false,
-        ..super::apple_base::opts(os)
+        ..super::apple_base::opts(os, target_arch_name(arch), target_abi(arch))
     }
 }
diff --git a/compiler/rustc_target/src/spec/armv4t_none_eabi.rs b/compiler/rustc_target/src/spec/armv4t_none_eabi.rs
new file mode 100644 (file)
index 0000000..a76ffe8
--- /dev/null
@@ -0,0 +1,54 @@
+//! Targets the ARMv4T, with code as `a32` code by default.
+//!
+//! Primarily of use for the GBA, but usable with other devices too.
+//!
+//! Please ping @Lokathor if changes are needed.
+//!
+//! This target profile assumes that you have the ARM binutils in your path
+//! (specifically the linker, `arm-none-eabi-ld`). They can be obtained for free
+//! for all major OSes from the ARM developer's website, and they may also be
+//! available in your system's package manager. Unfortunately, the standard
+//! linker that Rust uses (`lld`) only supports as far back as `ARMv5TE`, so we
+//! must use the GNU `ld` linker.
+//!
+//! **Important:** This target profile **does not** specify a linker script. You
+//! just get the default link script when you build a binary for this target.
+//! The default link script is very likely wrong, so you should use
+//! `-Clink-arg=-Tmy_script.ld` to override that with a correct linker script.
+
+use crate::spec::{cvs, LinkerFlavor, PanicStrategy, RelocModel, Target, TargetOptions};
+
+pub fn target() -> Target {
+    Target {
+        llvm_target: "armv4t-none-eabi".into(),
+        pointer_width: 32,
+        arch: "arm".into(),
+        /* Data layout args are '-' separated:
+         * little endian
+         * stack is 64-bit aligned (EABI)
+         * pointers are 32-bit
+         * i64 must be 64-bit aligned (EABI)
+         * mangle names with ELF style
+         * native integers are 32-bit
+         * All other elements are default
+         */
+        data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
+        options: TargetOptions {
+            abi: "eabi".into(),
+            linker_flavor: LinkerFlavor::Ld,
+            linker: Some("arm-none-eabi-ld".into()),
+            asm_args: cvs!["-mthumb-interwork", "-march=armv4t", "-mlittle-endian",],
+            features: "+soft-float,+strict-align".into(),
+            main_needs_argc_argv: false,
+            atomic_cas: false,
+            has_thumb_interworking: true,
+            relocation_model: RelocModel::Static,
+            panic_strategy: PanicStrategy::Abort,
+            // from thumb_base, rust-lang/rust#44993.
+            emit_debug_gdb_scripts: false,
+            // from thumb_base, apparently gcc/clang give enums a minimum of 8 bits on no-os targets
+            c_enum_min_bits: 8,
+            ..Default::default()
+        },
+    }
+}
index df1e3275f73738932dc05ac8a57be68d0bb5ca20..962ad0c66d914b502f92b6640703b2c08b637814 100644 (file)
@@ -1,6 +1,11 @@
 use crate::spec::{crt_objects, cvs, LinkOutputKind, LinkerFlavor, LldFlavor, TargetOptions};
 
 pub fn opts() -> TargetOptions {
+    // This mirrors the linker options provided by clang. We presume lld for
+    // now. When using clang as the linker it will supply these options for us,
+    // so we only list them for ld/lld.
+    //
+    // https://github.com/llvm/llvm-project/blob/db9322b2066c55254e7691efeab863f43bfcc084/clang/lib/Driver/ToolChains/Fuchsia.cpp#L31
     let pre_link_args = TargetOptions::link_args(
         LinkerFlavor::Ld,
         &[
index 1718bd77b868fc9a72ff1004c171cb8f6ffcc6a7..5e9ceb844f73cd978c287b0c47cd4dfe23f5198e 100644 (file)
@@ -1,7 +1,8 @@
 use crate::spec::{FramePointer, LinkerFlavor, StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let mut base = super::apple_base::opts("macos");
+    // ld64 only understand i386 and not i686
+    let mut base = super::apple_base::opts("macos", "i386", "");
     base.cpu = "yonah".into();
     base.max_atomic_width = Some(64);
     base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32"]);
index c7c5a23190102c4c67f1c234df95f1ff0d4bfaf4..1db6db78b17e4f8e0e7125270f6110ccbf843b55 100644 (file)
@@ -46,7 +46,10 @@ fn check_consistency(&self) {
                         )
                     }
                     (LinkerFlavor::Gcc, LldFlavor::Ld64) => {
-                        assert_matches!(flavor, LinkerFlavor::Gcc)
+                        assert_matches!(
+                            flavor,
+                            LinkerFlavor::Lld(LldFlavor::Ld64) | LinkerFlavor::Gcc
+                        )
                     }
                     (LinkerFlavor::Msvc | LinkerFlavor::Lld(LldFlavor::Link), LldFlavor::Link) => {
                         assert_matches!(
index 2546ab9b7e6809833cb339f941983a22d67bcbff..c9bb0112f0e3d154498c817678207010722e9bb5 100644 (file)
@@ -13,7 +13,9 @@ pub fn target() -> Target {
             abi: "eabi".into(),
             // The ARMv6-M architecture doesn't support unaligned loads/stores so we disable them
             // with +strict-align.
-            features: "+strict-align".into(),
+            // Also force-enable 32-bit atomics, which allows the use of atomic load/store only.
+            // The resulting atomics are ABI incompatible with atomics backed by libatomic.
+            features: "+strict-align,+atomics-32".into(),
             // There are no atomic CAS instructions available in the instruction set of the ARMv6-M
             // architecture
             atomic_cas: false,
index dbd26899c1899e2a02562690e188ec4b0ef5fb73..176c9dd6b764b8a6932a0edcfae3a0780dd7c936 100644 (file)
@@ -2,11 +2,12 @@
 use crate::spec::{FramePointer, LinkerFlavor, SanitizerSet, StackProbeType, Target};
 
 pub fn target() -> Target {
-    let mut base = super::apple_base::opts("macos");
+    let arch = "x86_64";
+    let mut base = super::apple_base::opts("macos", arch, "");
     base.cpu = "core2".into();
     base.max_atomic_width = Some(128); // core2 support cmpxchg16b
     base.frame_pointer = FramePointer::Always;
-    base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64", "-arch", "x86_64"]);
+    base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]);
     base.link_env_remove.to_mut().extend(super::apple_base::macos_link_env_remove());
     // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
     base.stack_probes = StackProbeType::Call;
@@ -16,7 +17,6 @@ pub fn target() -> Target {
     // Clang automatically chooses a more specific target based on
     // MACOSX_DEPLOYMENT_TARGET.  To enable cross-language LTO to work
     // correctly, we do too.
-    let arch = "x86_64";
     let llvm_target = super::apple_base::macos_llvm_target(&arch);
 
     Target {
index c75632571ad38d100450cb96ddd8467c892bfa2f..2122bcd37fc07aae6f95e39968884bd7ee3e43ce 100644 (file)
@@ -1,10 +1,14 @@
 use super::apple_sdk_base::{opts, Arch};
-use crate::spec::{StackProbeType, Target, TargetOptions};
+use crate::spec::{LinkerFlavor, StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = opts("ios", Arch::X86_64_macabi);
+    let llvm_target = "x86_64-apple-ios13.0-macabi";
+
+    let mut base = opts("ios", Arch::X86_64_macabi);
+    base.add_pre_link_args(LinkerFlavor::Gcc, &["-target", llvm_target]);
+
     Target {
-        llvm_target: "x86_64-apple-ios13.0-macabi".into(),
+        llvm_target: llvm_target.into(),
         pointer_width: 64,
         data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .into(),
index aebeb49e623b9a36cdb6450dd8095ed7a5a49b2c..566f236f26a8c7061587937dcc40780f49dcb592 100644 (file)
@@ -23,4 +23,5 @@ rustc_query_system = { path = "../rustc_query_system" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
 rustc_target = { path = "../rustc_target" }
+rustc_transmute = { path = "../rustc_transmute", features = ["rustc"] }
 smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
index 5763e6d1b559ed78de22923792b0ba4f16629cbd..6b230210888503d1c34412684eff79fbacd4f186 100644 (file)
@@ -205,10 +205,8 @@ pub fn find_auto_trait_generics<A>(
             // At this point, we already have all of the bounds we need. FulfillmentContext is used
             // to store all of the necessary region/lifetime bounds in the InferContext, as well as
             // an additional sanity check.
-            let mut fulfill = FulfillmentContext::new();
-            fulfill.register_bound(&infcx, full_env, ty, trait_did, ObligationCause::dummy());
-            let errors = fulfill.select_all_or_error(&infcx);
-
+            let errors =
+                super::fully_solve_bound(&infcx, ObligationCause::dummy(), full_env, ty, trait_did);
             if !errors.is_empty() {
                 panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, errors);
             }
index 5fcaa52d41747ad2124cc701f54b9dec3ccc9646..c0700748c79f9d7df78b0bf21458e92ebd509974 100644 (file)
@@ -5,7 +5,7 @@
 
 use crate::infer::{DefiningAnchor, TyCtxtInferExt};
 use crate::traits::{
-    FulfillmentContext, ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine,
+    ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine, TraitEngineExt,
     Unimplemented,
 };
 use rustc_middle::traits::CodegenObligationError;
@@ -23,8 +23,6 @@ pub fn codegen_fulfill_obligation<'tcx>(
     tcx: TyCtxt<'tcx>,
     (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>),
 ) -> Result<&'tcx ImplSource<'tcx, ()>, CodegenObligationError> {
-    // Remove any references to regions; this helps improve caching.
-    let trait_ref = tcx.erase_regions(trait_ref);
     // We expect the input to be fully normalized.
     debug_assert_eq!(trait_ref, tcx.normalize_erasing_regions(param_env, trait_ref));
 
@@ -55,7 +53,7 @@ pub fn codegen_fulfill_obligation<'tcx>(
         // Currently, we use a fulfillment context to completely resolve
         // all nested obligations. This is because they can inform the
         // inference of the impl's type parameters.
-        let mut fulfill_cx = FulfillmentContext::new();
+        let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(tcx);
         let impl_source = selection.map(|predicate| {
             fulfill_cx.register_predicate_obligation(&infcx, predicate);
         });
index f62ccb99df5ebf12118cfff4e460caaed5eec5e5..8ab1aa65d3a9f43dccd5460bbdc5f3dce4af1a1e 100644 (file)
 use crate::traits::util::impl_subject_and_oblig;
 use crate::traits::SkipLeakCheck;
 use crate::traits::{
-    self, FulfillmentContext, Normalized, Obligation, ObligationCause, PredicateObligation,
-    PredicateObligations, SelectionContext,
+    self, Normalized, Obligation, ObligationCause, PredicateObligation, PredicateObligations,
+    SelectionContext,
 };
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::Diagnostic;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
-use rustc_infer::traits::{util, TraitEngine};
+use rustc_infer::traits::util;
 use rustc_middle::traits::specialization_graph::OverlapMode;
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
 use rustc_middle::ty::subst::Subst;
@@ -302,7 +302,6 @@ fn negative_impl<'cx, 'tcx>(
         let impl_env = tcx.param_env(impl1_def_id);
         let subject1 = match traits::fully_normalize(
             &infcx,
-            FulfillmentContext::new(),
             ObligationCause::dummy(),
             impl_env,
             tcx.impl_subject(impl1_def_id),
@@ -385,16 +384,11 @@ fn resolve_negative_obligation<'cx, 'tcx>(
         return false;
     };
 
-    let mut fulfillment_cx = FulfillmentContext::new();
-    fulfillment_cx.register_predicate_obligation(infcx, o);
-
-    let errors = fulfillment_cx.select_all_or_error(infcx);
-
+    let errors = super::fully_solve_obligation(infcx, o);
     if !errors.is_empty() {
         return false;
     }
 
-    // FIXME -- also add "assumed to be well formed" types into the `outlives_env`
     let outlives_env = OutlivesEnvironment::new(param_env);
     infcx.process_registered_region_obligations(outlives_env.region_bound_pairs(), param_env);
 
index 7ee3fe844b5a8cb1ce8071193f1237804c9b1809..e4f918b4b0eaebce14bb850d5da16da1115b5fde 100644 (file)
@@ -1315,6 +1315,13 @@ fn report_projection_error(
         error: &MismatchedProjectionTypes<'tcx>,
     );
 
+    fn maybe_detailed_projection_msg(
+        &self,
+        pred: ty::ProjectionPredicate<'tcx>,
+        normalized_ty: ty::Term<'tcx>,
+        expected_ty: ty::Term<'tcx>,
+    ) -> Option<String>;
+
     fn fuzzy_match_tys(
         &self,
         a: Ty<'tcx>,
@@ -1542,23 +1549,19 @@ fn report_projection_error(
                     normalized_ty,
                     data.term,
                 ) {
-                    values = Some(infer::ValuePairs::Terms(ExpectedFound::new(
-                        is_normalized_ty_expected,
-                        normalized_ty,
-                        data.term,
-                    )));
+                    values = Some((data, is_normalized_ty_expected, normalized_ty, data.term));
                     err_buf = error;
                     err = &err_buf;
                 }
             }
 
-            let mut diag = struct_span_err!(
-                self.tcx.sess,
-                obligation.cause.span,
-                E0271,
-                "type mismatch resolving `{}`",
-                predicate
-            );
+            let msg = values
+                .and_then(|(predicate, _, normalized_ty, expected_ty)| {
+                    self.maybe_detailed_projection_msg(predicate, normalized_ty, expected_ty)
+                })
+                .unwrap_or_else(|| format!("type mismatch resolving `{}`", predicate));
+            let mut diag = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271, "{msg}");
+
             let secondary_span = match predicate.kind().skip_binder() {
                 ty::PredicateKind::Projection(proj) => self
                     .tcx
@@ -1596,7 +1599,13 @@ fn report_projection_error(
                 &mut diag,
                 &obligation.cause,
                 secondary_span,
-                values,
+                values.map(|(_, is_normalized_ty_expected, normalized_ty, term)| {
+                    infer::ValuePairs::Terms(ExpectedFound::new(
+                        is_normalized_ty_expected,
+                        normalized_ty,
+                        term,
+                    ))
+                }),
                 err,
                 true,
                 false,
@@ -1606,6 +1615,33 @@ fn report_projection_error(
         });
     }
 
+    fn maybe_detailed_projection_msg(
+        &self,
+        pred: ty::ProjectionPredicate<'tcx>,
+        normalized_ty: ty::Term<'tcx>,
+        expected_ty: ty::Term<'tcx>,
+    ) -> Option<String> {
+        let trait_def_id = pred.projection_ty.trait_def_id(self.tcx);
+        let self_ty = pred.projection_ty.self_ty();
+
+        if Some(pred.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output() {
+            Some(format!(
+                "expected `{self_ty}` to be a {fn_kind} that returns `{expected_ty}`, but it returns `{normalized_ty}`",
+                fn_kind = self_ty.prefix_string(self.tcx)
+            ))
+        } else if Some(trait_def_id) == self.tcx.lang_items().future_trait() {
+            Some(format!(
+                "expected `{self_ty}` to be a future that resolves to `{expected_ty}`, but it resolves to `{normalized_ty}`"
+            ))
+        } else if Some(trait_def_id) == self.tcx.get_diagnostic_item(sym::Iterator) {
+            Some(format!(
+                "expected `{self_ty}` to be an iterator that yields `{expected_ty}`, but it yields `{normalized_ty}`"
+            ))
+        } else {
+            None
+        }
+    }
+
     fn fuzzy_match_tys(
         &self,
         mut a: Ty<'tcx>,
@@ -2129,7 +2165,7 @@ fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
                             }
                         ] = path.segments
                         && data.trait_ref.def_id == *trait_id
-                        && self.tcx.trait_of_item(item_id) == Some(*trait_id)
+                        && self.tcx.trait_of_item(*item_id) == Some(*trait_id)
                         && !self.is_tainted_by_errors()
                     {
                         let (verb, noun) = match self.tcx.associated_item(item_id).kind {
index 7e8872d90182824ba2bb007c7b8be1e016434158..e6907637c57b628fbd6dca7622411f3b2b97b968 100644 (file)
@@ -223,8 +223,7 @@ fn on_unimplemented_note(
                 if let Some(def) = aty.ty_adt_def() {
                     // We also want to be able to select the slice's type's original
                     // signature with no type arguments resolved
-                    let type_string = self.tcx.type_of(def.did()).to_string();
-                    flags.push((sym::_Self, Some(format!("[{type_string}]"))));
+                    flags.push((sym::_Self, Some(format!("[{}]", self.tcx.type_of(def.did())))));
                 }
                 if aty.is_integral() {
                     flags.push((sym::_Self, Some("[{integral}]".to_string())));
@@ -242,10 +241,10 @@ fn on_unimplemented_note(
                 if let Some(def) = aty.ty_adt_def() {
                     // We also want to be able to select the array's type's original
                     // signature with no type arguments resolved
-                    let type_string = self.tcx.type_of(def.did()).to_string();
-                    flags.push((sym::_Self, Some(format!("[{type_string}; _]"))));
+                    let def_ty = self.tcx.type_of(def.did());
+                    flags.push((sym::_Self, Some(format!("[{def_ty}; _]"))));
                     if let Some(n) = len {
-                        flags.push((sym::_Self, Some(format!("[{type_string}; {n}]"))));
+                        flags.push((sym::_Self, Some(format!("[{def_ty}; {n}]"))));
                     }
                 }
                 if aty.is_integral() {
index b2eb8fdf8a5444dda1e66b09bd68d607cce5302a..219413121d812cc4190183359fdb86e04719f9ba 100644 (file)
@@ -1946,7 +1946,6 @@ fn note_obligation_cause_for_async_await(
             ));
 
             let original_span = err.span.primary_span().unwrap();
-            let original_span = self.tcx.sess.source_map().guess_head_span(original_span);
             let mut span = MultiSpan::from_span(original_span);
 
             let message = outer_generator
@@ -2715,7 +2714,7 @@ fn note_obligation_cause_code<T>(
                 if let Some(ident) = self
                     .tcx
                     .opt_associated_item(trait_item_def_id)
-                    .and_then(|i| self.tcx.opt_item_ident(i.container.id()))
+                    .and_then(|i| self.tcx.opt_item_ident(i.container_id(self.tcx)))
                 {
                     assoc_span.push_span_label(ident.span, "in this trait");
                 }
index dd2769c7186981273fa6c87d4be513d348cab8d4..e1bd48ba8aca81f5df0702327299483080a72216 100644 (file)
@@ -63,8 +63,7 @@ pub fn can_type_implement_copy<'tcx>(
                 } else {
                     ObligationCause::dummy_with_span(span)
                 };
-                let ctx = traits::FulfillmentContext::new();
-                match traits::fully_normalize(&infcx, ctx, cause, param_env, ty) {
+                match traits::fully_normalize(&infcx, cause, param_env, ty) {
                     Ok(ty) => {
                         if !infcx.type_is_copy_modulo_regions(param_env, ty, span) {
                             infringing.push((field, ty));
index d0a17f712d3dfc24e46c9d8b9c902f6a0dc97813..b6d6df1eec6a12a56d3bd570f4a61eb04a25793d 100644 (file)
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
+use rustc_infer::traits::TraitEngineExt as _;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
 use rustc_middle::ty::visit::TypeVisitable;
-use rustc_middle::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry};
+use rustc_middle::ty::{
+    self, DefIdTree, GenericParamDefKind, Subst, ToPredicate, Ty, TyCtxt, TypeSuperVisitable,
+    VtblEntry,
+};
 use rustc_span::{sym, Span};
 use smallvec::SmallVec;
 
@@ -161,22 +165,20 @@ pub fn type_known_to_meet_bound_modulo_regions<'a, 'tcx>(
         // this function's result remains infallible, we must confirm
         // that guess. While imperfect, I believe this is sound.
 
-        // The handling of regions in this area of the code is terrible,
-        // see issue #29149. We should be able to improve on this with
-        // NLL.
-        let mut fulfill_cx = FulfillmentContext::new();
-
         // We can use a dummy node-id here because we won't pay any mind
         // to region obligations that arise (there shouldn't really be any
         // anyhow).
         let cause = ObligationCause::misc(span, hir::CRATE_HIR_ID);
 
-        fulfill_cx.register_bound(infcx, param_env, ty, def_id, cause);
+        // The handling of regions in this area of the code is terrible,
+        // see issue #29149. We should be able to improve on this with
+        // NLL.
+        let errors = fully_solve_bound(infcx, cause, param_env, ty, def_id);
 
         // Note: we only assume something is `Copy` if we can
         // *definitively* show that it implements `Copy`. Otherwise,
         // assume it is move; linear is always ok.
-        match fulfill_cx.select_all_or_error(infcx).as_slice() {
+        match &errors[..] {
             [] => {
                 debug!(
                     "type_known_to_meet_bound_modulo_regions: ty={:?} bound={} success",
@@ -222,15 +224,13 @@ fn do_normalize_predicates<'tcx>(
     // them here too, and we will remove this function when
     // we move over to lazy normalization *anyway*.
     tcx.infer_ctxt().ignoring_regions().enter(|infcx| {
-        let fulfill_cx = FulfillmentContext::new();
-        let predicates =
-            match fully_normalize(&infcx, fulfill_cx, cause, elaborated_env, predicates) {
-                Ok(predicates) => predicates,
-                Err(errors) => {
-                    let reported = infcx.report_fulfillment_errors(&errors, None, false);
-                    return Err(reported);
-                }
-            };
+        let predicates = match fully_normalize(&infcx, cause, elaborated_env, predicates) {
+            Ok(predicates) => predicates,
+            Err(errors) => {
+                let reported = infcx.report_fulfillment_errors(&errors, None, false);
+                return Err(reported);
+            }
+        };
 
         debug!("do_normalize_predictes: normalized predicates = {:?}", predicates);
 
@@ -381,9 +381,9 @@ pub fn normalize_param_env_or_error<'tcx>(
     )
 }
 
+/// Normalize a type and process all resulting obligations, returning any errors
 pub fn fully_normalize<'a, 'tcx, T>(
     infcx: &InferCtxt<'a, 'tcx>,
-    mut fulfill_cx: FulfillmentContext<'tcx>,
     cause: ObligationCause<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     value: T,
@@ -399,8 +399,10 @@ pub fn fully_normalize<'a, 'tcx, T>(
         "fully_normalize: normalized_value={:?} obligations={:?}",
         normalized_value, obligations
     );
+
+    let mut fulfill_cx = FulfillmentContext::new();
     for obligation in obligations {
-        fulfill_cx.register_predicate_obligation(selcx.infcx(), obligation);
+        fulfill_cx.register_predicate_obligation(infcx, obligation);
     }
 
     debug!("fully_normalize: select_all_or_error start");
@@ -414,6 +416,43 @@ pub fn fully_normalize<'a, 'tcx, T>(
     Ok(resolved_value)
 }
 
+/// Process an obligation (and any nested obligations that come from it) to
+/// completion, returning any errors
+pub fn fully_solve_obligation<'a, 'tcx>(
+    infcx: &InferCtxt<'a, 'tcx>,
+    obligation: PredicateObligation<'tcx>,
+) -> Vec<FulfillmentError<'tcx>> {
+    let mut engine = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
+    engine.register_predicate_obligation(infcx, obligation);
+    engine.select_all_or_error(infcx)
+}
+
+/// Process a set of obligations (and any nested obligations that come from them)
+/// to completion
+pub fn fully_solve_obligations<'a, 'tcx>(
+    infcx: &InferCtxt<'a, 'tcx>,
+    obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>,
+) -> Vec<FulfillmentError<'tcx>> {
+    let mut engine = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
+    engine.register_predicate_obligations(infcx, obligations);
+    engine.select_all_or_error(infcx)
+}
+
+/// Process a bound (and any nested obligations that come from it) to completion.
+/// This is a convenience function for traits that have no generic arguments, such
+/// as auto traits, and builtin traits like Copy or Sized.
+pub fn fully_solve_bound<'a, 'tcx>(
+    infcx: &InferCtxt<'a, 'tcx>,
+    cause: ObligationCause<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    ty: Ty<'tcx>,
+    bound: DefId,
+) -> Vec<FulfillmentError<'tcx>> {
+    let mut engine = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
+    engine.register_bound(infcx, param_env, ty, bound, cause);
+    engine.select_all_or_error(infcx)
+}
+
 /// Normalizes the predicates and checks whether they hold in an empty environment. If this
 /// returns true, then either normalize encountered an error or one of the predicates did not
 /// hold. Used when creating vtables to check for unsatisfiable methods.
@@ -428,20 +467,13 @@ pub fn impossible_predicates<'tcx>(
         infcx.set_tainted_by_errors();
 
         let param_env = ty::ParamEnv::reveal_all();
-        let mut selcx = SelectionContext::new(&infcx);
-        let mut fulfill_cx = FulfillmentContext::new();
-        let cause = ObligationCause::dummy();
-        let Normalized { value: predicates, obligations } =
-            normalize(&mut selcx, param_env, cause.clone(), predicates);
-        for obligation in obligations {
-            fulfill_cx.register_predicate_obligation(&infcx, obligation);
-        }
+        let ocx = ObligationCtxt::new(&infcx);
+        let predicates = ocx.normalize(ObligationCause::dummy(), param_env, predicates);
         for predicate in predicates {
-            let obligation = Obligation::new(cause.clone(), param_env, predicate);
-            fulfill_cx.register_predicate_obligation(&infcx, obligation);
+            let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate);
+            ocx.register_obligation(obligation);
         }
-
-        let errors = fulfill_cx.select_all_or_error(&infcx);
+        let errors = ocx.select_all_or_error();
 
         // Clean up after ourselves
         let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
@@ -474,6 +506,77 @@ fn subst_and_check_impossible_predicates<'tcx>(
     result
 }
 
+/// Checks whether a trait's method is impossible to call on a given impl.
+///
+/// This only considers predicates that reference the impl's generics, and not
+/// those that reference the method's generics.
+fn is_impossible_method<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    (impl_def_id, trait_item_def_id): (DefId, DefId),
+) -> bool {
+    struct ReferencesOnlyParentGenerics<'tcx> {
+        tcx: TyCtxt<'tcx>,
+        generics: &'tcx ty::Generics,
+        trait_item_def_id: DefId,
+    }
+    impl<'tcx> ty::TypeVisitor<'tcx> for ReferencesOnlyParentGenerics<'tcx> {
+        type BreakTy = ();
+        fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+            // If this is a parameter from the trait item's own generics, then bail
+            if let ty::Param(param) = t.kind()
+                && let param_def_id = self.generics.type_param(param, self.tcx).def_id
+                && self.tcx.parent(param_def_id) == self.trait_item_def_id
+            {
+                return ControlFlow::BREAK;
+            }
+            t.super_visit_with(self)
+        }
+        fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+            if let ty::ReEarlyBound(param) = r.kind()
+                && let param_def_id = self.generics.region_param(&param, self.tcx).def_id
+                && self.tcx.parent(param_def_id) == self.trait_item_def_id
+            {
+                return ControlFlow::BREAK;
+            }
+            r.super_visit_with(self)
+        }
+        fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+            if let ty::ConstKind::Param(param) = ct.kind()
+                && let param_def_id = self.generics.const_param(&param, self.tcx).def_id
+                && self.tcx.parent(param_def_id) == self.trait_item_def_id
+            {
+                return ControlFlow::BREAK;
+            }
+            ct.super_visit_with(self)
+        }
+    }
+
+    let generics = tcx.generics_of(trait_item_def_id);
+    let predicates = tcx.predicates_of(trait_item_def_id);
+    let impl_trait_ref =
+        tcx.impl_trait_ref(impl_def_id).expect("expected impl to correspond to trait");
+    let param_env = tcx.param_env(impl_def_id);
+
+    let mut visitor = ReferencesOnlyParentGenerics { tcx, generics, trait_item_def_id };
+    let predicates_for_trait = predicates.predicates.iter().filter_map(|(pred, span)| {
+        if pred.visit_with(&mut visitor).is_continue() {
+            Some(Obligation::new(
+                ObligationCause::dummy_with_span(*span),
+                param_env,
+                ty::EarlyBinder(*pred).subst(tcx, impl_trait_ref.substs),
+            ))
+        } else {
+            None
+        }
+    });
+
+    tcx.infer_ctxt().ignoring_regions().enter(|ref infcx| {
+        let mut fulfill_ctxt = <dyn TraitEngine<'_>>::new(tcx);
+        fulfill_ctxt.register_predicate_obligations(infcx, predicates_for_trait);
+        !fulfill_ctxt.select_all_or_error(infcx).is_empty()
+    })
+}
+
 #[derive(Clone, Debug)]
 enum VtblSegment<'tcx> {
     MetadataDSA,
@@ -854,6 +957,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
         vtable_entries,
         vtable_trait_upcasting_coercion_new_vptr_slot,
         subst_and_check_impossible_predicates,
+        is_impossible_method,
         try_unify_abstract_consts: |tcx, param_env_and| {
             let (param_env, (a, b)) = param_env_and.into_parts();
             const_evaluatable::try_unify_abstract_consts(tcx, (a, b), param_env)
index 2921ce0ffefe1f3bb8ed32e6217c65140184b5ff..612f51309088805cab18f7733e1ace0e301bda4c 100644 (file)
@@ -690,7 +690,7 @@ fn receiver_is_dispatchable<'tcx>(
         // U: Trait<Arg1, ..., ArgN>
         let trait_predicate = {
             let substs =
-                InternalSubsts::for_item(tcx, method.container.assert_trait(), |param, _| {
+                InternalSubsts::for_item(tcx, method.trait_container(tcx).unwrap(), |param, _| {
                     if param.index == 0 {
                         unsized_self_ty.into()
                     } else {
index 4d3b0b4cf077ce9b8e282c6fad6bcdf82e5a1233..9227bbf011dbfcb2c2d43475778289ed38f2bbf5 100644 (file)
@@ -300,7 +300,7 @@ fn verify(
             match token {
                 Piece::String(_) => (), // Normal string, no need to check it
                 Piece::NextArgument(a) => match a.position {
-                    Position::ArgumentNamed(s, _) => {
+                    Position::ArgumentNamed(s) => {
                         match Symbol::intern(s) {
                             // `{Self}` is allowed
                             kw::SelfUpper => (),
@@ -386,7 +386,7 @@ pub fn format(
             .map(|p| match p {
                 Piece::String(s) => s,
                 Piece::NextArgument(a) => match a.position {
-                    Position::ArgumentNamed(s, _) => {
+                    Position::ArgumentNamed(s) => {
                         let s = Symbol::intern(s);
                         match generic_map.get(&s) {
                             Some(val) => val,
index 9de4d3a646cb306e2264b6e4179a75336b6600df..74625cc7bb750ad97814aebc77b965bd2893e43b 100644 (file)
@@ -32,7 +32,7 @@
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::visit::{MaxUniverse, TypeVisitable};
-use rustc_middle::ty::{self, EarlyBinder, Term, ToPredicate, Ty, TyCtxt};
+use rustc_middle::ty::{self, Term, ToPredicate, Ty, TyCtxt};
 use rustc_span::symbol::sym;
 
 use std::collections::BTreeMap;
@@ -619,6 +619,15 @@ fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> {
             constant.eval(self.selcx.tcx(), self.param_env)
         }
     }
+
+    #[inline]
+    fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
+        if p.allow_normalization() && needs_normalization(&p, self.param_env.reveal()) {
+            p.super_fold_with(self)
+        } else {
+            p
+        }
+    }
 }
 
 pub struct BoundVarReplacer<'me, 'tcx> {
@@ -744,10 +753,7 @@ fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
             }
             ty::ConstKind::Bound(debruijn, bound_const) if debruijn >= self.current_index => {
                 let universe = self.universe_for(debruijn);
-                let p = ty::PlaceholderConst {
-                    universe,
-                    name: ty::BoundConst { var: bound_const, ty: ct.ty() },
-                };
+                let p = ty::PlaceholderConst { universe, name: bound_const };
                 self.mapped_consts.insert(p, bound_const);
                 self.infcx
                     .tcx
@@ -1988,7 +1994,7 @@ fn confirm_impl_candidate<'cx, 'tcx>(
         return Progress { term: tcx.ty_error().into(), obligations: nested };
     };
 
-    if !assoc_ty.item.defaultness.has_value() {
+    if !assoc_ty.item.defaultness(tcx).has_value() {
         // This means that the impl is missing a definition for the
         // associated type. This error will be reported by the type
         // checker method `check_impl_items_against_trait`, so here we
@@ -2008,16 +2014,16 @@ fn confirm_impl_candidate<'cx, 'tcx>(
     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);
+    let ty = tcx.bound_type_of(assoc_ty.item.def_id);
     let is_const = matches!(tcx.def_kind(assoc_ty.item.def_id), DefKind::AssocConst);
-    let term: ty::Term<'tcx> = if is_const {
+    let term: ty::EarlyBinder<ty::Term<'tcx>> = if is_const {
         let identity_substs =
             crate::traits::InternalSubsts::identity_for_item(tcx, assoc_ty.item.def_id);
         let did = ty::WithOptConstParam::unknown(assoc_ty.item.def_id);
         let kind = ty::ConstKind::Unevaluated(ty::Unevaluated::new(did, identity_substs));
-        tcx.mk_const(ty::ConstS { ty, kind }).into()
+        ty.map_bound(|ty| tcx.mk_const(ty::ConstS { ty, kind }).into())
     } else {
-        ty.into()
+        ty.map_bound(|ty| ty.into())
     };
     if substs.len() != tcx.generics_of(assoc_ty.item.def_id).count() {
         let err = tcx.ty_error_with_message(
@@ -2027,7 +2033,7 @@ fn confirm_impl_candidate<'cx, 'tcx>(
         Progress { term: err.into(), obligations: nested }
     } else {
         assoc_ty_own_obligations(selcx, obligation, &mut nested);
-        Progress { term: EarlyBinder(term).subst(tcx, substs), obligations: nested }
+        Progress { term: term.subst(tcx, substs), obligations: nested }
     }
 }
 
@@ -2089,7 +2095,11 @@ fn assoc_def(
         return Ok(specialization_graph::LeafDef {
             item: *item,
             defining_node: impl_node,
-            finalizing_node: if item.defaultness.is_default() { None } else { Some(impl_node) },
+            finalizing_node: if item.defaultness(tcx).is_default() {
+                None
+            } else {
+                Some(impl_node)
+            },
         });
     }
 
index 449d7a7b47b1fcd82042d7156c0cb876c0ab25a2..61c556b726d6ce40a26317d9175d6e731bc378fa 100644 (file)
@@ -266,7 +266,15 @@ fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
                 debug!("QueryNormalizer: result = {:#?}", result);
                 debug!("QueryNormalizer: obligations = {:#?}", obligations);
                 self.obligations.extend(obligations);
-                Ok(result.normalized_ty)
+
+                let res = result.normalized_ty;
+                // `tcx.normalize_projection_ty` may normalize to a type that still has
+                // unevaluated consts, so keep normalizing here if that's the case.
+                if res != ty && res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) {
+                    Ok(res.try_super_fold_with(self)?)
+                } else {
+                    Ok(res)
+                }
             }
 
             ty::Projection(data) => {
@@ -305,18 +313,27 @@ fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
                 debug!("QueryNormalizer: result = {:#?}", result);
                 debug!("QueryNormalizer: obligations = {:#?}", obligations);
                 self.obligations.extend(obligations);
-                Ok(crate::traits::project::PlaceholderReplacer::replace_placeholders(
+
+                let res = crate::traits::project::PlaceholderReplacer::replace_placeholders(
                     infcx,
                     mapped_regions,
                     mapped_types,
                     mapped_consts,
                     &self.universes,
                     result.normalized_ty,
-                ))
+                );
+                // `tcx.normalize_projection_ty` may normalize to a type that still has
+                // unevaluated consts, so keep normalizing here if that's the case.
+                if res != ty && res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) {
+                    Ok(res.try_super_fold_with(self)?)
+                } else {
+                    Ok(res)
+                }
             }
 
             _ => ty.try_super_fold_with(self),
         })()?;
+
         self.cache.insert(ty, res);
         Ok(res)
     }
@@ -351,4 +368,16 @@ fn try_fold_mir_const(
             mir::ConstantKind::Val(_, _) => constant.try_super_fold_with(self)?,
         })
     }
+
+    #[inline]
+    fn try_fold_predicate(
+        &mut self,
+        p: ty::Predicate<'tcx>,
+    ) -> Result<ty::Predicate<'tcx>, Self::Error> {
+        if p.allow_normalization() && needs_normalization(&p, self.param_env.reveal()) {
+            p.try_super_fold_with(self)
+        } else {
+            Ok(p)
+        }
+    }
 }
index c99564936aad92298ec9d3c5f31896593fe32106..f6e196e31414ccc64f54044256fcc90e64108328 100644 (file)
@@ -1,11 +1,9 @@
 use crate::infer::canonical::query_response;
 use crate::infer::{InferCtxt, InferOk};
-use crate::traits::engine::TraitEngineExt as _;
+use crate::traits;
 use crate::traits::query::type_op::TypeOpOutput;
 use crate::traits::query::Fallible;
-use crate::traits::TraitEngine;
 use rustc_infer::infer::region_constraints::RegionConstraintData;
-use rustc_infer::traits::TraitEngineExt as _;
 use rustc_span::source_map::DUMMY_SP;
 
 use std::fmt;
@@ -62,8 +60,6 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
     infcx: &InferCtxt<'_, 'tcx>,
     op: impl FnOnce() -> Fallible<InferOk<'tcx, R>>,
 ) -> Fallible<(TypeOpOutput<'tcx, Op>, RegionConstraintData<'tcx>)> {
-    let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
-
     // During NLL, we expect that nobody will register region
     // obligations **except** as part of a custom type op (and, at the
     // end of each custom type op, we scrape out the region
@@ -77,8 +73,7 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
     );
 
     let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?;
-    fulfill_cx.register_predicate_obligations(infcx, obligations);
-    let errors = fulfill_cx.select_all_or_error(infcx);
+    let errors = traits::fully_solve_obligations(infcx, obligations);
     if !errors.is_empty() {
         infcx.tcx.sess.diagnostic().delay_span_bug(
             DUMMY_SP,
index 6e8581128dd8ea2a822c49a806e0238a5dfc9665..50e9b95a445fd7e340caf5b697c0c52737c77797 100644 (file)
@@ -8,7 +8,7 @@
 use hir::LangItem;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
-use rustc_infer::traits::TraitEngine;
+use rustc_infer::traits::ObligationCause;
 use rustc_infer::traits::{Obligation, SelectionError, TraitObligation};
 use rustc_lint_defs::builtin::DEREF_INTO_DYN_SUPERTRAIT;
 use rustc_middle::ty::print::with_no_trimmed_paths;
@@ -305,6 +305,10 @@ pub(super) fn assemble_candidates<'o>(
                 self.assemble_candidates_for_unsizing(obligation, &mut candidates);
             } else if lang_items.destruct_trait() == Some(def_id) {
                 self.assemble_const_destruct_candidates(obligation, &mut candidates);
+            } else if lang_items.transmute_trait() == Some(def_id) {
+                // User-defined transmutability impls are permitted.
+                self.assemble_candidates_from_impls(obligation, &mut candidates);
+                self.assemble_candidates_for_transmutability(obligation, &mut candidates);
             } else {
                 if lang_items.clone_trait() == Some(def_id) {
                     // Same builtin conditions as `Copy`, i.e., every type which has builtin support
@@ -702,8 +706,8 @@ fn assemble_candidates_from_object_ty(
     fn need_migrate_deref_output_trait_object(
         &mut self,
         ty: Ty<'tcx>,
-        cause: &traits::ObligationCause<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
+        cause: &ObligationCause<'tcx>,
     ) -> Option<(Ty<'tcx>, DefId)> {
         let tcx = self.tcx();
         if tcx.features().trait_upcasting {
@@ -725,24 +729,27 @@ fn need_migrate_deref_output_trait_object(
             return None;
         }
 
-        let mut fulfillcx = traits::FulfillmentContext::new_in_snapshot();
-        let normalized_ty = fulfillcx.normalize_projection_type(
-            &self.infcx,
+        let ty = traits::normalize_projection_type(
+            self,
             param_env,
             ty::ProjectionTy {
                 item_def_id: tcx.lang_items().deref_target()?,
                 substs: trait_ref.substs,
             },
             cause.clone(),
-        );
-
-        let ty::Dynamic(data, ..) = normalized_ty.kind() else {
-            return None;
-        };
-
-        let def_id = data.principal_def_id()?;
-
-        return Some((normalized_ty, def_id));
+            0,
+            // We're *intentionally* throwing these away,
+            // since we don't actually use them.
+            &mut vec![],
+        )
+        .ty()
+        .unwrap();
+
+        if let ty::Dynamic(data, ..) = ty.kind() {
+            Some((ty, data.principal_def_id()?))
+        } else {
+            None
+        }
     }
 
     /// Searches for unsizing that might apply to `obligation`.
@@ -805,8 +812,8 @@ fn assemble_candidates_for_unsizing(
                         if let Some((deref_output_ty, deref_output_trait_did)) = self
                             .need_migrate_deref_output_trait_object(
                                 source,
-                                &obligation.cause,
                                 obligation.param_env,
+                                &obligation.cause,
                             )
                         {
                             if deref_output_trait_did == target_trait_did {
@@ -873,6 +880,24 @@ fn assemble_candidates_for_unsizing(
         };
     }
 
+    #[tracing::instrument(level = "debug", skip(self, obligation, candidates))]
+    fn assemble_candidates_for_transmutability(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+        candidates: &mut SelectionCandidateSet<'tcx>,
+    ) {
+        if obligation.has_param_types_or_consts() {
+            return;
+        }
+
+        if obligation.has_infer_types_or_consts() {
+            candidates.ambiguous = true;
+            return;
+        }
+
+        candidates.vec.push(TransmutabilityCandidate);
+    }
+
     #[tracing::instrument(level = "debug", skip(self, obligation, candidates))]
     fn assemble_candidates_for_trait_alias(
         &mut self,
index d4c9fd1c5f9cd9abae3f9c334206b2c79a1ff43e..2a1099fc82abc5fe6312d03640aa514005294c96 100644 (file)
@@ -48,6 +48,11 @@ pub(super) fn confirm_candidate(
                 ImplSource::Builtin(data)
             }
 
+            TransmutabilityCandidate => {
+                let data = self.confirm_transmutability_candidate(obligation)?;
+                ImplSource::Builtin(data)
+            }
+
             ParamCandidate(param) => {
                 let obligations =
                     self.confirm_param_candidate(obligation, param.map_bound(|t| t.trait_ref));
@@ -139,67 +144,65 @@ fn confirm_projection_candidate(
         obligation: &TraitObligation<'tcx>,
         idx: usize,
     ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
-        self.infcx.commit_unconditionally(|_| {
-            let tcx = self.tcx();
-
-            let trait_predicate = self.infcx.shallow_resolve(obligation.predicate);
-            let placeholder_trait_predicate =
-                self.infcx().replace_bound_vars_with_placeholders(trait_predicate).trait_ref;
-            let placeholder_self_ty = placeholder_trait_predicate.self_ty();
-            let placeholder_trait_predicate = ty::Binder::dummy(placeholder_trait_predicate);
-            let (def_id, substs) = match *placeholder_self_ty.kind() {
-                ty::Projection(proj) => (proj.item_def_id, proj.substs),
-                ty::Opaque(def_id, substs) => (def_id, substs),
-                _ => bug!("projection candidate for unexpected type: {:?}", placeholder_self_ty),
-            };
+        let tcx = self.tcx();
 
-            let candidate_predicate =
-                tcx.bound_item_bounds(def_id).map_bound(|i| i[idx]).subst(tcx, substs);
-            let candidate = candidate_predicate
-                .to_opt_poly_trait_pred()
-                .expect("projection candidate is not a trait predicate")
-                .map_bound(|t| t.trait_ref);
-            let mut obligations = Vec::new();
-            let candidate = normalize_with_depth_to(
-                self,
-                obligation.param_env,
-                obligation.cause.clone(),
-                obligation.recursion_depth + 1,
-                candidate,
-                &mut obligations,
-            );
+        let trait_predicate = self.infcx.shallow_resolve(obligation.predicate);
+        let placeholder_trait_predicate =
+            self.infcx().replace_bound_vars_with_placeholders(trait_predicate).trait_ref;
+        let placeholder_self_ty = placeholder_trait_predicate.self_ty();
+        let placeholder_trait_predicate = ty::Binder::dummy(placeholder_trait_predicate);
+        let (def_id, substs) = match *placeholder_self_ty.kind() {
+            ty::Projection(proj) => (proj.item_def_id, proj.substs),
+            ty::Opaque(def_id, substs) => (def_id, substs),
+            _ => bug!("projection candidate for unexpected type: {:?}", placeholder_self_ty),
+        };
 
-            obligations.extend(self.infcx.commit_if_ok(|_| {
-                self.infcx
-                    .at(&obligation.cause, obligation.param_env)
-                    .sup(placeholder_trait_predicate, candidate)
-                    .map(|InferOk { obligations, .. }| obligations)
-                    .map_err(|_| Unimplemented)
-            })?);
-
-            if let ty::Projection(..) = placeholder_self_ty.kind() {
-                let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs).predicates;
-                debug!(?predicates, "projection predicates");
-                for predicate in predicates {
-                    let normalized = normalize_with_depth_to(
-                        self,
-                        obligation.param_env,
-                        obligation.cause.clone(),
-                        obligation.recursion_depth + 1,
-                        predicate,
-                        &mut obligations,
-                    );
-                    obligations.push(Obligation::with_depth(
-                        obligation.cause.clone(),
-                        obligation.recursion_depth + 1,
-                        obligation.param_env,
-                        normalized,
-                    ));
-                }
+        let candidate_predicate =
+            tcx.bound_item_bounds(def_id).map_bound(|i| i[idx]).subst(tcx, substs);
+        let candidate = candidate_predicate
+            .to_opt_poly_trait_pred()
+            .expect("projection candidate is not a trait predicate")
+            .map_bound(|t| t.trait_ref);
+        let mut obligations = Vec::new();
+        let candidate = normalize_with_depth_to(
+            self,
+            obligation.param_env,
+            obligation.cause.clone(),
+            obligation.recursion_depth + 1,
+            candidate,
+            &mut obligations,
+        );
+
+        obligations.extend(self.infcx.commit_if_ok(|_| {
+            self.infcx
+                .at(&obligation.cause, obligation.param_env)
+                .sup(placeholder_trait_predicate, candidate)
+                .map(|InferOk { obligations, .. }| obligations)
+                .map_err(|_| Unimplemented)
+        })?);
+
+        if let ty::Projection(..) = placeholder_self_ty.kind() {
+            let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs).predicates;
+            debug!(?predicates, "projection predicates");
+            for predicate in predicates {
+                let normalized = normalize_with_depth_to(
+                    self,
+                    obligation.param_env,
+                    obligation.cause.clone(),
+                    obligation.recursion_depth + 1,
+                    predicate,
+                    &mut obligations,
+                );
+                obligations.push(Obligation::with_depth(
+                    obligation.cause.clone(),
+                    obligation.recursion_depth + 1,
+                    obligation.param_env,
+                    normalized,
+                ));
             }
+        }
 
-            Ok(obligations)
-        })
+        Ok(obligations)
     }
 
     fn confirm_param_candidate(
@@ -267,6 +270,53 @@ fn confirm_builtin_candidate(
         ImplSourceBuiltinData { nested: obligations }
     }
 
+    fn confirm_transmutability_candidate(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+    ) -> Result<ImplSourceBuiltinData<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+        debug!(?obligation, "confirm_transmutability_candidate");
+
+        let predicate = obligation.predicate;
+
+        let type_at = |i| predicate.map_bound(|p| p.trait_ref.substs.type_at(i));
+        let bool_at = |i| {
+            predicate
+                .skip_binder()
+                .trait_ref
+                .substs
+                .const_at(i)
+                .try_eval_bool(self.tcx(), obligation.param_env)
+                .unwrap_or(true)
+        };
+
+        let src_and_dst = predicate.map_bound(|p| rustc_transmute::Types {
+            src: p.trait_ref.substs.type_at(1),
+            dst: p.trait_ref.substs.type_at(0),
+        });
+
+        let scope = type_at(2).skip_binder();
+
+        let assume = rustc_transmute::Assume {
+            alignment: bool_at(3),
+            lifetimes: bool_at(4),
+            validity: bool_at(5),
+            visibility: bool_at(6),
+        };
+
+        let cause = obligation.cause.clone();
+
+        let mut transmute_env = rustc_transmute::TransmuteTypeEnv::new(self.infcx);
+
+        let maybe_transmutable = transmute_env.is_transmutable(cause, src_and_dst, scope, assume);
+
+        use rustc_transmute::Answer;
+
+        match maybe_transmutable {
+            Answer::Yes => Ok(ImplSourceBuiltinData { nested: vec![] }),
+            _ => Err(Unimplemented),
+        }
+    }
+
     /// This handles the case where an `auto trait Foo` impl is being used.
     /// The idea is that the impl applies to `X : Foo` if the following conditions are met:
     ///
@@ -295,19 +345,16 @@ fn vtable_auto_impl(
         ensure_sufficient_stack(|| {
             let cause = obligation.derived_cause(BuiltinDerivedObligation);
 
-            let trait_obligations: Vec<PredicateObligation<'_>> =
-                self.infcx.commit_unconditionally(|_| {
-                    let poly_trait_ref = obligation.predicate.to_poly_trait_ref();
-                    let trait_ref = self.infcx.replace_bound_vars_with_placeholders(poly_trait_ref);
-                    self.impl_or_trait_obligations(
-                        &cause,
-                        obligation.recursion_depth + 1,
-                        obligation.param_env,
-                        trait_def_id,
-                        &trait_ref.substs,
-                        obligation.predicate,
-                    )
-                });
+            let poly_trait_ref = obligation.predicate.to_poly_trait_ref();
+            let trait_ref = self.infcx.replace_bound_vars_with_placeholders(poly_trait_ref);
+            let trait_obligations: Vec<PredicateObligation<'_>> = self.impl_or_trait_obligations(
+                &cause,
+                obligation.recursion_depth + 1,
+                obligation.param_env,
+                trait_def_id,
+                &trait_ref.substs,
+                obligation.predicate,
+            );
 
             let mut obligations = self.collect_predicates_for_types(
                 obligation.param_env,
@@ -336,19 +383,17 @@ fn confirm_impl_candidate(
 
         // First, create the substitutions by matching the impl again,
         // this time not in a probe.
-        self.infcx.commit_unconditionally(|_| {
-            let substs = self.rematch_impl(impl_def_id, obligation);
-            debug!(?substs, "impl substs");
-            ensure_sufficient_stack(|| {
-                self.vtable_impl(
-                    impl_def_id,
-                    substs,
-                    &obligation.cause,
-                    obligation.recursion_depth + 1,
-                    obligation.param_env,
-                    obligation.predicate,
-                )
-            })
+        let substs = self.rematch_impl(impl_def_id, obligation);
+        debug!(?substs, "impl substs");
+        ensure_sufficient_stack(|| {
+            self.vtable_impl(
+                impl_def_id,
+                substs,
+                &obligation.cause,
+                obligation.recursion_depth + 1,
+                obligation.param_env,
+                obligation.predicate,
+            )
         })
     }
 
@@ -595,25 +640,23 @@ fn confirm_trait_alias_candidate(
     ) -> ImplSourceTraitAliasData<'tcx, PredicateObligation<'tcx>> {
         debug!(?obligation, ?alias_def_id, "confirm_trait_alias_candidate");
 
-        self.infcx.commit_unconditionally(|_| {
-            let predicate = self.infcx().replace_bound_vars_with_placeholders(obligation.predicate);
-            let trait_ref = predicate.trait_ref;
-            let trait_def_id = trait_ref.def_id;
-            let substs = trait_ref.substs;
+        let predicate = self.infcx().replace_bound_vars_with_placeholders(obligation.predicate);
+        let trait_ref = predicate.trait_ref;
+        let trait_def_id = trait_ref.def_id;
+        let substs = trait_ref.substs;
 
-            let trait_obligations = self.impl_or_trait_obligations(
-                &obligation.cause,
-                obligation.recursion_depth,
-                obligation.param_env,
-                trait_def_id,
-                &substs,
-                obligation.predicate,
-            );
+        let trait_obligations = self.impl_or_trait_obligations(
+            &obligation.cause,
+            obligation.recursion_depth,
+            obligation.param_env,
+            trait_def_id,
+            &substs,
+            obligation.predicate,
+        );
 
-            debug!(?trait_def_id, ?trait_obligations, "trait alias obligations");
+        debug!(?trait_def_id, ?trait_obligations, "trait alias obligations");
 
-            ImplSourceTraitAliasData { alias_def_id, substs, nested: trait_obligations }
-        })
+        ImplSourceTraitAliasData { alias_def_id, substs, nested: trait_obligations }
     }
 
     fn confirm_generator_candidate(
@@ -711,15 +754,13 @@ fn confirm_poly_trait_refs(
         // Normalize the obligation and expected trait refs together, because why not
         let Normalized { obligations: nested, value: (obligation_trait_ref, expected_trait_ref) } =
             ensure_sufficient_stack(|| {
-                self.infcx.commit_unconditionally(|_| {
-                    normalize_with_depth(
-                        self,
-                        obligation.param_env,
-                        obligation.cause.clone(),
-                        obligation.recursion_depth + 1,
-                        (obligation_trait_ref, expected_trait_ref),
-                    )
-                })
+                normalize_with_depth(
+                    self,
+                    obligation.param_env,
+                    obligation.cause.clone(),
+                    obligation.recursion_depth + 1,
+                    (obligation_trait_ref, expected_trait_ref),
+                )
             });
 
         self.infcx
@@ -1095,32 +1136,30 @@ fn confirm_const_destruct_candidate(
         // first check it like a regular impl candidate.
         // This is copied from confirm_impl_candidate but remaps the predicate to `~const Drop` beforehand.
         if let Some(impl_def_id) = impl_def_id {
-            let obligations = self.infcx.commit_unconditionally(|_| {
-                let mut new_obligation = obligation.clone();
-                new_obligation.predicate = new_obligation.predicate.map_bound(|mut trait_pred| {
-                    trait_pred.trait_ref.def_id = drop_trait;
-                    trait_pred
-                });
-                let substs = self.rematch_impl(impl_def_id, &new_obligation);
-                debug!(?substs, "impl substs");
-
-                let cause = obligation.derived_cause(|derived| {
-                    ImplDerivedObligation(Box::new(ImplDerivedObligationCause {
-                        derived,
-                        impl_def_id,
-                        span: obligation.cause.span,
-                    }))
-                });
-                ensure_sufficient_stack(|| {
-                    self.vtable_impl(
-                        impl_def_id,
-                        substs,
-                        &cause,
-                        new_obligation.recursion_depth + 1,
-                        new_obligation.param_env,
-                        obligation.predicate,
-                    )
-                })
+            let mut new_obligation = obligation.clone();
+            new_obligation.predicate = new_obligation.predicate.map_bound(|mut trait_pred| {
+                trait_pred.trait_ref.def_id = drop_trait;
+                trait_pred
+            });
+            let substs = self.rematch_impl(impl_def_id, &new_obligation);
+            debug!(?substs, "impl substs");
+
+            let cause = obligation.derived_cause(|derived| {
+                ImplDerivedObligation(Box::new(ImplDerivedObligationCause {
+                    derived,
+                    impl_def_id,
+                    span: obligation.cause.span,
+                }))
+            });
+            let obligations = ensure_sufficient_stack(|| {
+                self.vtable_impl(
+                    impl_def_id,
+                    substs,
+                    &cause,
+                    new_obligation.recursion_depth + 1,
+                    new_obligation.param_env,
+                    obligation.predicate,
+                )
             });
             nested.extend(obligations.nested);
         }
@@ -1171,34 +1210,30 @@ fn confirm_const_destruct_candidate(
                 // If we have a projection type, make sure to normalize it so we replace it
                 // with a fresh infer variable
                 ty::Projection(..) => {
-                    self.infcx.commit_unconditionally(|_| {
-                        let predicate = normalize_with_depth_to(
-                            self,
-                            obligation.param_env,
-                            cause.clone(),
-                            obligation.recursion_depth + 1,
-                            self_ty
-                                .rebind(ty::TraitPredicate {
-                                    trait_ref: ty::TraitRef {
-                                        def_id: self
-                                            .tcx()
-                                            .require_lang_item(LangItem::Destruct, None),
-                                        substs: self.tcx().mk_substs_trait(nested_ty, &[]),
-                                    },
-                                    constness: ty::BoundConstness::ConstIfConst,
-                                    polarity: ty::ImplPolarity::Positive,
-                                })
-                                .to_predicate(tcx),
-                            &mut nested,
-                        );
-
-                        nested.push(Obligation::with_depth(
-                            cause.clone(),
-                            obligation.recursion_depth + 1,
-                            obligation.param_env,
-                            predicate,
-                        ));
-                    });
+                    let predicate = normalize_with_depth_to(
+                        self,
+                        obligation.param_env,
+                        cause.clone(),
+                        obligation.recursion_depth + 1,
+                        self_ty
+                            .rebind(ty::TraitPredicate {
+                                trait_ref: ty::TraitRef {
+                                    def_id: self.tcx().require_lang_item(LangItem::Destruct, None),
+                                    substs: self.tcx().mk_substs_trait(nested_ty, &[]),
+                                },
+                                constness: ty::BoundConstness::ConstIfConst,
+                                polarity: ty::ImplPolarity::Positive,
+                            })
+                            .to_predicate(tcx),
+                        &mut nested,
+                    );
+
+                    nested.push(Obligation::with_depth(
+                        cause.clone(),
+                        obligation.recursion_depth + 1,
+                        obligation.param_env,
+                        predicate,
+                    ));
                 }
 
                 // If we have any other type (e.g. an ADT), just register a nested obligation
index 17f34012d1dd3e2a2a2f23ad25b3ff4f09b6c8d5..c01ac197991069e8b6c9a5d2309d0d99e6186ceb 100644 (file)
@@ -1630,6 +1630,9 @@ fn candidate_should_be_dropped_in_favor_of(
                 );
             }
 
+            // FIXME(@jswrenn): this should probably be more sophisticated
+            (TransmutabilityCandidate, _) | (_, TransmutabilityCandidate) => false,
+
             // (*)
             (
                 BuiltinCandidate { has_nested: false }
@@ -1883,7 +1886,11 @@ fn sized_conditions(
                 let sized_crit = def.sized_constraint(self.tcx());
                 // (*) binder moved here
                 Where(obligation.predicate.rebind({
-                    sized_crit.iter().map(|ty| EarlyBinder(*ty).subst(self.tcx(), substs)).collect()
+                    sized_crit
+                        .0
+                        .iter()
+                        .map(|ty| sized_crit.rebind(*ty).subst(self.tcx(), substs))
+                        .collect()
                 }))
             }
 
@@ -2081,30 +2088,28 @@ fn collect_predicates_for_types(
             .flat_map(|ty| {
                 let ty: ty::Binder<'tcx, Ty<'tcx>> = types.rebind(*ty); // <----/
 
-                self.infcx.commit_unconditionally(|_| {
-                    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(
-                                self,
-                                param_env,
-                                cause.clone(),
-                                recursion_depth,
-                                placeholder_ty,
-                            )
-                        });
-                    let placeholder_obligation = predicate_for_trait_def(
-                        self.tcx(),
-                        param_env,
-                        cause.clone(),
-                        trait_def_id,
-                        recursion_depth,
-                        normalized_ty,
-                        &[],
-                    );
-                    obligations.push(placeholder_obligation);
-                    obligations
-                })
+                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(
+                            self,
+                            param_env,
+                            cause.clone(),
+                            recursion_depth,
+                            placeholder_ty,
+                        )
+                    });
+                let placeholder_obligation = predicate_for_trait_def(
+                    self.tcx(),
+                    param_env,
+                    cause.clone(),
+                    trait_def_id,
+                    recursion_depth,
+                    normalized_ty,
+                    &[],
+                );
+                obligations.push(placeholder_obligation);
+                obligations
             })
             .collect()
     }
@@ -2356,11 +2361,11 @@ fn impl_or_trait_obligations(
         // obligation will normalize to `<$0 as Iterator>::Item = $1` and
         // `$1: Copy`, so we must ensure the obligations are emitted in
         // that order.
-        let predicates = tcx.predicates_of(def_id);
+        let predicates = tcx.bound_predicates_of(def_id);
         debug!(?predicates);
-        assert_eq!(predicates.parent, None);
-        let mut obligations = Vec::with_capacity(predicates.predicates.len());
-        for (predicate, span) in predicates.predicates {
+        assert_eq!(predicates.0.parent, None);
+        let mut obligations = Vec::with_capacity(predicates.0.predicates.len());
+        for (predicate, span) in predicates.0.predicates {
             let span = *span;
             let cause = cause.clone().derived_cause(parent_trait_pred, |derived| {
                 ImplDerivedObligation(Box::new(ImplDerivedObligationCause {
@@ -2374,7 +2379,7 @@ fn impl_or_trait_obligations(
                 param_env,
                 cause.clone(),
                 recursion_depth,
-                EarlyBinder(*predicate).subst(tcx, substs),
+                predicates.rebind(*predicate).subst(tcx, substs),
                 &mut obligations,
             );
             obligations.push(Obligation { cause, recursion_depth, param_env, predicate });
index 5f77aae6f221fd4ee74007a960164a5e4c060f5e..0f76fef0eee228168c49a3d5128776dd1338574f 100644 (file)
@@ -14,7 +14,7 @@
 
 use crate::infer::{InferCtxt, InferOk, TyCtxtInferExt};
 use crate::traits::select::IntercrateAmbiguityCause;
-use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause, TraitEngine};
+use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause};
 use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
 use rustc_errors::{struct_span_err, EmissionGuarantee, LintDiagnosticBuilder};
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -25,7 +25,7 @@
 use rustc_span::{Span, DUMMY_SP};
 
 use super::util;
-use super::{FulfillmentContext, SelectionContext};
+use super::SelectionContext;
 
 /// Information pertinent to an overlapping impl error.
 #[derive(Debug)]
@@ -149,18 +149,19 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId,
 
     // Create an infcx, taking the predicates of impl1 as assumptions:
     tcx.infer_ctxt().enter(|infcx| {
-        // Normalize the trait reference. The WF rules ought to ensure
-        // that this always succeeds.
         let impl1_trait_ref = match traits::fully_normalize(
             &infcx,
-            FulfillmentContext::new(),
             ObligationCause::dummy(),
             penv,
             impl1_trait_ref,
         ) {
             Ok(impl1_trait_ref) => impl1_trait_ref,
-            Err(err) => {
-                bug!("failed to fully normalize {:?}: {:?}", impl1_trait_ref, err);
+            Err(_errors) => {
+                tcx.sess.delay_span_bug(
+                    tcx.def_span(impl1_def_id),
+                    format!("failed to fully normalize {impl1_trait_ref}"),
+                );
+                impl1_trait_ref
             }
         };
 
@@ -207,11 +208,8 @@ fn fulfill_implication<'a, 'tcx>(
     // (which are packed up in penv)
 
     infcx.save_and_restore_in_snapshot_flag(|infcx| {
-        let mut fulfill_cx = FulfillmentContext::new();
-        for oblig in obligations.chain(more_obligations) {
-            fulfill_cx.register_predicate_obligation(&infcx, oblig);
-        }
-        match fulfill_cx.select_all_or_error(infcx).as_slice() {
+        let errors = traits::fully_solve_obligations(&infcx, obligations.chain(more_obligations));
+        match &errors[..] {
             [] => {
                 debug!(
                     "fulfill_implication: an impl for {:?} specializes {:?}",
index c278752e3d9f46459a6027ebcd67307f0020624c..5829a0f92ee410a6ac17997a64629163fd6a600a 100644 (file)
@@ -1,6 +1,6 @@
 use crate::infer::{InferCtxt, TyCtxtInferExt};
 use crate::traits::ObligationCause;
-use crate::traits::{self, TraitEngine};
+use crate::traits::{TraitEngine, TraitEngineExt};
 
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
@@ -72,7 +72,7 @@ fn type_marked_structural<'tcx>(
     adt_ty: Ty<'tcx>,
     cause: ObligationCause<'tcx>,
 ) -> bool {
-    let mut fulfillment_cx = traits::FulfillmentContext::new();
+    let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
     // require `#[derive(PartialEq)]`
     let structural_peq_def_id =
         infcx.tcx.require_lang_item(LangItem::StructuralPeq, Some(cause.span));
index 3170b29ee69733777702926ac673cbfa480f0c62..d25006016629c907bf0d0f60d489900610ac3dd8 100644 (file)
@@ -6,7 +6,7 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::subst::{GenericArg, Subst, SubstsRef};
-use rustc_middle::ty::{self, EarlyBinder, ImplSubject, ToPredicate, Ty, TyCtxt, TypeVisitable};
+use rustc_middle::ty::{self, ImplSubject, ToPredicate, Ty, TyCtxt, TypeVisitable};
 
 use super::{Normalized, Obligation, ObligationCause, PredicateObligation, SelectionContext};
 pub use rustc_infer::traits::{self, util::*};
@@ -200,8 +200,8 @@ pub fn impl_subject_and_oblig<'a, 'tcx>(
     impl_def_id: DefId,
     impl_substs: SubstsRef<'tcx>,
 ) -> (ImplSubject<'tcx>, impl Iterator<Item = PredicateObligation<'tcx>>) {
-    let subject = selcx.tcx().impl_subject(impl_def_id);
-    let subject = EarlyBinder(subject).subst(selcx.tcx(), impl_substs);
+    let subject = selcx.tcx().bound_impl_subject(impl_def_id);
+    let subject = subject.subst(selcx.tcx(), impl_substs);
     let Normalized { value: subject, obligations: normalization_obligations1 } =
         super::normalize(selcx, param_env, ObligationCause::dummy(), subject);
 
@@ -358,7 +358,8 @@ pub fn generator_trait_ref_and_outputs<'tcx>(
 }
 
 pub fn impl_item_is_final(tcx: TyCtxt<'_>, assoc_item: &ty::AssocItem) -> bool {
-    assoc_item.defaultness.is_final() && tcx.impl_defaultness(assoc_item.container.id()).is_final()
+    assoc_item.defaultness(tcx).is_final()
+        && tcx.impl_defaultness(assoc_item.container_id(tcx)).is_final()
 }
 
 pub enum TupleArgumentsFlag {
index 497819ce5c567bac02148bc4b97c5803e964204a..ff5ca0cbcb7b134bf8a7e3aa73d82d9223089ca5 100644 (file)
@@ -8,9 +8,7 @@
 
 use rustc_middle::traits::ChalkRustInterner as RustInterner;
 use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
-use rustc_middle::ty::{
-    self, AssocItemContainer, AssocKind, EarlyBinder, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable,
-};
+use rustc_middle::ty::{self, AssocKind, EarlyBinder, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable};
 
 use rustc_ast::ast;
 use rustc_attr as attr;
@@ -53,11 +51,11 @@ fn bounds_for<T>(&self, def_id: DefId, bound_vars: SubstsRef<'tcx>) -> Vec<T>
     where
         ty::Predicate<'tcx>: LowerInto<'tcx, std::option::Option<T>>,
     {
-        self.interner
-            .tcx
-            .explicit_item_bounds(def_id)
+        let bounds = self.interner.tcx.bound_explicit_item_bounds(def_id);
+        bounds
+            .0
             .iter()
-            .map(|(bound, _)| EarlyBinder(*bound).subst(self.interner.tcx, &bound_vars))
+            .map(|(bound, _)| bounds.rebind(*bound).subst(self.interner.tcx, &bound_vars))
             .filter_map(|bound| LowerInto::<Option<_>>::lower_into(bound, self.interner))
             .collect()
     }
@@ -74,7 +72,7 @@ fn associated_ty_data(
     ) -> Arc<chalk_solve::rust_ir::AssociatedTyDatum<RustInterner<'tcx>>> {
         let def_id = assoc_type_id.0;
         let assoc_item = self.interner.tcx.associated_item(def_id);
-        let AssocItemContainer::TraitContainer(trait_def_id) = assoc_item.container else {
+        let Some(trait_def_id) = assoc_item.trait_container(self.interner.tcx) else {
             unimplemented!("Not possible??");
         };
         match assoc_item.kind {
@@ -270,21 +268,20 @@ fn fn_def_datum(
 
         let where_clauses = self.where_clauses_for(def_id, bound_vars);
 
-        let sig = self.interner.tcx.fn_sig(def_id);
+        let sig = self.interner.tcx.bound_fn_sig(def_id);
         let (inputs_and_output, iobinders, _) = crate::chalk::lowering::collect_bound_vars(
             self.interner,
             self.interner.tcx,
-            EarlyBinder(sig.inputs_and_output()).subst(self.interner.tcx, bound_vars),
+            sig.map_bound(|s| s.inputs_and_output()).subst(self.interner.tcx, bound_vars),
         );
 
         let argument_types = inputs_and_output[..inputs_and_output.len() - 1]
             .iter()
-            .map(|t| {
-                EarlyBinder(*t).subst(self.interner.tcx, &bound_vars).lower_into(self.interner)
-            })
+            .map(|t| sig.rebind(*t).subst(self.interner.tcx, &bound_vars).lower_into(self.interner))
             .collect();
 
-        let return_type = EarlyBinder(inputs_and_output[inputs_and_output.len() - 1])
+        let return_type = sig
+            .rebind(inputs_and_output[inputs_and_output.len() - 1])
             .subst(self.interner.tcx, &bound_vars)
             .lower_into(self.interner);
 
@@ -297,7 +294,7 @@ fn fn_def_datum(
         };
         Arc::new(chalk_solve::rust_ir::FnDefDatum {
             id: fn_def_id,
-            sig: sig.lower_into(self.interner),
+            sig: sig.0.lower_into(self.interner),
             binders: chalk_ir::Binders::new(binders, bound),
         })
     }
@@ -455,7 +452,7 @@ fn associated_ty_value(
     ) -> Arc<chalk_solve::rust_ir::AssociatedTyValue<RustInterner<'tcx>>> {
         let def_id = associated_ty_id.0;
         let assoc_item = self.interner.tcx.associated_item(def_id);
-        let impl_id = assoc_item.container.id();
+        let impl_id = assoc_item.container_id(self.interner.tcx);
         match assoc_item.kind {
             AssocKind::Type => {}
             _ => unimplemented!("Not possible??"),
@@ -505,12 +502,14 @@ fn opaque_ty_data(
 
         let identity_substs = InternalSubsts::identity_for_item(self.interner.tcx, opaque_ty_id.0);
 
+        let explicit_item_bounds = self.interner.tcx.bound_explicit_item_bounds(opaque_ty_id.0);
         let bounds =
-            self.interner
-                .tcx
-                .explicit_item_bounds(opaque_ty_id.0)
+            explicit_item_bounds
+                .0
                 .iter()
-                .map(|(bound, _)| EarlyBinder(*bound).subst(self.interner.tcx, &bound_vars))
+                .map(|(bound, _)| {
+                    explicit_item_bounds.rebind(*bound).subst(self.interner.tcx, &bound_vars)
+                })
                 .map(|bound| {
                     bound.fold_with(&mut ReplaceOpaqueTyFolder {
                         tcx: self.interner.tcx,
index db7ea4253e36c86454addb406e20a8fdb6ded972..f76386fa720dfaa6b2e9e5dbe95ba8ccae81ba10 100644 (file)
@@ -76,7 +76,7 @@ pub(crate) fn evaluate_goal<'tcx>(
                         chalk_ir::UniverseIndex { counter: ui.index() },
                     ),
                     CanonicalVarKind::Const(_ui, _ty) => unimplemented!(),
-                    CanonicalVarKind::PlaceholderConst(_pc) => unimplemented!(),
+                    CanonicalVarKind::PlaceholderConst(_pc, _ty) => unimplemented!(),
                 }),
             ),
             value: obligation.value.lower_into(interner),
index 4d4d55de5f45791f9bb3e864aa63f513c4e936f4..e3e78f70b15ef9014ba115a63405fde35b50a283 100644 (file)
@@ -14,8 +14,7 @@
 use rustc_trait_selection::infer::InferCtxtBuilderExt;
 use rustc_trait_selection::traits::query::{CanonicalTyGoal, Fallible, NoSolution};
 use rustc_trait_selection::traits::wf;
-use rustc_trait_selection::traits::FulfillmentContext;
-use rustc_trait_selection::traits::TraitEngine;
+use rustc_trait_selection::traits::{TraitEngine, TraitEngineExt};
 use smallvec::{smallvec, SmallVec};
 
 pub(crate) fn provide(p: &mut Providers) {
@@ -52,7 +51,7 @@ fn compute_implied_outlives_bounds<'tcx>(
 
     let mut implied_bounds = vec![];
 
-    let mut fulfill_cx = FulfillmentContext::new();
+    let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(tcx);
 
     while let Some(arg) = wf_args.pop() {
         if !checked_wf_args.insert(arg) {
diff --git a/compiler/rustc_transmute/Cargo.toml b/compiler/rustc_transmute/Cargo.toml
new file mode 100644 (file)
index 0000000..9dc96e0
--- /dev/null
@@ -0,0 +1,28 @@
+[package]
+name = "rustc_transmute"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+tracing = "0.1"
+rustc_data_structures = { path = "../rustc_data_structures", optional = true}
+rustc_infer = { path = "../rustc_infer", optional = true}
+rustc_macros = { path = "../rustc_macros", optional = true}
+rustc_middle = { path = "../rustc_middle", optional = true}
+rustc_span = { path = "../rustc_span", optional = true}
+rustc_target = { path = "../rustc_target", optional = true}
+
+[features]
+rustc = [
+    "rustc_middle",
+    "rustc_data_structures",
+    "rustc_infer",
+    "rustc_macros",
+    "rustc_span",
+    "rustc_target",
+]
+
+[dev-dependencies]
+itertools = "0.10.1"
\ No newline at end of file
diff --git a/compiler/rustc_transmute/src/layout/dfa.rs b/compiler/rustc_transmute/src/layout/dfa.rs
new file mode 100644 (file)
index 0000000..b60ea6e
--- /dev/null
@@ -0,0 +1,184 @@
+use super::{nfa, Byte, Nfa, Ref};
+use crate::Map;
+use std::fmt;
+use std::sync::atomic::{AtomicU32, Ordering};
+
+#[derive(PartialEq, Clone, Debug)]
+pub(crate) struct Dfa<R>
+where
+    R: Ref,
+{
+    pub(crate) transitions: Map<State, Transitions<R>>,
+    pub(crate) start: State,
+    pub(crate) accepting: State,
+}
+
+#[derive(PartialEq, Clone, Debug)]
+pub(crate) struct Transitions<R>
+where
+    R: Ref,
+{
+    byte_transitions: Map<Byte, State>,
+    ref_transitions: Map<R, State>,
+}
+
+impl<R> Default for Transitions<R>
+where
+    R: Ref,
+{
+    fn default() -> Self {
+        Self { byte_transitions: Map::default(), ref_transitions: Map::default() }
+    }
+}
+
+impl<R> Transitions<R>
+where
+    R: Ref,
+{
+    fn insert(&mut self, transition: Transition<R>, state: State) {
+        match transition {
+            Transition::Byte(b) => {
+                self.byte_transitions.insert(b, state);
+            }
+            Transition::Ref(r) => {
+                self.ref_transitions.insert(r, state);
+            }
+        }
+    }
+}
+
+/// The states in a `Nfa` represent byte offsets.
+#[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Copy, Clone)]
+pub(crate) struct State(u32);
+
+#[derive(Hash, Eq, PartialEq, Clone, Copy)]
+pub(crate) enum Transition<R>
+where
+    R: Ref,
+{
+    Byte(Byte),
+    Ref(R),
+}
+
+impl fmt::Debug for State {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "S_{}", self.0)
+    }
+}
+
+impl<R> fmt::Debug for Transition<R>
+where
+    R: Ref,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match &self {
+            Self::Byte(b) => b.fmt(f),
+            Self::Ref(r) => r.fmt(f),
+        }
+    }
+}
+
+impl<R> Dfa<R>
+where
+    R: Ref,
+{
+    pub(crate) fn unit() -> Self {
+        let transitions: Map<State, Transitions<R>> = Map::default();
+        let start = State::new();
+        let accepting = start;
+
+        Self { transitions, start, accepting }
+    }
+
+    #[cfg(test)]
+    pub(crate) fn bool() -> Self {
+        let mut transitions: Map<State, Transitions<R>> = Map::default();
+        let start = State::new();
+        let accepting = State::new();
+
+        transitions.entry(start).or_default().insert(Transition::Byte(Byte::Init(0x00)), accepting);
+
+        transitions.entry(start).or_default().insert(Transition::Byte(Byte::Init(0x01)), accepting);
+
+        Self { transitions, start, accepting }
+    }
+
+    #[instrument(level = "debug")]
+    #[cfg_attr(feature = "rustc", allow(rustc::potential_query_instability))]
+    pub(crate) fn from_nfa(nfa: Nfa<R>) -> Self {
+        let Nfa { transitions: nfa_transitions, start: nfa_start, accepting: nfa_accepting } = nfa;
+
+        let mut dfa_transitions: Map<State, Transitions<R>> = Map::default();
+        let mut nfa_to_dfa: Map<nfa::State, State> = Map::default();
+        let dfa_start = State::new();
+        nfa_to_dfa.insert(nfa_start, dfa_start);
+
+        let mut queue = vec![(nfa_start, dfa_start)];
+
+        while let Some((nfa_state, dfa_state)) = queue.pop() {
+            if nfa_state == nfa_accepting {
+                continue;
+            }
+
+            for (nfa_transition, next_nfa_states) in nfa_transitions[&nfa_state].iter() {
+                let dfa_transitions =
+                    dfa_transitions.entry(dfa_state).or_insert_with(Default::default);
+
+                let mapped_state = next_nfa_states.iter().find_map(|x| nfa_to_dfa.get(x).copied());
+
+                let next_dfa_state = match nfa_transition {
+                    &nfa::Transition::Byte(b) => *dfa_transitions
+                        .byte_transitions
+                        .entry(b)
+                        .or_insert_with(|| mapped_state.unwrap_or_else(State::new)),
+                    &nfa::Transition::Ref(r) => *dfa_transitions
+                        .ref_transitions
+                        .entry(r)
+                        .or_insert_with(|| mapped_state.unwrap_or_else(State::new)),
+                };
+
+                for &next_nfa_state in next_nfa_states {
+                    nfa_to_dfa.entry(next_nfa_state).or_insert_with(|| {
+                        queue.push((next_nfa_state, next_dfa_state));
+                        next_dfa_state
+                    });
+                }
+            }
+        }
+
+        let dfa_accepting = nfa_to_dfa[&nfa_accepting];
+
+        Self { transitions: dfa_transitions, start: dfa_start, accepting: dfa_accepting }
+    }
+
+    pub(crate) fn bytes_from(&self, start: State) -> Option<&Map<Byte, State>> {
+        Some(&self.transitions.get(&start)?.byte_transitions)
+    }
+
+    pub(crate) fn byte_from(&self, start: State, byte: Byte) -> Option<State> {
+        self.transitions.get(&start)?.byte_transitions.get(&byte).copied()
+    }
+
+    pub(crate) fn refs_from(&self, start: State) -> Option<&Map<R, State>> {
+        Some(&self.transitions.get(&start)?.ref_transitions)
+    }
+}
+
+impl State {
+    pub(crate) fn new() -> Self {
+        static COUNTER: AtomicU32 = AtomicU32::new(0);
+        Self(COUNTER.fetch_add(1, Ordering::SeqCst))
+    }
+}
+
+impl<R> From<nfa::Transition<R>> for Transition<R>
+where
+    R: Ref,
+{
+    fn from(nfa_transition: nfa::Transition<R>) -> Self {
+        match nfa_transition {
+            nfa::Transition::Byte(byte) => Transition::Byte(byte),
+            nfa::Transition::Ref(r) => Transition::Ref(r),
+        }
+    }
+}
diff --git a/compiler/rustc_transmute/src/layout/mod.rs b/compiler/rustc_transmute/src/layout/mod.rs
new file mode 100644 (file)
index 0000000..07035eb
--- /dev/null
@@ -0,0 +1,71 @@
+use std::fmt::{self, Debug};
+use std::hash::Hash;
+
+pub(crate) mod tree;
+pub(crate) use tree::Tree;
+
+pub(crate) mod nfa;
+pub(crate) use nfa::Nfa;
+
+pub(crate) mod dfa;
+pub(crate) use dfa::Dfa;
+
+#[derive(Debug)]
+pub(crate) struct Uninhabited;
+
+/// An instance of a byte is either initialized to a particular value, or uninitialized.
+#[derive(Hash, Eq, PartialEq, Clone, Copy)]
+pub(crate) enum Byte {
+    Uninit,
+    Init(u8),
+}
+
+impl fmt::Debug for Byte {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match &self {
+            Self::Uninit => f.write_str("??u8"),
+            Self::Init(b) => write!(f, "{:#04x}u8", b),
+        }
+    }
+}
+
+pub(crate) trait Def: Debug + Hash + Eq + PartialEq + Copy + Clone {}
+pub trait Ref: Debug + Hash + Eq + PartialEq + Copy + Clone {}
+
+impl Def for ! {}
+impl Ref for ! {}
+
+#[cfg(feature = "rustc")]
+pub(crate) mod rustc {
+    use rustc_middle::mir::Mutability;
+    use rustc_middle::ty;
+    use rustc_middle::ty::Region;
+    use rustc_middle::ty::Ty;
+
+    /// A reference in the layout.
+    #[derive(Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Clone, Copy)]
+    pub struct Ref<'tcx> {
+        lifetime: Region<'tcx>,
+        ty: Ty<'tcx>,
+        mutability: Mutability,
+    }
+
+    impl<'tcx> super::Ref for Ref<'tcx> {}
+
+    impl<'tcx> Ref<'tcx> {
+        pub fn min_align(&self) -> usize {
+            todo!()
+        }
+    }
+
+    /// A visibility node in the layout.
+    #[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)]
+    pub enum Def<'tcx> {
+        Adt(ty::AdtDef<'tcx>),
+        Variant(&'tcx ty::VariantDef),
+        Field(&'tcx ty::FieldDef),
+        Primitive,
+    }
+
+    impl<'tcx> super::Def for Def<'tcx> {}
+}
diff --git a/compiler/rustc_transmute/src/layout/nfa.rs b/compiler/rustc_transmute/src/layout/nfa.rs
new file mode 100644 (file)
index 0000000..f25e3c1
--- /dev/null
@@ -0,0 +1,179 @@
+use super::{Byte, Ref, Tree, Uninhabited};
+use crate::{Map, Set};
+use std::fmt;
+use std::sync::atomic::{AtomicU32, Ordering};
+
+/// A non-deterministic finite automaton (NFA) that represents the layout of a type.
+/// The transmutability of two given types is computed by comparing their `Nfa`s.
+#[derive(PartialEq, Debug)]
+pub(crate) struct Nfa<R>
+where
+    R: Ref,
+{
+    pub(crate) transitions: Map<State, Map<Transition<R>, Set<State>>>,
+    pub(crate) start: State,
+    pub(crate) accepting: State,
+}
+
+/// The states in a `Nfa` represent byte offsets.
+#[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Copy, Clone)]
+pub(crate) struct State(u32);
+
+/// The transitions between states in a `Nfa` reflect bit validity.
+#[derive(Hash, Eq, PartialEq, Clone, Copy)]
+pub(crate) enum Transition<R>
+where
+    R: Ref,
+{
+    Byte(Byte),
+    Ref(R),
+}
+
+impl fmt::Debug for State {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "S_{}", self.0)
+    }
+}
+
+impl<R> fmt::Debug for Transition<R>
+where
+    R: Ref,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match &self {
+            Self::Byte(b) => b.fmt(f),
+            Self::Ref(r) => r.fmt(f),
+        }
+    }
+}
+
+impl<R> Nfa<R>
+where
+    R: Ref,
+{
+    pub(crate) fn unit() -> Self {
+        let transitions: Map<State, Map<Transition<R>, Set<State>>> = Map::default();
+        let start = State::new();
+        let accepting = start;
+
+        Nfa { transitions, start, accepting }
+    }
+
+    pub(crate) fn from_byte(byte: Byte) -> Self {
+        let mut transitions: Map<State, Map<Transition<R>, Set<State>>> = Map::default();
+        let start = State::new();
+        let accepting = State::new();
+
+        let source = transitions.entry(start).or_default();
+        let edge = source.entry(Transition::Byte(byte)).or_default();
+        edge.insert(accepting);
+
+        Nfa { transitions, start, accepting }
+    }
+
+    pub(crate) fn from_ref(r: R) -> Self {
+        let mut transitions: Map<State, Map<Transition<R>, Set<State>>> = Map::default();
+        let start = State::new();
+        let accepting = State::new();
+
+        let source = transitions.entry(start).or_default();
+        let edge = source.entry(Transition::Ref(r)).or_default();
+        edge.insert(accepting);
+
+        Nfa { transitions, start, accepting }
+    }
+
+    pub(crate) fn from_tree(tree: Tree<!, R>) -> Result<Self, Uninhabited> {
+        Ok(match tree {
+            Tree::Byte(b) => Self::from_byte(b),
+            Tree::Def(..) => unreachable!(),
+            Tree::Ref(r) => Self::from_ref(r),
+            Tree::Alt(alts) => {
+                let mut alts = alts.into_iter().map(Self::from_tree);
+                let mut nfa = alts.next().ok_or(Uninhabited)??;
+                for alt in alts {
+                    nfa = nfa.union(alt?);
+                }
+                nfa
+            }
+            Tree::Seq(elts) => {
+                let mut nfa = Self::unit();
+                for elt in elts.into_iter().map(Self::from_tree) {
+                    nfa = nfa.concat(elt?);
+                }
+                nfa
+            }
+        })
+    }
+
+    /// Concatenate two `Nfa`s.
+    pub(crate) fn concat(self, other: Self) -> Self {
+        if self.start == self.accepting {
+            return other;
+        } else if other.start == other.accepting {
+            return self;
+        }
+
+        let start = self.start;
+        let accepting = other.accepting;
+
+        let mut transitions: Map<State, Map<Transition<R>, Set<State>>> = self.transitions;
+
+        // the iteration order doesn't matter
+        #[cfg_attr(feature = "rustc", allow(rustc::potential_query_instability))]
+        for (source, transition) in other.transitions {
+            let fix_state = |state| if state == other.start { self.accepting } else { state };
+            let entry = transitions.entry(fix_state(source)).or_default();
+            for (edge, destinations) in transition {
+                let entry = entry.entry(edge.clone()).or_default();
+                for destination in destinations {
+                    entry.insert(fix_state(destination));
+                }
+            }
+        }
+
+        Self { transitions, start, accepting }
+    }
+
+    /// Compute the union of two `Nfa`s.
+    pub(crate) fn union(self, other: Self) -> Self {
+        let start = self.start;
+        let accepting = self.accepting;
+
+        let mut transitions: Map<State, Map<Transition<R>, Set<State>>> = self.transitions.clone();
+
+        // the iteration order doesn't matter
+        #[cfg_attr(feature = "rustc", allow(rustc::potential_query_instability))]
+        for (&(mut source), transition) in other.transitions.iter() {
+            // if source is starting state of `other`, replace with starting state of `self`
+            if source == other.start {
+                source = self.start;
+            }
+            let entry = transitions.entry(source).or_default();
+            for (edge, destinations) in transition {
+                let entry = entry.entry(edge.clone()).or_default();
+                // the iteration order doesn't matter
+                #[cfg_attr(feature = "rustc", allow(rustc::potential_query_instability))]
+                for &(mut destination) in destinations {
+                    // if dest is accepting state of `other`, replace with accepting state of `self`
+                    if destination == other.accepting {
+                        destination = self.accepting;
+                    }
+                    entry.insert(destination);
+                }
+            }
+        }
+        Self { transitions, start, accepting }
+    }
+
+    pub(crate) fn edges_from(&self, start: State) -> Option<&Map<Transition<R>, Set<State>>> {
+        self.transitions.get(&start)
+    }
+}
+
+impl State {
+    pub(crate) fn new() -> Self {
+        static COUNTER: AtomicU32 = AtomicU32::new(0);
+        Self(COUNTER.fetch_add(1, Ordering::SeqCst))
+    }
+}
diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs
new file mode 100644 (file)
index 0000000..70b3ba0
--- /dev/null
@@ -0,0 +1,471 @@
+use super::{Byte, Def, Ref};
+
+#[cfg(test)]
+mod tests;
+
+/// A tree-based representation of a type layout.
+///
+/// Invariants:
+/// 1. All paths through the layout have the same length (in bytes).
+///
+/// Nice-to-haves:
+/// 1. An `Alt` is never directly nested beneath another `Alt`.
+/// 2. A `Seq` is never directly nested beneath another `Seq`.
+/// 3. `Seq`s and `Alt`s with a single member do not exist.
+#[derive(Clone, Debug, Hash, PartialEq, Eq)]
+pub(crate) enum Tree<D, R>
+where
+    D: Def,
+    R: Ref,
+{
+    /// A sequence of successive layouts.
+    Seq(Vec<Self>),
+    /// A choice between alternative layouts.
+    Alt(Vec<Self>),
+    /// A definition node.
+    Def(D),
+    /// A reference node.
+    Ref(R),
+    /// A byte node.
+    Byte(Byte),
+}
+
+impl<D, R> Tree<D, R>
+where
+    D: Def,
+    R: Ref,
+{
+    /// A `Tree` consisting only of a definition node.
+    pub(crate) fn def(def: D) -> Self {
+        Self::Def(def)
+    }
+
+    /// A `Tree` representing an uninhabited type.
+    pub(crate) fn uninhabited() -> Self {
+        Self::Alt(vec![])
+    }
+
+    /// A `Tree` representing a zero-sized type.
+    pub(crate) fn unit() -> Self {
+        Self::Seq(Vec::new())
+    }
+
+    /// A `Tree` containing a single, uninitialized byte.
+    pub(crate) fn uninit() -> Self {
+        Self::Byte(Byte::Uninit)
+    }
+
+    /// A `Tree` representing the layout of `bool`.
+    pub(crate) fn bool() -> Self {
+        Self::from_bits(0x00).or(Self::from_bits(0x01))
+    }
+
+    /// A `Tree` whose layout matches that of a `u8`.
+    pub(crate) fn u8() -> Self {
+        Self::Alt((0u8..=255).map(Self::from_bits).collect())
+    }
+
+    /// A `Tree` whose layout accepts exactly the given bit pattern.
+    pub(crate) fn from_bits(bits: u8) -> Self {
+        Self::Byte(Byte::Init(bits))
+    }
+
+    /// A `Tree` whose layout is a number of the given width.
+    pub(crate) fn number(width_in_bytes: usize) -> Self {
+        Self::Seq(vec![Self::u8(); width_in_bytes])
+    }
+
+    /// A `Tree` whose layout is entirely padding of the given width.
+    pub(crate) fn padding(width_in_bytes: usize) -> Self {
+        Self::Seq(vec![Self::uninit(); width_in_bytes])
+    }
+
+    /// Remove all `Def` nodes, and all branches of the layout for which `f` produces false.
+    pub(crate) fn prune<F>(self, f: &F) -> Tree<!, R>
+    where
+        F: Fn(D) -> bool,
+    {
+        match self {
+            Self::Seq(elts) => elts
+                .into_iter()
+                .map(|elt| elt.prune(f))
+                .try_fold(Tree::unit(), |elts, elt| {
+                    if elt == Tree::uninhabited() {
+                        Err(Tree::uninhabited())
+                    } else {
+                        Ok(elts.then(elt))
+                    }
+                })
+                .into_ok_or_err(),
+            Self::Alt(alts) => alts
+                .into_iter()
+                .map(|alt| alt.prune(f))
+                .fold(Tree::uninhabited(), |alts, alt| alts.or(alt)),
+            Self::Byte(b) => Tree::Byte(b),
+            Self::Ref(r) => Tree::Ref(r),
+            Self::Def(d) => {
+                if !f(d) {
+                    Tree::uninhabited()
+                } else {
+                    Tree::unit()
+                }
+            }
+        }
+    }
+
+    /// Produces `true` if `Tree` is an inhabited type; otherwise false.
+    pub(crate) fn is_inhabited(&self) -> bool {
+        match self {
+            Self::Seq(elts) => elts.into_iter().all(|elt| elt.is_inhabited()),
+            Self::Alt(alts) => alts.into_iter().any(|alt| alt.is_inhabited()),
+            Self::Byte(..) | Self::Ref(..) | Self::Def(..) => true,
+        }
+    }
+}
+
+impl<D, R> Tree<D, R>
+where
+    D: Def,
+    R: Ref,
+{
+    /// Produces a new `Tree` where `other` is sequenced after `self`.
+    pub(crate) fn then(self, other: Self) -> Self {
+        match (self, other) {
+            (Self::Seq(elts), other) | (other, Self::Seq(elts)) if elts.len() == 0 => other,
+            (Self::Seq(mut lhs), Self::Seq(mut rhs)) => {
+                lhs.append(&mut rhs);
+                Self::Seq(lhs)
+            }
+            (Self::Seq(mut lhs), rhs) => {
+                lhs.push(rhs);
+                Self::Seq(lhs)
+            }
+            (lhs, Self::Seq(mut rhs)) => {
+                rhs.insert(0, lhs);
+                Self::Seq(rhs)
+            }
+            (lhs, rhs) => Self::Seq(vec![lhs, rhs]),
+        }
+    }
+
+    /// Produces a new `Tree` accepting either `self` or `other` as alternative layouts.
+    pub(crate) fn or(self, other: Self) -> Self {
+        match (self, other) {
+            (Self::Alt(alts), other) | (other, Self::Alt(alts)) if alts.len() == 0 => other,
+            (Self::Alt(mut lhs), Self::Alt(rhs)) => {
+                lhs.extend(rhs);
+                Self::Alt(lhs)
+            }
+            (Self::Alt(mut alts), alt) | (alt, Self::Alt(mut alts)) => {
+                alts.push(alt);
+                Self::Alt(alts)
+            }
+            (lhs, rhs) => Self::Alt(vec![lhs, rhs]),
+        }
+    }
+}
+
+#[derive(Debug, Copy, Clone)]
+pub(crate) enum Err {
+    /// The layout of the type is unspecified.
+    Unspecified,
+    /// This error will be surfaced elsewhere by rustc, so don't surface it.
+    Unknown,
+}
+
+#[cfg(feature = "rustc")]
+pub(crate) mod rustc {
+    use super::{Err, Tree};
+    use crate::layout::rustc::{Def, Ref};
+
+    use rustc_middle::ty;
+    use rustc_middle::ty::layout::LayoutError;
+    use rustc_middle::ty::util::Discr;
+    use rustc_middle::ty::AdtDef;
+    use rustc_middle::ty::ParamEnv;
+    use rustc_middle::ty::SubstsRef;
+    use rustc_middle::ty::Ty;
+    use rustc_middle::ty::TyCtxt;
+    use rustc_middle::ty::VariantDef;
+    use rustc_target::abi::Align;
+    use std::alloc;
+
+    impl<'tcx> From<LayoutError<'tcx>> for Err {
+        fn from(err: LayoutError<'tcx>) -> Self {
+            match err {
+                LayoutError::Unknown(..) => Self::Unknown,
+                err @ _ => unimplemented!("{:?}", err),
+            }
+        }
+    }
+
+    trait LayoutExt {
+        fn clamp_align(&self, min_align: Align, max_align: Align) -> Self;
+    }
+
+    impl LayoutExt for alloc::Layout {
+        fn clamp_align(&self, min_align: Align, max_align: Align) -> Self {
+            let min_align = min_align.bytes().try_into().unwrap();
+            let max_align = max_align.bytes().try_into().unwrap();
+            Self::from_size_align(self.size(), self.align().clamp(min_align, max_align)).unwrap()
+        }
+    }
+
+    struct LayoutSummary {
+        total_align: Align,
+        total_size: usize,
+        discriminant_size: usize,
+        discriminant_align: Align,
+    }
+
+    impl LayoutSummary {
+        fn from_ty<'tcx>(ty: Ty<'tcx>, ctx: TyCtxt<'tcx>) -> Result<Self, LayoutError<'tcx>> {
+            use rustc_middle::ty::ParamEnvAnd;
+            use rustc_target::abi::{TyAndLayout, Variants};
+
+            let param_env = ParamEnv::reveal_all();
+            let param_env_and_type = ParamEnvAnd { param_env, value: ty };
+            let TyAndLayout { layout, .. } = ctx.layout_of(param_env_and_type)?;
+
+            let total_size: usize = layout.size().bytes_usize();
+            let total_align: Align = layout.align().abi;
+            let discriminant_align: Align;
+            let discriminant_size: usize;
+
+            if let Variants::Multiple { tag, .. } = layout.variants() {
+                discriminant_align = tag.align(&ctx).abi;
+                discriminant_size = tag.size(&ctx).bytes_usize();
+            } else {
+                discriminant_align = Align::ONE;
+                discriminant_size = 0;
+            };
+
+            Ok(Self { total_align, total_size, discriminant_align, discriminant_size })
+        }
+
+        fn into(&self) -> alloc::Layout {
+            alloc::Layout::from_size_align(
+                self.total_size,
+                self.total_align.bytes().try_into().unwrap(),
+            )
+            .unwrap()
+        }
+    }
+
+    impl<'tcx> Tree<Def<'tcx>, Ref<'tcx>> {
+        pub fn from_ty(ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Result<Self, Err> {
+            use rustc_middle::ty::FloatTy::*;
+            use rustc_middle::ty::IntTy::*;
+            use rustc_middle::ty::UintTy::*;
+            use rustc_target::abi::HasDataLayout;
+
+            let target = tcx.data_layout();
+
+            match ty.kind() {
+                ty::Bool => Ok(Self::bool()),
+
+                ty::Int(I8) | ty::Uint(U8) => Ok(Self::u8()),
+                ty::Int(I16) | ty::Uint(U16) => Ok(Self::number(2)),
+                ty::Int(I32) | ty::Uint(U32) | ty::Float(F32) => Ok(Self::number(4)),
+                ty::Int(I64) | ty::Uint(U64) | ty::Float(F64) => Ok(Self::number(8)),
+                ty::Int(I128) | ty::Uint(U128) => Ok(Self::number(16)),
+                ty::Int(Isize) | ty::Uint(Usize) => {
+                    Ok(Self::number(target.pointer_size.bytes_usize()))
+                }
+
+                ty::Tuple(members) => {
+                    if members.len() == 0 {
+                        Ok(Tree::unit())
+                    } else {
+                        Err(Err::Unspecified)
+                    }
+                }
+
+                ty::Array(ty, len) => {
+                    let len = len.try_eval_usize(tcx, ParamEnv::reveal_all()).unwrap();
+                    let elt = Tree::from_ty(*ty, tcx)?;
+                    Ok(std::iter::repeat(elt)
+                        .take(len as usize)
+                        .fold(Tree::unit(), |tree, elt| tree.then(elt)))
+                }
+
+                ty::Adt(adt_def, substs_ref) => {
+                    use rustc_middle::ty::AdtKind;
+
+                    // If the layout is ill-specified, halt.
+                    if !(adt_def.repr().c() || adt_def.repr().int.is_some()) {
+                        return Err(Err::Unspecified);
+                    }
+
+                    // Compute a summary of the type's layout.
+                    let layout_summary = LayoutSummary::from_ty(ty, tcx)?;
+
+                    // The layout begins with this adt's visibility.
+                    let vis = Self::def(Def::Adt(*adt_def));
+
+                    // And is followed the layout(s) of its variants
+                    Ok(vis.then(match adt_def.adt_kind() {
+                        AdtKind::Struct => Self::from_repr_c_variant(
+                            ty,
+                            *adt_def,
+                            substs_ref,
+                            &layout_summary,
+                            None,
+                            adt_def.non_enum_variant(),
+                            tcx,
+                        )?,
+                        AdtKind::Enum => {
+                            tracing::trace!(?adt_def, "treeifying enum");
+                            let mut tree = Tree::uninhabited();
+
+                            for (idx, discr) in adt_def.discriminants(tcx) {
+                                tree = tree.or(Self::from_repr_c_variant(
+                                    ty,
+                                    *adt_def,
+                                    substs_ref,
+                                    &layout_summary,
+                                    Some(discr),
+                                    adt_def.variant(idx),
+                                    tcx,
+                                )?);
+                            }
+
+                            tree
+                        }
+                        AdtKind::Union => {
+                            // is the layout well-defined?
+                            if !adt_def.repr().c() {
+                                return Err(Err::Unspecified);
+                            }
+
+                            let ty_layout = layout_of(tcx, ty)?;
+
+                            let mut tree = Tree::uninhabited();
+
+                            for field in adt_def.all_fields() {
+                                let variant_ty = field.ty(tcx, substs_ref);
+                                let variant_layout = layout_of(tcx, variant_ty)?;
+                                let padding_needed = ty_layout.size() - variant_layout.size();
+                                let variant = Self::def(Def::Field(field))
+                                    .then(Self::from_ty(variant_ty, tcx)?)
+                                    .then(Self::padding(padding_needed));
+
+                                tree = tree.or(variant);
+                            }
+
+                            tree
+                        }
+                    }))
+                }
+                _ => Err(Err::Unspecified),
+            }
+        }
+
+        fn from_repr_c_variant(
+            ty: Ty<'tcx>,
+            adt_def: AdtDef<'tcx>,
+            substs_ref: SubstsRef<'tcx>,
+            layout_summary: &LayoutSummary,
+            discr: Option<Discr<'tcx>>,
+            variant_def: &'tcx VariantDef,
+            tcx: TyCtxt<'tcx>,
+        ) -> Result<Self, Err> {
+            let mut tree = Tree::unit();
+
+            let repr = adt_def.repr();
+            let min_align = repr.align.unwrap_or(Align::ONE);
+            let max_align = repr.pack.unwrap_or(Align::MAX);
+
+            let clamp =
+                |align: Align| align.clamp(min_align, max_align).bytes().try_into().unwrap();
+
+            let variant_span = tracing::trace_span!(
+                "treeifying variant",
+                min_align = ?min_align,
+                max_align = ?max_align,
+            )
+            .entered();
+
+            let mut variant_layout = alloc::Layout::from_size_align(
+                0,
+                layout_summary.total_align.bytes().try_into().unwrap(),
+            )
+            .unwrap();
+
+            // The layout of the variant is prefixed by the discriminant, if any.
+            if let Some(discr) = discr {
+                tracing::trace!(?discr, "treeifying discriminant");
+                let discr_layout = alloc::Layout::from_size_align(
+                    layout_summary.discriminant_size,
+                    clamp(layout_summary.discriminant_align),
+                )
+                .unwrap();
+                tracing::trace!(?discr_layout, "computed discriminant layout");
+                variant_layout = variant_layout.extend(discr_layout).unwrap().0;
+                tree = tree.then(Self::from_disr(discr, tcx, layout_summary.discriminant_size));
+            }
+
+            // Next come fields.
+            let fields_span = tracing::trace_span!("treeifying fields").entered();
+            for field_def in variant_def.fields.iter() {
+                let field_ty = field_def.ty(tcx, substs_ref);
+                let _span = tracing::trace_span!("treeifying field", field = ?field_ty).entered();
+
+                // begin with the field's visibility
+                tree = tree.then(Self::def(Def::Field(field_def)));
+
+                // compute the field's layout charactaristics
+                let field_layout = layout_of(tcx, field_ty)?.clamp_align(min_align, max_align);
+
+                // next comes the field's padding
+                let padding_needed = variant_layout.padding_needed_for(field_layout.align());
+                if padding_needed > 0 {
+                    tree = tree.then(Self::padding(padding_needed));
+                }
+
+                // finally, the field's layout
+                tree = tree.then(Self::from_ty(field_ty, tcx)?);
+
+                // extend the variant layout with the field layout
+                variant_layout = variant_layout.extend(field_layout).unwrap().0;
+            }
+            drop(fields_span);
+
+            // finally: padding
+            let padding_span = tracing::trace_span!("adding trailing padding").entered();
+            let padding_needed = layout_summary.total_size - variant_layout.size();
+            if padding_needed > 0 {
+                tree = tree.then(Self::padding(padding_needed));
+            };
+            drop(padding_span);
+            drop(variant_span);
+            Ok(tree)
+        }
+
+        pub fn from_disr(discr: Discr<'tcx>, tcx: TyCtxt<'tcx>, size: usize) -> Self {
+            // FIXME(@jswrenn): I'm certain this is missing needed endian nuance.
+            let bytes = discr.val.to_ne_bytes();
+            let bytes = &bytes[..size];
+            Self::Seq(bytes.into_iter().copied().map(|b| Self::from_bits(b)).collect())
+        }
+    }
+
+    fn layout_of<'tcx>(
+        ctx: TyCtxt<'tcx>,
+        ty: Ty<'tcx>,
+    ) -> Result<alloc::Layout, LayoutError<'tcx>> {
+        use rustc_middle::ty::ParamEnvAnd;
+        use rustc_target::abi::TyAndLayout;
+
+        let param_env = ParamEnv::reveal_all();
+        let param_env_and_type = ParamEnvAnd { param_env, value: ty };
+        let TyAndLayout { layout, .. } = ctx.layout_of(param_env_and_type)?;
+        let layout = alloc::Layout::from_size_align(
+            layout.size().bytes_usize(),
+            layout.align().abi.bytes().try_into().unwrap(),
+        )
+        .unwrap();
+        tracing::trace!(?ty, ?layout, "computed layout for type");
+        Ok(layout)
+    }
+}
diff --git a/compiler/rustc_transmute/src/layout/tree/tests.rs b/compiler/rustc_transmute/src/layout/tree/tests.rs
new file mode 100644 (file)
index 0000000..90515e9
--- /dev/null
@@ -0,0 +1,80 @@
+use super::Tree;
+
+#[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)]
+pub enum Def {
+    Visible,
+    Invisible,
+}
+
+impl super::Def for Def {}
+
+mod prune {
+    use super::*;
+
+    mod should_simplify {
+        use super::*;
+
+        #[test]
+        fn seq_1() {
+            let layout: Tree<Def, !> = Tree::def(Def::Visible).then(Tree::from_bits(0x00));
+            assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::from_bits(0x00));
+        }
+
+        #[test]
+        fn seq_2() {
+            let layout: Tree<Def, !> =
+                Tree::from_bits(0x00).then(Tree::def(Def::Visible)).then(Tree::from_bits(0x01));
+
+            assert_eq!(
+                layout.prune(&|d| matches!(d, Def::Visible)),
+                Tree::from_bits(0x00).then(Tree::from_bits(0x01))
+            );
+        }
+    }
+
+    mod should_reject {
+        use super::*;
+
+        #[test]
+        fn invisible_def() {
+            let layout: Tree<Def, !> = Tree::def(Def::Invisible);
+            assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::uninhabited());
+        }
+
+        #[test]
+        fn invisible_def_in_seq_len_2() {
+            let layout: Tree<Def, !> = Tree::def(Def::Visible).then(Tree::def(Def::Invisible));
+            assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::uninhabited());
+        }
+
+        #[test]
+        fn invisible_def_in_seq_len_3() {
+            let layout: Tree<Def, !> =
+                Tree::def(Def::Visible).then(Tree::from_bits(0x00)).then(Tree::def(Def::Invisible));
+            assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::uninhabited());
+        }
+    }
+
+    mod should_accept {
+        use super::*;
+
+        #[test]
+        fn visible_def() {
+            let layout: Tree<Def, !> = Tree::def(Def::Visible);
+            assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::unit());
+        }
+
+        #[test]
+        fn visible_def_in_seq_len_2() {
+            let layout: Tree<Def, !> = Tree::def(Def::Visible).then(Tree::def(Def::Visible));
+            assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::unit());
+        }
+
+        #[test]
+        fn visible_def_in_seq_len_3() {
+            let layout: Tree<Def, !> =
+                Tree::def(Def::Visible).then(Tree::from_bits(0x00)).then(Tree::def(Def::Visible));
+            assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::from_bits(0x00));
+        }
+    }
+}
diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs
new file mode 100644 (file)
index 0000000..cfc7c75
--- /dev/null
@@ -0,0 +1,117 @@
+#![feature(
+    alloc_layout_extra,
+    control_flow_enum,
+    decl_macro,
+    iterator_try_reduce,
+    never_type,
+    result_into_ok_or_err
+)]
+#![allow(dead_code, unused_variables)]
+
+#[macro_use]
+extern crate tracing;
+
+#[cfg(feature = "rustc")]
+pub(crate) use rustc_data_structures::fx::{FxHashMap as Map, FxHashSet as Set};
+
+#[cfg(not(feature = "rustc"))]
+pub(crate) use std::collections::{HashMap as Map, HashSet as Set};
+
+pub(crate) mod layout;
+pub(crate) mod maybe_transmutable;
+
+#[derive(Default)]
+pub struct Assume {
+    pub alignment: bool,
+    pub lifetimes: bool,
+    pub validity: bool,
+    pub visibility: bool,
+}
+
+/// The type encodes answers to the question: "Are these types transmutable?"
+#[derive(Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Clone)]
+pub enum Answer<R>
+where
+    R: layout::Ref,
+{
+    /// `Src` is transmutable into `Dst`.
+    Yes,
+
+    /// `Src` is NOT transmutable into `Dst`.
+    No(Reason),
+
+    /// `Src` is transmutable into `Dst`, if `src` is transmutable into `dst`.
+    IfTransmutable { src: R, dst: R },
+
+    /// `Src` is transmutable into `Dst`, if all of the enclosed requirements are met.
+    IfAll(Vec<Answer<R>>),
+
+    /// `Src` is transmutable into `Dst` if any of the enclosed requirements are met.
+    IfAny(Vec<Answer<R>>),
+}
+
+/// Answers: Why wasn't the source type transmutable into the destination type?
+#[derive(Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Clone)]
+pub enum Reason {
+    /// The layout of the source type is unspecified.
+    SrcIsUnspecified,
+    /// The layout of the destination type is unspecified.
+    DstIsUnspecified,
+    /// The layout of the destination type is bit-incompatible with the source type.
+    DstIsBitIncompatible,
+    /// There aren't any public constructors for `Dst`.
+    DstIsPrivate,
+    /// `Dst` is larger than `Src`, and the excess bytes were not exclusively uninitialized.
+    DstIsTooBig,
+}
+
+#[cfg(feature = "rustc")]
+mod rustc {
+    use rustc_infer::infer::InferCtxt;
+    use rustc_macros::{TypeFoldable, TypeVisitable};
+    use rustc_middle::traits::ObligationCause;
+    use rustc_middle::ty::Binder;
+    use rustc_middle::ty::Ty;
+
+    /// The source and destination types of a transmutation.
+    #[derive(TypeFoldable, TypeVisitable, Debug, Clone, Copy)]
+    pub struct Types<'tcx> {
+        /// The source type.
+        pub src: Ty<'tcx>,
+        /// The destination type.
+        pub dst: Ty<'tcx>,
+    }
+
+    pub struct TransmuteTypeEnv<'cx, 'tcx> {
+        infcx: &'cx InferCtxt<'cx, 'tcx>,
+    }
+
+    impl<'cx, 'tcx> TransmuteTypeEnv<'cx, 'tcx> {
+        pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>) -> Self {
+            Self { infcx }
+        }
+
+        #[allow(unused)]
+        pub fn is_transmutable(
+            &mut self,
+            cause: ObligationCause<'tcx>,
+            src_and_dst: Binder<'tcx, Types<'tcx>>,
+            scope: Ty<'tcx>,
+            assume: crate::Assume,
+        ) -> crate::Answer<crate::layout::rustc::Ref<'tcx>> {
+            let src = src_and_dst.map_bound(|types| types.src).skip_binder();
+            let dst = src_and_dst.map_bound(|types| types.dst).skip_binder();
+            crate::maybe_transmutable::MaybeTransmutableQuery::new(
+                src,
+                dst,
+                scope,
+                assume,
+                self.infcx.tcx,
+            )
+            .answer()
+        }
+    }
+}
+
+#[cfg(feature = "rustc")]
+pub use rustc::*;
diff --git a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs
new file mode 100644 (file)
index 0000000..076d922
--- /dev/null
@@ -0,0 +1,320 @@
+use crate::Map;
+use crate::{Answer, Reason};
+
+#[cfg(test)]
+mod tests;
+
+mod query_context;
+use query_context::QueryContext;
+
+use crate::layout::{self, dfa, Byte, Dfa, Nfa, Tree, Uninhabited};
+pub(crate) struct MaybeTransmutableQuery<L, C>
+where
+    C: QueryContext,
+{
+    src: L,
+    dst: L,
+    scope: <C as QueryContext>::Scope,
+    assume: crate::Assume,
+    context: C,
+}
+
+impl<L, C> MaybeTransmutableQuery<L, C>
+where
+    C: QueryContext,
+{
+    pub(crate) fn new(
+        src: L,
+        dst: L,
+        scope: <C as QueryContext>::Scope,
+        assume: crate::Assume,
+        context: C,
+    ) -> Self {
+        Self { src, dst, scope, assume, context }
+    }
+
+    pub(crate) fn map_layouts<F, M>(
+        self,
+        f: F,
+    ) -> Result<MaybeTransmutableQuery<M, C>, Answer<<C as QueryContext>::Ref>>
+    where
+        F: FnOnce(
+            L,
+            L,
+            <C as QueryContext>::Scope,
+            &C,
+        ) -> Result<(M, M), Answer<<C as QueryContext>::Ref>>,
+    {
+        let Self { src, dst, scope, assume, context } = self;
+
+        let (src, dst) = f(src, dst, scope, &context)?;
+
+        Ok(MaybeTransmutableQuery { src, dst, scope, assume, context })
+    }
+}
+
+#[cfg(feature = "rustc")]
+mod rustc {
+    use super::*;
+    use crate::layout::tree::Err;
+
+    use rustc_middle::ty::Ty;
+    use rustc_middle::ty::TyCtxt;
+
+    impl<'tcx> MaybeTransmutableQuery<Ty<'tcx>, TyCtxt<'tcx>> {
+        /// This method begins by converting `src` and `dst` from `Ty`s to `Tree`s,
+        /// then computes an answer using those trees.
+        #[instrument(level = "debug", skip(self), fields(src = ?self.src, dst = ?self.dst))]
+        pub fn answer(self) -> Answer<<TyCtxt<'tcx> as QueryContext>::Ref> {
+            let query_or_answer = self.map_layouts(|src, dst, scope, &context| {
+                // Convert `src` and `dst` from their rustc representations, to `Tree`-based
+                // representations. If these conversions fail, conclude that the transmutation is
+                // unacceptable; the layouts of both the source and destination types must be
+                // well-defined.
+                let src = Tree::from_ty(src, context).map_err(|err| match err {
+                    // Answer `Yes` here, because "Unknown Type" will already be reported by
+                    // rustc. No need to spam the user with more errors.
+                    Err::Unknown => Answer::Yes,
+                    Err::Unspecified => Answer::No(Reason::SrcIsUnspecified),
+                })?;
+
+                let dst = Tree::from_ty(dst, context).map_err(|err| match err {
+                    Err::Unknown => Answer::Yes,
+                    Err::Unspecified => Answer::No(Reason::DstIsUnspecified),
+                })?;
+
+                Ok((src, dst))
+            });
+
+            match query_or_answer {
+                Ok(query) => query.answer(),
+                Err(answer) => answer,
+            }
+        }
+    }
+}
+
+impl<C> MaybeTransmutableQuery<Tree<<C as QueryContext>::Def, <C as QueryContext>::Ref>, C>
+where
+    C: QueryContext,
+{
+    /// Answers whether a `Tree` is transmutable into another `Tree`.
+    ///
+    /// This method begins by de-def'ing `src` and `dst`, and prunes private paths from `dst`,
+    /// then converts `src` and `dst` to `Nfa`s, and computes an answer using those NFAs.
+    #[inline(always)]
+    #[instrument(level = "debug", skip(self), fields(src = ?self.src, dst = ?self.dst))]
+    pub(crate) fn answer(self) -> Answer<<C as QueryContext>::Ref> {
+        let assume_visibility = self.assume.visibility;
+        let query_or_answer = self.map_layouts(|src, dst, scope, context| {
+            // Remove all `Def` nodes from `src`, without checking their visibility.
+            let src = src.prune(&|def| true);
+
+            tracing::trace!(?src, "pruned src");
+
+            // Remove all `Def` nodes from `dst`, additionally...
+            let dst = if assume_visibility {
+                // ...if visibility is assumed, don't check their visibility.
+                dst.prune(&|def| true)
+            } else {
+                // ...otherwise, prune away all unreachable paths through the `Dst` layout.
+                dst.prune(&|def| context.is_accessible_from(def, scope))
+            };
+
+            tracing::trace!(?dst, "pruned dst");
+
+            // Convert `src` from a tree-based representation to an NFA-based representation.
+            // If the conversion fails because `src` is uninhabited, conclude that the transmutation
+            // is acceptable, because instances of the `src` type do not exist.
+            let src = Nfa::from_tree(src).map_err(|Uninhabited| Answer::Yes)?;
+
+            // Convert `dst` from a tree-based representation to an NFA-based representation.
+            // If the conversion fails because `src` is uninhabited, conclude that the transmutation
+            // is unacceptable, because instances of the `dst` type do not exist.
+            let dst =
+                Nfa::from_tree(dst).map_err(|Uninhabited| Answer::No(Reason::DstIsPrivate))?;
+
+            Ok((src, dst))
+        });
+
+        match query_or_answer {
+            Ok(query) => query.answer(),
+            Err(answer) => answer,
+        }
+    }
+}
+
+impl<C> MaybeTransmutableQuery<Nfa<<C as QueryContext>::Ref>, C>
+where
+    C: QueryContext,
+{
+    /// Answers whether a `Nfa` is transmutable into another `Nfa`.
+    ///
+    /// This method converts `src` and `dst` to DFAs, then computes an answer using those DFAs.
+    #[inline(always)]
+    #[instrument(level = "debug", skip(self), fields(src = ?self.src, dst = ?self.dst))]
+    pub(crate) fn answer(self) -> Answer<<C as QueryContext>::Ref> {
+        let query_or_answer = self
+            .map_layouts(|src, dst, scope, context| Ok((Dfa::from_nfa(src), Dfa::from_nfa(dst))));
+
+        match query_or_answer {
+            Ok(query) => query.answer(),
+            Err(answer) => answer,
+        }
+    }
+}
+
+impl<C> MaybeTransmutableQuery<Dfa<<C as QueryContext>::Ref>, C>
+where
+    C: QueryContext,
+{
+    /// Answers whether a `Nfa` is transmutable into another `Nfa`.
+    ///
+    /// This method converts `src` and `dst` to DFAs, then computes an answer using those DFAs.
+    pub(crate) fn answer(self) -> Answer<<C as QueryContext>::Ref> {
+        MaybeTransmutableQuery {
+            src: &self.src,
+            dst: &self.dst,
+            scope: self.scope,
+            assume: self.assume,
+            context: self.context,
+        }
+        .answer()
+    }
+}
+
+impl<'l, C> MaybeTransmutableQuery<&'l Dfa<<C as QueryContext>::Ref>, C>
+where
+    C: QueryContext,
+{
+    pub(crate) fn answer(&mut self) -> Answer<<C as QueryContext>::Ref> {
+        self.answer_memo(&mut Map::default(), self.src.start, self.dst.start)
+    }
+
+    #[inline(always)]
+    #[instrument(level = "debug", skip(self))]
+    fn answer_memo(
+        &self,
+        cache: &mut Map<(dfa::State, dfa::State), Answer<<C as QueryContext>::Ref>>,
+        src_state: dfa::State,
+        dst_state: dfa::State,
+    ) -> Answer<<C as QueryContext>::Ref> {
+        if let Some(answer) = cache.get(&(src_state, dst_state)) {
+            answer.clone()
+        } else {
+            let answer = if dst_state == self.dst.accepting {
+                // truncation: `size_of(Src) >= size_of(Dst)`
+                Answer::Yes
+            } else if src_state == self.src.accepting {
+                // extension: `size_of(Src) >= size_of(Dst)`
+                if let Some(dst_state_prime) = self.dst.byte_from(dst_state, Byte::Uninit) {
+                    self.answer_memo(cache, src_state, dst_state_prime)
+                } else {
+                    Answer::No(Reason::DstIsTooBig)
+                }
+            } else {
+                let src_quantification = if self.assume.validity {
+                    // if the compiler may assume that the programmer is doing additional validity checks,
+                    // (e.g.: that `src != 3u8` when the destination type is `bool`)
+                    // then there must exist at least one transition out of `src_state` such that the transmute is viable...
+                    there_exists
+                } else {
+                    // if the compiler cannot assume that the programmer is doing additional validity checks,
+                    // then for all transitions out of `src_state`, such that the transmute is viable...
+                    // then there must exist at least one transition out of `src_state` such that the transmute is viable...
+                    for_all
+                };
+
+                src_quantification(
+                    self.src.bytes_from(src_state).unwrap_or(&Map::default()),
+                    |(&src_validity, &src_state_prime)| {
+                        if let Some(dst_state_prime) = self.dst.byte_from(dst_state, src_validity) {
+                            self.answer_memo(cache, src_state_prime, dst_state_prime)
+                        } else if let Some(dst_state_prime) =
+                            self.dst.byte_from(dst_state, Byte::Uninit)
+                        {
+                            self.answer_memo(cache, src_state_prime, dst_state_prime)
+                        } else {
+                            Answer::No(Reason::DstIsBitIncompatible)
+                        }
+                    },
+                )
+            };
+            cache.insert((src_state, dst_state), answer.clone());
+            answer
+        }
+    }
+}
+
+impl<R> Answer<R>
+where
+    R: layout::Ref,
+{
+    pub(crate) fn and(self, rhs: Self) -> Self {
+        match (self, rhs) {
+            (Self::No(reason), _) | (_, Self::No(reason)) => Self::No(reason),
+            (Self::Yes, Self::Yes) => Self::Yes,
+            (Self::IfAll(mut lhs), Self::IfAll(ref mut rhs)) => {
+                lhs.append(rhs);
+                Self::IfAll(lhs)
+            }
+            (constraint, Self::IfAll(mut constraints))
+            | (Self::IfAll(mut constraints), constraint) => {
+                constraints.push(constraint);
+                Self::IfAll(constraints)
+            }
+            (lhs, rhs) => Self::IfAll(vec![lhs, rhs]),
+        }
+    }
+
+    pub(crate) fn or(self, rhs: Self) -> Self {
+        match (self, rhs) {
+            (Self::Yes, _) | (_, Self::Yes) => Self::Yes,
+            (Self::No(lhr), Self::No(rhr)) => Self::No(lhr),
+            (Self::IfAny(mut lhs), Self::IfAny(ref mut rhs)) => {
+                lhs.append(rhs);
+                Self::IfAny(lhs)
+            }
+            (constraint, Self::IfAny(mut constraints))
+            | (Self::IfAny(mut constraints), constraint) => {
+                constraints.push(constraint);
+                Self::IfAny(constraints)
+            }
+            (lhs, rhs) => Self::IfAny(vec![lhs, rhs]),
+        }
+    }
+}
+
+pub fn for_all<R, I, F>(iter: I, f: F) -> Answer<R>
+where
+    R: layout::Ref,
+    I: IntoIterator,
+    F: FnMut(<I as IntoIterator>::Item) -> Answer<R>,
+{
+    use std::ops::ControlFlow::{Break, Continue};
+    let (Continue(result) | Break(result)) =
+        iter.into_iter().map(f).try_fold(Answer::Yes, |constraints, constraint| {
+            match constraint.and(constraints) {
+                Answer::No(reason) => Break(Answer::No(reason)),
+                maybe => Continue(maybe),
+            }
+        });
+    result
+}
+
+pub fn there_exists<R, I, F>(iter: I, f: F) -> Answer<R>
+where
+    R: layout::Ref,
+    I: IntoIterator,
+    F: FnMut(<I as IntoIterator>::Item) -> Answer<R>,
+{
+    use std::ops::ControlFlow::{Break, Continue};
+    let (Continue(result) | Break(result)) = iter.into_iter().map(f).try_fold(
+        Answer::No(Reason::DstIsBitIncompatible),
+        |constraints, constraint| match constraint.or(constraints) {
+            Answer::Yes => Break(Answer::Yes),
+            maybe => Continue(maybe),
+        },
+    );
+    result
+}
diff --git a/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs b/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs
new file mode 100644 (file)
index 0000000..9c2cf4c
--- /dev/null
@@ -0,0 +1,93 @@
+use crate::layout;
+
+/// Context necessary to answer the question "Are these types transmutable?".
+pub(crate) trait QueryContext {
+    type Def: layout::Def;
+    type Ref: layout::Ref;
+    type Scope: Copy;
+
+    /// Is `def` accessible from the defining module of `scope`?
+    fn is_accessible_from(&self, def: Self::Def, scope: Self::Scope) -> bool;
+
+    fn min_align(&self, reference: Self::Ref) -> usize;
+}
+
+#[cfg(test)]
+pub(crate) mod test {
+    use super::QueryContext;
+
+    pub(crate) struct UltraMinimal;
+
+    #[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)]
+    pub(crate) enum Def {
+        Visible,
+        Invisible,
+    }
+
+    impl crate::layout::Def for Def {}
+
+    impl QueryContext for UltraMinimal {
+        type Def = Def;
+        type Ref = !;
+        type Scope = ();
+
+        fn is_accessible_from(&self, def: Def, scope: ()) -> bool {
+            matches!(Def::Visible, def)
+        }
+
+        fn min_align(&self, reference: !) -> usize {
+            unimplemented!()
+        }
+    }
+}
+
+#[cfg(feature = "rustc")]
+mod rustc {
+    use super::*;
+    use rustc_middle::ty::{Ty, TyCtxt};
+
+    impl<'tcx> super::QueryContext for TyCtxt<'tcx> {
+        type Def = layout::rustc::Def<'tcx>;
+        type Ref = layout::rustc::Ref<'tcx>;
+
+        type Scope = Ty<'tcx>;
+
+        #[instrument(level = "debug", skip(self))]
+        fn is_accessible_from(&self, def: Self::Def, scope: Self::Scope) -> bool {
+            use layout::rustc::Def;
+            use rustc_middle::ty;
+
+            let parent = if let ty::Adt(adt_def, ..) = scope.kind() {
+                use rustc_middle::ty::DefIdTree;
+                let parent = self.parent(adt_def.did());
+                parent
+            } else {
+                // Is this always how we want to handle a non-ADT scope?
+                return false;
+            };
+
+            let def_id = match def {
+                Def::Adt(adt_def) => adt_def.did(),
+                Def::Variant(variant_def) => variant_def.def_id,
+                Def::Field(field_def) => field_def.did,
+                Def::Primitive => {
+                    // primitives do not have a def_id, but they're always accessible
+                    return true;
+                }
+            };
+
+            let ret = if self.visibility(def_id).is_accessible_from(parent, *self) {
+                true
+            } else {
+                false
+            };
+
+            tracing::trace!(?ret, "ret");
+            ret
+        }
+
+        fn min_align(&self, reference: Self::Ref) -> usize {
+            unimplemented!()
+        }
+    }
+}
diff --git a/compiler/rustc_transmute/src/maybe_transmutable/tests.rs b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs
new file mode 100644 (file)
index 0000000..d9d1256
--- /dev/null
@@ -0,0 +1,115 @@
+use super::query_context::test::{Def, UltraMinimal};
+use crate::maybe_transmutable::MaybeTransmutableQuery;
+use crate::{layout, Answer, Reason, Set};
+use itertools::Itertools;
+
+mod bool {
+    use super::*;
+
+    #[test]
+    fn should_permit_identity_transmutation_tree() {
+        println!("{:?}", layout::Tree::<!, !>::bool());
+        let answer = crate::maybe_transmutable::MaybeTransmutableQuery::new(
+            layout::Tree::<Def, !>::bool(),
+            layout::Tree::<Def, !>::bool(),
+            (),
+            crate::Assume { alignment: false, lifetimes: false, validity: true, visibility: false },
+            UltraMinimal,
+        )
+        .answer();
+        assert_eq!(answer, Answer::Yes);
+    }
+
+    #[test]
+    fn should_permit_identity_transmutation_dfa() {
+        let answer = crate::maybe_transmutable::MaybeTransmutableQuery::new(
+            layout::Dfa::<!>::bool(),
+            layout::Dfa::<!>::bool(),
+            (),
+            crate::Assume { alignment: false, lifetimes: false, validity: true, visibility: false },
+            UltraMinimal,
+        )
+        .answer();
+        assert_eq!(answer, Answer::Yes);
+    }
+
+    #[test]
+    fn should_permit_validity_expansion_and_reject_contraction() {
+        let un = layout::Tree::<Def, !>::uninhabited();
+        let b0 = layout::Tree::<Def, !>::from_bits(0);
+        let b1 = layout::Tree::<Def, !>::from_bits(1);
+        let b2 = layout::Tree::<Def, !>::from_bits(2);
+
+        let alts = [b0, b1, b2];
+
+        let into_layout = |alts: Vec<_>| {
+            alts.into_iter().fold(layout::Tree::<Def, !>::uninhabited(), layout::Tree::<Def, !>::or)
+        };
+
+        let into_set = |alts: Vec<_>| {
+            #[cfg(feature = "rustc")]
+            let mut set = Set::default();
+            #[cfg(not(feature = "rustc"))]
+            let mut set = Set::new();
+            set.extend(alts);
+            set
+        };
+
+        for src_alts in alts.clone().into_iter().powerset() {
+            let src_layout = into_layout(src_alts.clone());
+            let src_set = into_set(src_alts.clone());
+
+            for dst_alts in alts.clone().into_iter().powerset().filter(|alts| !alts.is_empty()) {
+                let dst_layout = into_layout(dst_alts.clone());
+                let dst_set = into_set(dst_alts.clone());
+
+                if src_set.is_subset(&dst_set) {
+                    assert_eq!(
+                        Answer::Yes,
+                        MaybeTransmutableQuery::new(
+                            src_layout.clone(),
+                            dst_layout.clone(),
+                            (),
+                            crate::Assume { validity: false, ..crate::Assume::default() },
+                            UltraMinimal,
+                        )
+                        .answer(),
+                        "{:?} SHOULD be transmutable into {:?}",
+                        src_layout,
+                        dst_layout
+                    );
+                } else if !src_set.is_disjoint(&dst_set) {
+                    assert_eq!(
+                        Answer::Yes,
+                        MaybeTransmutableQuery::new(
+                            src_layout.clone(),
+                            dst_layout.clone(),
+                            (),
+                            crate::Assume { validity: true, ..crate::Assume::default() },
+                            UltraMinimal,
+                        )
+                        .answer(),
+                        "{:?} SHOULD be transmutable (assuming validity) into {:?}",
+                        src_layout,
+                        dst_layout
+                    );
+                } else {
+                    assert_eq!(
+                        Answer::No(Reason::DstIsBitIncompatible),
+                        MaybeTransmutableQuery::new(
+                            src_layout.clone(),
+                            dst_layout.clone(),
+                            (),
+                            crate::Assume { validity: false, ..crate::Assume::default() },
+                            UltraMinimal,
+                        )
+                        .answer(),
+                        "{:?} should NOT be transmutable into {:?}",
+                        src_layout,
+                        dst_layout
+                    );
+                }
+            }
+        }
+    }
+}
index 4142c999ca749a94cbe870b519c03f033893a909..515a73ead777ac61763f2d2c20d8d5f41533f8b4 100644 (file)
@@ -1,6 +1,6 @@
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::DefId;
 use rustc_middle::ty::{self, TyCtxt};
 
 pub fn provide(providers: &mut ty::query::Providers) {
@@ -9,7 +9,6 @@ pub fn provide(providers: &mut ty::query::Providers) {
         associated_item_def_ids,
         associated_items,
         impl_item_implementor_ids,
-        trait_of_item,
         ..*providers
     };
 }
@@ -40,16 +39,6 @@ fn impl_item_implementor_ids(tcx: TyCtxt<'_>, impl_id: DefId) -> FxHashMap<DefId
         .collect()
 }
 
-/// If the given `DefId` describes an item belonging to a trait,
-/// returns the `DefId` of the trait that the trait item belongs to;
-/// otherwise, returns `None`.
-fn trait_of_item(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
-    tcx.opt_associated_item(def_id).and_then(|associated_item| match associated_item.container {
-        ty::TraitContainer(def_id) => Some(def_id),
-        ty::ImplContainer(_) => None,
-    })
-}
-
 fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem {
     let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
     let parent_def_id = tcx.hir().get_parent_item(id);
@@ -59,8 +48,7 @@ fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem {
             if let Some(impl_item_ref) =
                 impl_.items.iter().find(|i| i.id.def_id.to_def_id() == def_id)
             {
-                let assoc_item =
-                    associated_item_from_impl_item_ref(tcx, parent_def_id, impl_item_ref);
+                let assoc_item = associated_item_from_impl_item_ref(impl_item_ref);
                 debug_assert_eq!(assoc_item.def_id, def_id);
                 return assoc_item;
             }
@@ -70,8 +58,7 @@ fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem {
             if let Some(trait_item_ref) =
                 trait_item_refs.iter().find(|i| i.id.def_id.to_def_id() == def_id)
             {
-                let assoc_item =
-                    associated_item_from_trait_item_ref(tcx, parent_def_id, trait_item_ref);
+                let assoc_item = associated_item_from_trait_item_ref(trait_item_ref);
                 debug_assert_eq!(assoc_item.def_id, def_id);
                 return assoc_item;
             }
@@ -87,11 +74,7 @@ fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem {
     )
 }
 
-fn associated_item_from_trait_item_ref(
-    tcx: TyCtxt<'_>,
-    parent_def_id: LocalDefId,
-    trait_item_ref: &hir::TraitItemRef,
-) -> ty::AssocItem {
+fn associated_item_from_trait_item_ref(trait_item_ref: &hir::TraitItemRef) -> ty::AssocItem {
     let def_id = trait_item_ref.id.def_id;
     let (kind, has_self) = match trait_item_ref.kind {
         hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
@@ -102,20 +85,14 @@ fn associated_item_from_trait_item_ref(
     ty::AssocItem {
         name: trait_item_ref.ident.name,
         kind,
-        vis: tcx.visibility(def_id),
-        defaultness: trait_item_ref.defaultness,
         def_id: def_id.to_def_id(),
         trait_item_def_id: Some(def_id.to_def_id()),
-        container: ty::TraitContainer(parent_def_id.to_def_id()),
+        container: ty::TraitContainer,
         fn_has_self_parameter: has_self,
     }
 }
 
-fn associated_item_from_impl_item_ref(
-    tcx: TyCtxt<'_>,
-    parent_def_id: LocalDefId,
-    impl_item_ref: &hir::ImplItemRef,
-) -> ty::AssocItem {
+fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::AssocItem {
     let def_id = impl_item_ref.id.def_id;
     let (kind, has_self) = match impl_item_ref.kind {
         hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
@@ -126,11 +103,9 @@ fn associated_item_from_impl_item_ref(
     ty::AssocItem {
         name: impl_item_ref.ident.name,
         kind,
-        vis: tcx.visibility(def_id),
-        defaultness: impl_item_ref.defaultness,
         def_id: def_id.to_def_id(),
         trait_item_def_id: impl_item_ref.trait_item_def_id,
-        container: ty::ImplContainer(parent_def_id.to_def_id()),
+        container: ty::ImplContainer,
         fn_has_self_parameter: has_self,
     }
 }
index 979e997f2449162aa01878f507c8ce73aed1c8b8..bd1d568cd9a051079bae294ec74562a557c371ce 100644 (file)
@@ -281,7 +281,7 @@ fn resolve_associated_item<'tcx>(
             }
 
             // If the item does not have a value, then we cannot return an instance.
-            if !leaf_def.item.defaultness.has_value() {
+            if !leaf_def.item.defaultness(tcx).has_value() {
                 return Ok(None);
             }
 
index b1af3051719e85ae348628ad4669581fa58a8cd2..db0d45b86fc03dacfb09fb51fdf0e15327b6fb94 100644 (file)
@@ -2,9 +2,7 @@
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::subst::Subst;
-use rustc_middle::ty::{
-    self, Binder, EarlyBinder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt,
-};
+use rustc_middle::ty::{self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt};
 use rustc_trait_selection::traits;
 
 fn sized_constraint_for_ty<'tcx>(
@@ -33,8 +31,9 @@ fn sized_constraint_for_ty<'tcx>(
             let adt_tys = adt.sized_constraint(tcx);
             debug!("sized_constraint_for_ty({:?}) intermediate = {:?}", ty, adt_tys);
             adt_tys
+                .0
                 .iter()
-                .map(|ty| EarlyBinder(*ty).subst(tcx, substs))
+                .map(|ty| adt_tys.rebind(*ty).subst(tcx, substs))
                 .flat_map(|ty| sized_constraint_for_ty(tcx, adtdef, ty))
                 .collect()
         }
@@ -70,11 +69,13 @@ fn sized_constraint_for_ty<'tcx>(
 }
 
 fn impl_defaultness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Defaultness {
-    let item = tcx.hir().expect_item(def_id.expect_local());
-    if let hir::ItemKind::Impl(impl_) = &item.kind {
-        impl_.defaultness
-    } else {
-        bug!("`impl_defaultness` called on {:?}", item);
+    match tcx.hir().get_by_def_id(def_id.expect_local()) {
+        hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) => impl_.defaultness,
+        hir::Node::ImplItem(hir::ImplItem { defaultness, .. })
+        | hir::Node::TraitItem(hir::TraitItem { defaultness, .. }) => *defaultness,
+        node => {
+            bug!("`impl_defaultness` called on {:?}", node);
+        }
     }
 }
 
index faf52e2695a33507a26a659741d934e2453ea7ea..cae29c1d3c5f938a2b103d103a962c2b790d77ca 100644 (file)
@@ -30,3 +30,4 @@ rustc_ty_utils = { path = "../rustc_ty_utils" }
 rustc_lint = { path = "../rustc_lint" }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_type_ir = { path = "../rustc_type_ir" }
+rustc_feature = { path = "../rustc_feature" }
index 99a8101dc96ba3b60239fc167345fed08b70ab67..ff39bf36129bba2828276af51209bd839c27b13e 100644 (file)
@@ -255,7 +255,7 @@ pub(crate) fn complain_about_missing_associated_types(
                 trait_bound_spans.push(*span);
             }
             for assoc_item in items {
-                let trait_def_id = assoc_item.container.id();
+                let trait_def_id = assoc_item.container_id(tcx);
                 names.push(format!(
                     "`{}` (from trait `{}`)",
                     assoc_item.name,
@@ -321,7 +321,7 @@ pub(crate) fn complain_about_missing_associated_types(
             let mut dupes = false;
             for item in assoc_items {
                 let prefix = if names[&item.name] > 1 {
-                    let trait_def_id = item.container.id();
+                    let trait_def_id = item.container_id(tcx);
                     dupes = true;
                     format!("{}::", tcx.def_path_str(trait_def_id))
                 } else {
@@ -376,7 +376,7 @@ pub(crate) fn complain_about_missing_associated_types(
                 let mut label = vec![];
                 for item in assoc_items {
                     let postfix = if names[&item.name] > 1 {
-                        let trait_def_id = item.container.id();
+                        let trait_def_id = item.container_id(tcx);
                         format!(" (from trait `{}`)", tcx.def_path_str(trait_def_id))
                     } else {
                         String::new()
index 444f0fdd45a83faa289223dab995158ecc729f8c..758f1ef97664f1d4c6572e837342907561829fcd 100644 (file)
@@ -16,7 +16,8 @@
 use rustc_ast::TraitObjectSyntax;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{
-    struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, FatalError, MultiSpan,
+    struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, FatalError,
+    MultiSpan,
 };
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
@@ -1141,7 +1142,7 @@ fn add_predicates_for_ast_type_binding(
             .or_else(|| find_item_of_kind(ty::AssocKind::Const))
             .expect("missing associated type");
 
-        if !assoc_item.vis.is_accessible_from(def_scope, tcx) {
+        if !assoc_item.visibility(tcx).is_accessible_from(def_scope, tcx) {
             tcx.sess
                 .struct_span_err(
                     binding.span,
@@ -1160,7 +1161,7 @@ fn add_predicates_for_ast_type_binding(
                         span: binding.span,
                         prev_span: *prev_span,
                         item_name: binding.item_name,
-                        def_path: tcx.def_path_str(assoc_item.container.id()),
+                        def_path: tcx.def_path_str(assoc_item.container_id(tcx)),
                     });
                 })
                 .or_insert(binding.span);
@@ -1997,7 +1998,7 @@ pub fn associated_path_to_ty(
         let ty = self.normalize_ty(span, ty);
 
         let kind = DefKind::AssocTy;
-        if !item.vis.is_accessible_from(def_scope, tcx) {
+        if !item.visibility(tcx).is_accessible_from(def_scope, tcx) {
             let kind = kind.descr(item.def_id);
             let msg = format!("{} `{}` is private", kind, assoc_ident);
             tcx.sess
@@ -2106,7 +2107,7 @@ fn qpath_to_ty(
     pub fn prohibit_generics<'a>(
         &self,
         segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
-        extend: impl Fn(&mut DiagnosticBuilder<'tcx, ErrorGuaranteed>),
+        extend: impl Fn(&mut Diagnostic),
     ) -> bool {
         let args = segments.clone().flat_map(|segment| segment.args().args);
 
@@ -2984,11 +2985,7 @@ fn compute_object_lifetime_bound(
     }
 
     /// Make sure that we are in the condition to suggest the blanket implementation.
-    fn maybe_lint_blanket_trait_impl<T: rustc_errors::EmissionGuarantee>(
-        &self,
-        self_ty: &hir::Ty<'_>,
-        diag: &mut DiagnosticBuilder<'_, T>,
-    ) {
+    fn maybe_lint_blanket_trait_impl(&self, self_ty: &hir::Ty<'_>, diag: &mut Diagnostic) {
         let tcx = self.tcx();
         let parent_id = tcx.hir().get_parent_item(self_ty.hir_id);
         if let hir::Node::Item(hir::Item {
@@ -3081,7 +3078,7 @@ fn maybe_lint_bare_trait(&self, self_ty: &hir::Ty<'_>, in_path: bool) {
                             sugg,
                             Applicability::MachineApplicable,
                         );
-                        self.maybe_lint_blanket_trait_impl::<()>(&self_ty, &mut diag);
+                        self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag);
                         diag.emit();
                     },
                 );
index df315b8a3bc3da7f2a6c9b8fa632440a85597f14..2d50412007d909b493571c7d774bc4c82b729dd0 100644 (file)
@@ -4,7 +4,7 @@
 use rustc_hir::{self as hir, ExprKind};
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::traits::Obligation;
-use rustc_middle::ty::{self, ToPredicate, Ty, TypeVisitable};
+use rustc_middle::ty::{self, ToPredicate, Ty};
 use rustc_span::Span;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 use rustc_trait_selection::traits::{
@@ -94,7 +94,9 @@ pub fn check_match(
             let arm_ty = self.check_expr_with_expectation(&arm.body, expected);
             all_arms_diverge &= self.diverges.get();
 
-            let opt_suggest_box_span = self.opt_suggest_box_span(arm_ty, orig_expected);
+            let opt_suggest_box_span = prior_arm.and_then(|(_, prior_arm_ty, _)| {
+                self.opt_suggest_box_span(prior_arm_ty, arm_ty, orig_expected)
+            });
 
             let (arm_block_id, arm_span) = if let hir::ExprKind::Block(blk, _) = arm.body.kind {
                 (Some(blk.hir_id), self.find_block_span(blk))
@@ -293,6 +295,7 @@ fn maybe_get_coercion_reason(&self, hir_id: hir::HirId, sp: Span) -> Option<(Spa
     pub(crate) fn if_cause(
         &self,
         span: Span,
+        cond_span: Span,
         then_expr: &'tcx hir::Expr<'tcx>,
         else_expr: &'tcx hir::Expr<'tcx>,
         then_ty: Ty<'tcx>,
@@ -357,8 +360,9 @@ pub(crate) fn if_cause(
             // ```
             if block.expr.is_none() && block.stmts.is_empty()
                 && let Some(outer_span) = &mut outer_span
+                && let Some(cond_span) = cond_span.find_ancestor_inside(*outer_span)
             {
-                *outer_span = self.tcx.sess.source_map().guess_head_span(*outer_span);
+                *outer_span = outer_span.with_hi(cond_span.hi())
             }
 
             (self.find_block_span(block), block.hir_id)
@@ -471,43 +475,48 @@ pub(super) fn demand_scrutinee_type(
     // provide a structured suggestion in that case.
     pub(crate) fn opt_suggest_box_span(
         &self,
-        outer_ty: Ty<'tcx>,
+        first_ty: Ty<'tcx>,
+        second_ty: Ty<'tcx>,
         orig_expected: Expectation<'tcx>,
     ) -> Option<Span> {
         match orig_expected {
             Expectation::ExpectHasType(expected)
                 if self.in_tail_expr
-                    && self.ret_coercion.as_ref()?.borrow().merged_ty().has_opaque_types()
-                    && self.can_coerce(outer_ty, expected) =>
+                    && self.return_type_has_opaque
+                    && self.can_coerce(first_ty, expected)
+                    && self.can_coerce(second_ty, expected) =>
             {
                 let obligations = self.fulfillment_cx.borrow().pending_obligations();
                 let mut suggest_box = !obligations.is_empty();
-                for o in obligations {
-                    match o.predicate.kind().skip_binder() {
-                        ty::PredicateKind::Trait(t) => {
-                            let pred =
-                                ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate {
-                                    trait_ref: ty::TraitRef {
-                                        def_id: t.def_id(),
-                                        substs: self.tcx.mk_substs_trait(outer_ty, &[]),
+                'outer: for o in obligations {
+                    for outer_ty in &[first_ty, second_ty] {
+                        match o.predicate.kind().skip_binder() {
+                            ty::PredicateKind::Trait(t) => {
+                                let pred = ty::Binder::dummy(ty::PredicateKind::Trait(
+                                    ty::TraitPredicate {
+                                        trait_ref: ty::TraitRef {
+                                            def_id: t.def_id(),
+                                            substs: self.tcx.mk_substs_trait(*outer_ty, &[]),
+                                        },
+                                        constness: t.constness,
+                                        polarity: t.polarity,
                                     },
-                                    constness: t.constness,
-                                    polarity: t.polarity,
-                                }));
-                            let obl = Obligation::new(
-                                o.cause.clone(),
-                                self.param_env,
-                                pred.to_predicate(self.tcx),
-                            );
-                            suggest_box &= self.predicate_must_hold_modulo_regions(&obl);
-                            if !suggest_box {
-                                // We've encountered some obligation that didn't hold, so the
-                                // return expression can't just be boxed. We don't need to
-                                // evaluate the rest of the obligations.
-                                break;
+                                ));
+                                let obl = Obligation::new(
+                                    o.cause.clone(),
+                                    self.param_env,
+                                    pred.to_predicate(self.tcx),
+                                );
+                                suggest_box &= self.predicate_must_hold_modulo_regions(&obl);
+                                if !suggest_box {
+                                    // We've encountered some obligation that didn't hold, so the
+                                    // return expression can't just be boxed. We don't need to
+                                    // evaluate the rest of the obligations.
+                                    break 'outer;
+                                }
                             }
+                            _ => {}
                         }
-                        _ => {}
                     }
                 }
                 // If all the obligations hold (or there are no obligations) the tail expression
index 7aaddc2bd7aab545fbdd576f558e998ae500f1eb..6c7b2a2889fa49526241835a6ef0c43c6c358b83 100644 (file)
@@ -32,6 +32,7 @@
 
 use crate::hir::def_id::DefId;
 use crate::type_error_struct;
+use hir::def_id::LOCAL_CRATE;
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_hir::lang_items::LangItem;
@@ -40,7 +41,7 @@
 use rustc_middle::ty::cast::{CastKind, CastTy};
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitable};
+use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitable, VariantDef};
 use rustc_session::lint;
 use rustc_session::Session;
 use rustc_span::symbol::sym;
@@ -173,6 +174,7 @@ pub enum CastError {
     /// or "a length". If this argument is None, then the metadata is unknown, for example,
     /// when we're typechecking a type parameter with a ?Sized bound.
     IntToFatCast(Option<&'static str>),
+    ForeignNonExhaustiveAdt,
 }
 
 impl From<ErrorGuaranteed> for CastError {
@@ -591,6 +593,17 @@ fn report_cast_error(&self, fcx: &FnCtxt<'a, 'tcx>, e: CastError) {
                 }
                 err.emit();
             }
+            CastError::ForeignNonExhaustiveAdt => {
+                make_invalid_casting_error(
+                    fcx.tcx.sess,
+                    self.span,
+                    self.expr_ty,
+                    self.cast_ty,
+                    fcx,
+                )
+                .note("cannot cast an enum with a non-exhaustive variant when it's defined in another crate")
+                .emit();
+            }
         }
     }
 
@@ -789,6 +802,14 @@ pub fn do_check(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<CastKind, CastError> {
             _ => return Err(CastError::NonScalar),
         };
 
+        if let ty::Adt(adt_def, _) = *self.expr_ty.kind() {
+            if adt_def.did().krate != LOCAL_CRATE {
+                if adt_def.variants().iter().any(VariantDef::is_field_list_non_exhaustive) {
+                    return Err(CastError::ForeignNonExhaustiveAdt);
+                }
+            }
+        }
+
         match (t_from, t_cast) {
             // These types have invariants! can't cast into them.
             (_, Int(CEnum) | FnPtr) => Err(CastError::NonScalar),
index 9497d5c4528cc9e85eb4b6c842e12c4a01b8f92b..5cdb2acd9f3c5b24cf91b65549dafd2f5d527ee7 100644 (file)
@@ -18,6 +18,7 @@
 use rustc_infer::traits::Obligation;
 use rustc_lint::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
 use rustc_middle::hir::nested_filter;
+use rustc_middle::middle::stability::EvalResult;
 use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::util::{Discr, IntTypeExt};
@@ -32,7 +33,6 @@
 use rustc_trait_selection::traits::{self, ObligationCtxt};
 use rustc_ty_utils::representability::{self, Representability};
 
-use std::iter;
 use std::ops::ControlFlow;
 
 pub(super) fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) {
@@ -1098,18 +1098,34 @@ fn check_impl_items_against_trait<'tcx>(
         for &trait_item_id in tcx.associated_item_def_ids(impl_trait_ref.def_id) {
             let is_implemented = ancestors
                 .leaf_def(tcx, trait_item_id)
-                .map_or(false, |node_item| node_item.item.defaultness.has_value());
+                .map_or(false, |node_item| node_item.item.defaultness(tcx).has_value());
 
             if !is_implemented && tcx.impl_defaultness(impl_id).is_final() {
                 missing_items.push(tcx.associated_item(trait_item_id));
             }
 
-            if let Some(required_items) = &must_implement_one_of {
-                // true if this item is specifically implemented in this impl
-                let is_implemented_here = ancestors
-                    .leaf_def(tcx, trait_item_id)
-                    .map_or(false, |node_item| !node_item.defining_node.is_from_trait());
+            // true if this item is specifically implemented in this impl
+            let is_implemented_here = ancestors
+                .leaf_def(tcx, trait_item_id)
+                .map_or(false, |node_item| !node_item.defining_node.is_from_trait());
+
+            if !is_implemented_here {
+                match tcx.eval_default_body_stability(trait_item_id, full_impl_span) {
+                    EvalResult::Deny { feature, reason, issue, .. } => default_body_is_unstable(
+                        tcx,
+                        full_impl_span,
+                        trait_item_id,
+                        feature,
+                        reason,
+                        issue,
+                    ),
 
+                    // Unmarked default bodies are considered stable (at least for now).
+                    EvalResult::Allow | EvalResult::Unmarked => {}
+                }
+            }
+
+            if let Some(required_items) = &must_implement_one_of {
                 if is_implemented_here {
                     let trait_item = tcx.associated_item(trait_item_id);
                     if required_items.contains(&trait_item.ident(tcx)) {
@@ -1494,76 +1510,107 @@ fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: L
         }
     }
 
-    let mut disr_vals: Vec<Discr<'tcx>> = Vec::with_capacity(vs.len());
-    // This tracks the previous variant span (in the loop) incase we need it for diagnostics
-    let mut prev_variant_span: Span = DUMMY_SP;
-    for ((_, discr), v) in iter::zip(def.discriminants(tcx), vs) {
-        // Check for duplicate discriminant values
-        if let Some(i) = disr_vals.iter().position(|&x| x.val == discr.val) {
-            let variant_did = def.variant(VariantIdx::new(i)).def_id;
-            let variant_i_hir_id = tcx.hir().local_def_id_to_hir_id(variant_did.expect_local());
-            let variant_i = tcx.hir().expect_variant(variant_i_hir_id);
-            let i_span = match variant_i.disr_expr {
-                Some(ref expr) => tcx.hir().span(expr.hir_id),
-                None => tcx.def_span(variant_did),
-            };
-            let span = match v.disr_expr {
-                Some(ref expr) => tcx.hir().span(expr.hir_id),
-                None => v.span,
-            };
-            let display_discr = format_discriminant_overflow(tcx, v, discr);
-            let display_discr_i = format_discriminant_overflow(tcx, variant_i, disr_vals[i]);
-            let no_disr = v.disr_expr.is_none();
-            let mut err = struct_span_err!(
-                tcx.sess,
-                sp,
-                E0081,
-                "discriminant value `{}` assigned more than once",
-                discr,
-            );
-
-            err.span_label(i_span, format!("first assignment of {display_discr_i}"));
-            err.span_label(span, format!("second assignment of {display_discr}"));
-
-            if no_disr {
-                err.span_label(
-                    prev_variant_span,
-                    format!(
-                        "assigned discriminant for `{}` was incremented from this discriminant",
-                        v.ident
-                    ),
-                );
-            }
-            err.emit();
-        }
-
-        disr_vals.push(discr);
-        prev_variant_span = v.span;
-    }
+    detect_discriminant_duplicate(tcx, def.discriminants(tcx).collect(), vs, sp);
 
     check_representable(tcx, sp, def_id);
     check_transparent(tcx, sp, def);
 }
 
-/// In the case that a discriminant is both a duplicate and an overflowing literal,
-/// we insert both the assigned discriminant and the literal it overflowed from into the formatted
-/// output. Otherwise we format the discriminant normally.
-fn format_discriminant_overflow<'tcx>(
+/// Part of enum check. Given the discriminants of an enum, errors if two or more discriminants are equal
+fn detect_discriminant_duplicate<'tcx>(
     tcx: TyCtxt<'tcx>,
-    variant: &hir::Variant<'_>,
-    dis: Discr<'tcx>,
-) -> String {
-    if let Some(expr) = &variant.disr_expr {
-        let body = &tcx.hir().body(expr.body).value;
-        if let hir::ExprKind::Lit(lit) = &body.kind
-            && let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node
-            && dis.val != *lit_value
-        {
-                    return format!("`{dis}` (overflowed from `{lit_value}`)");
+    mut discrs: Vec<(VariantIdx, Discr<'tcx>)>,
+    vs: &'tcx [hir::Variant<'tcx>],
+    self_span: Span,
+) {
+    // Helper closure to reduce duplicate code. This gets called everytime we detect a duplicate.
+    // Here `idx` refers to the order of which the discriminant appears, and its index in `vs`
+    let report = |dis: Discr<'tcx>, idx: usize, err: &mut Diagnostic| {
+        let var = &vs[idx]; // HIR for the duplicate discriminant
+        let (span, display_discr) = match var.disr_expr {
+            Some(ref expr) => {
+                // In the case the discriminant is both a duplicate and overflowed, let the user know
+                if let hir::ExprKind::Lit(lit) = &tcx.hir().body(expr.body).value.kind
+                    && let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node
+                    && *lit_value != dis.val
+                {
+                    (tcx.hir().span(expr.hir_id), format!("`{dis}` (overflowed from `{lit_value}`)"))
+                // Otherwise, format the value as-is
+                } else {
+                    (tcx.hir().span(expr.hir_id), format!("`{dis}`"))
+                }
+            }
+            None => {
+                // At this point we know this discriminant is a duplicate, and was not explicitly
+                // assigned by the user. Here we iterate backwards to fetch the HIR for the last
+                // explictly assigned discriminant, and letting the user know that this was the
+                // increment startpoint, and how many steps from there leading to the duplicate
+                if let Some((n, hir::Variant { span, ident, .. })) =
+                    vs[..idx].iter().rev().enumerate().find(|v| v.1.disr_expr.is_some())
+                {
+                    let ve_ident = var.ident;
+                    let n = n + 1;
+                    let sp = if n > 1 { "variants" } else { "variant" };
+
+                    err.span_label(
+                        *span,
+                        format!("discriminant for `{ve_ident}` incremented from this startpoint (`{ident}` + {n} {sp} later => `{ve_ident}` = {dis})"),
+                    );
+                }
+
+                (vs[idx].span, format!("`{dis}`"))
+            }
+        };
+
+        err.span_label(span, format!("{display_discr} assigned here"));
+    };
+
+    // Here we loop through the discriminants, comparing each discriminant to another.
+    // When a duplicate is detected, we instatiate an error and point to both
+    // initial and duplicate value. The duplicate discriminant is then discarded by swapping
+    // it with the last element and decrementing the `vec.len` (which is why we have to evaluate
+    // `discrs.len()` anew every iteration, and why this could be tricky to do in a functional
+    // style as we are mutating `discrs` on the fly).
+    let mut i = 0;
+    while i < discrs.len() {
+        let hir_var_i_idx = discrs[i].0.index();
+        let mut error: Option<DiagnosticBuilder<'_, _>> = None;
+
+        let mut o = i + 1;
+        while o < discrs.len() {
+            let hir_var_o_idx = discrs[o].0.index();
+
+            if discrs[i].1.val == discrs[o].1.val {
+                let err = error.get_or_insert_with(|| {
+                    let mut ret = struct_span_err!(
+                        tcx.sess,
+                        self_span,
+                        E0081,
+                        "discriminant value `{}` assigned more than once",
+                        discrs[i].1,
+                    );
+
+                    report(discrs[i].1, hir_var_i_idx, &mut ret);
+
+                    ret
+                });
+
+                report(discrs[o].1, hir_var_o_idx, err);
+
+                // Safe to unwrap here, as we wouldn't reach this point if `discrs` was empty
+                discrs[o] = *discrs.last().unwrap();
+                discrs.pop();
+            } else {
+                o += 1;
+            }
         }
-    }
 
-    format!("`{dis}`")
+        if let Some(mut e) = error {
+            e.emit();
+        }
+
+        i += 1;
+    }
 }
 
 pub(super) fn check_type_params_are_used<'tcx>(
index 639cab98f1741f02175482d65b658417c12cb8e0..6c6bbfa22e30cab47a4cf5e52b86efb9aeca1df2 100644 (file)
 use crate::astconv::AstConv;
 use crate::check::FnCtxt;
 use rustc_errors::{
-    struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
+    struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
 };
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::{self, Visitor};
+use rustc_hir::Expr;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::{Coercion, InferOk, InferResult};
 use rustc_infer::traits::{Obligation, TraitEngine, TraitEngineExt};
@@ -87,6 +89,19 @@ fn deref(&self) -> &Self::Target {
 
 type CoerceResult<'tcx> = InferResult<'tcx, (Vec<Adjustment<'tcx>>, Ty<'tcx>)>;
 
+struct CollectRetsVisitor<'tcx> {
+    ret_exprs: Vec<&'tcx hir::Expr<'tcx>>,
+}
+
+impl<'tcx> Visitor<'tcx> for CollectRetsVisitor<'tcx> {
+    fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
+        if let hir::ExprKind::Ret(_) = expr.kind {
+            self.ret_exprs.push(expr);
+        }
+        intravisit::walk_expr(self, expr);
+    }
+}
+
 /// Coercing a mutable reference to an immutable works, while
 /// coercing `&T` to `&mut T` should be forbidden.
 fn coerce_mutbls<'tcx>(
@@ -737,7 +752,7 @@ fn coerce_from_safe_fn<F, G>(
         F: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
         G: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
     {
-        self.commit_unconditionally(|snapshot| {
+        self.commit_if_ok(|snapshot| {
             let result = if let ty::FnPtr(fn_ty_b) = b.kind()
                 && let (hir::Unsafety::Normal, hir::Unsafety::Unsafe) =
                     (fn_ty_a.unsafety(), fn_ty_b.unsafety())
@@ -1464,6 +1479,10 @@ pub(crate) fn coerce_inner<'a>(
                 }
             }
             Err(coercion_error) => {
+                // Mark that we've failed to coerce the types here to suppress
+                // any superfluous errors we might encounter while trying to
+                // emit or provide suggestions on how to fix the initial error.
+                fcx.set_tainted_by_errors();
                 let (expected, found) = if label_expression_as_expected {
                     // In the case where this is a "forced unit", like
                     // `break`, we want to call the `()` "expected"
@@ -1478,9 +1497,11 @@ pub(crate) fn coerce_inner<'a>(
                     // type)
                     (self.final_ty.unwrap_or(self.expected_ty), expression_ty)
                 };
+                let (expected, found) = fcx.resolve_vars_if_possible((expected, found));
 
                 let mut err;
                 let mut unsized_return = false;
+                let mut visitor = CollectRetsVisitor { ret_exprs: vec![] };
                 match *cause.code() {
                     ObligationCauseCode::ReturnNoExpression => {
                         err = struct_span_err!(
@@ -1506,6 +1527,10 @@ pub(crate) fn coerce_inner<'a>(
                         if !fcx.tcx.features().unsized_locals {
                             unsized_return = self.is_return_ty_unsized(fcx, blk_id);
                         }
+                        if let Some(expression) = expression
+                            && let hir::ExprKind::Loop(loop_blk, ..) = expression.kind {
+                              intravisit::walk_block(& mut visitor, loop_blk);
+                        }
                     }
                     ObligationCauseCode::ReturnValue(id) => {
                         err = self.report_return_mismatched_types(
@@ -1551,12 +1576,39 @@ pub(crate) fn coerce_inner<'a>(
                     );
                 }
 
+                if visitor.ret_exprs.len() > 0 && let Some(expr) = expression {
+                    self.note_unreachable_loop_return(&mut err, &expr, &visitor.ret_exprs);
+                }
                 err.emit_unless(unsized_return);
 
                 self.final_ty = Some(fcx.tcx.ty_error());
             }
         }
     }
+    fn note_unreachable_loop_return(
+        &self,
+        err: &mut Diagnostic,
+        expr: &hir::Expr<'tcx>,
+        ret_exprs: &Vec<&'tcx hir::Expr<'tcx>>,
+    ) {
+        let hir::ExprKind::Loop(_, _, _, loop_span) = expr.kind else { return;};
+        let mut span: MultiSpan = vec![loop_span].into();
+        span.push_span_label(loop_span, "this might have zero elements to iterate on");
+        for ret_expr in ret_exprs {
+            span.push_span_label(
+                ret_expr.span,
+                "if the loop doesn't execute, this value would never get returned",
+            );
+        }
+        err.span_note(
+            span,
+            "the function expects a value to always be returned, but loops might run zero times",
+        );
+        err.help(
+            "return a value for the case when the loop has zero elements to iterate on, or \
+           consider changing the return type to account for that possibility",
+        );
+    }
 
     fn report_return_mismatched_types<'a>(
         &self,
@@ -1648,9 +1700,30 @@ fn report_return_mismatched_types<'a>(
             );
         }
 
-        if let (Some(sp), Some(fn_output)) = (fcx.ret_coercion_span.get(), fn_output) {
+        let ret_coercion_span = fcx.ret_coercion_span.get();
+
+        if let Some(sp) = ret_coercion_span
+            // If the closure has an explicit return type annotation, or if
+            // the closure's return type has been inferred from outside
+            // requirements (such as an Fn* trait bound), then a type error
+            // may occur at the first return expression we see in the closure
+            // (if it conflicts with the declared return type). Skip adding a
+            // note in this case, since it would be incorrect.
+            && !fcx.return_type_pre_known
+        {
+            err.span_note(
+                sp,
+                &format!(
+                    "return type inferred to be `{}` here",
+                    expected
+                ),
+            );
+        }
+
+        if let (Some(sp), Some(fn_output)) = (ret_coercion_span, fn_output) {
             self.add_impl_trait_explanation(&mut err, cause, fcx, expected, sp, fn_output);
         }
+
         err
     }
 
index e3ac23686b6d692398543e1754e853693436c7c7..15a995ae59a8bfd8966a1c7a0bce88d9b2cc1459 100644 (file)
@@ -165,7 +165,7 @@ fn compare_predicate_entailment<'tcx>(
 
     // Create mapping from trait to placeholder.
     let trait_to_placeholder_substs =
-        impl_to_placeholder_substs.rebase_onto(tcx, impl_m.container.id(), trait_to_impl_substs);
+        impl_to_placeholder_substs.rebase_onto(tcx, impl_m.container_id(tcx), 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);
@@ -264,8 +264,13 @@ fn compare_predicate_entailment<'tcx>(
 
         let trait_sig = tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs);
         let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_sig);
+        // Next, add all inputs and output as well-formed tys. Importantly,
+        // we have to do this before normalization, since the normalized ty may
+        // not contain the input parameters. See issue #87748.
+        wf_tys.extend(trait_sig.inputs_and_output.iter());
         let trait_sig = ocx.normalize(norm_cause, param_env, trait_sig);
-        // Add the resulting inputs and output as well-formed.
+        // We also have to add the normalized trait signature
+        // as we don't normalize during implied bounds computation.
         wf_tys.extend(trait_sig.inputs_and_output.iter());
         let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig));
 
@@ -511,8 +516,8 @@ fn compare_self_type<'tcx>(
 
     let self_string = |method: &ty::AssocItem| {
         let untransformed_self_ty = match method.container {
-            ty::ImplContainer(_) => impl_trait_ref.self_ty(),
-            ty::TraitContainer(_) => tcx.types.self_param,
+            ty::ImplContainer => impl_trait_ref.self_ty(),
+            ty::TraitContainer => tcx.types.self_param,
         };
         let self_arg_ty = tcx.fn_sig(method.def_id).input(0);
         let param_env = ty::ParamEnv::reveal_all();
@@ -1194,7 +1199,7 @@ fn compare_type_predicate_entailment<'tcx>(
 ) -> Result<(), ErrorGuaranteed> {
     let impl_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id);
     let trait_to_impl_substs =
-        impl_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs);
+        impl_substs.rebase_onto(tcx, impl_ty.container_id(tcx), impl_trait_ref.substs);
 
     let impl_ty_generics = tcx.generics_of(impl_ty.def_id);
     let trait_ty_generics = tcx.generics_of(trait_ty.def_id);
@@ -1390,9 +1395,9 @@ pub fn check_type_bounds<'tcx>(
     });
     let bound_vars = tcx.mk_bound_variable_kinds(bound_vars.into_iter());
     let impl_ty_substs = tcx.intern_substs(&substs);
+    let container_id = impl_ty.container_id(tcx);
 
-    let rebased_substs =
-        impl_ty_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs);
+    let rebased_substs = impl_ty_substs.rebase_onto(tcx, container_id, impl_trait_ref.substs);
     let impl_ty_value = tcx.type_of(impl_ty.def_id);
 
     let param_env = tcx.param_env(impl_ty.def_id);
@@ -1441,8 +1446,7 @@ pub fn check_type_bounds<'tcx>(
     debug!(?normalize_param_env);
 
     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 rebased_substs = impl_ty_substs.rebase_onto(tcx, container_id, impl_trait_ref.substs);
 
     tcx.infer_ctxt().enter(move |infcx| {
         let ocx = ObligationCtxt::new(&infcx);
@@ -1505,10 +1509,13 @@ pub fn check_type_bounds<'tcx>(
         // Finally, resolve all regions. This catches wily misuses of
         // lifetime parameters.
         let implied_bounds = match impl_ty.container {
-            ty::TraitContainer(_) => FxHashSet::default(),
-            ty::ImplContainer(def_id) => {
-                wfcheck::impl_implied_bounds(tcx, param_env, def_id.expect_local(), impl_ty_span)
-            }
+            ty::TraitContainer => FxHashSet::default(),
+            ty::ImplContainer => wfcheck::impl_implied_bounds(
+                tcx,
+                param_env,
+                container_id.expect_local(),
+                impl_ty_span,
+            ),
         };
         let mut outlives_environment = OutlivesEnvironment::new(param_env);
         outlives_environment.add_implied_bounds(&infcx, implied_bounds, impl_ty_hir_id);
index f0110645551af94740851e5a3c434469c6a64a92..bac0be44aa9a2f4b04d1b902fe93d2afaa463d18 100644 (file)
@@ -45,7 +45,6 @@ pub fn emit_coerce_suggestions(
         self.note_type_is_not_clone(err, expected, expr_ty, expr);
         self.note_need_for_fn_pointer(err, expected, expr_ty);
         self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
-        self.report_closure_inferred_return_type(err, expected);
     }
 
     // Requires that the two types unify, and prints an error message if
@@ -599,13 +598,15 @@ fn can_use_as_ref(&self, expr: &hir::Expr<'_>) -> Option<(Span, &'static str, St
         };
 
         let self_ty = self.typeck_results.borrow().expr_ty(&method_expr[0]);
-        let self_ty = format!("{:?}", self_ty);
         let name = method_path.ident.name;
-        let is_as_ref_able = (self_ty.starts_with("&std::option::Option")
-            || self_ty.starts_with("&std::result::Result")
-            || self_ty.starts_with("std::option::Option")
-            || self_ty.starts_with("std::result::Result"))
-            && (name == sym::map || name == sym::and_then);
+        let is_as_ref_able = match self_ty.peel_refs().kind() {
+            ty::Adt(def, _) => {
+                (self.tcx.is_diagnostic_item(sym::Option, def.did())
+                    || self.tcx.is_diagnostic_item(sym::Result, def.did()))
+                    && (name == sym::map || name == sym::and_then)
+            }
+            _ => false,
+        };
         match (is_as_ref_able, self.sess().source_map().span_to_snippet(method_path.ident.span)) {
             (true, Ok(src)) => {
                 let suggestion = format!("as_ref().{}", src);
@@ -775,7 +776,7 @@ pub fn check_ref(
                             self.typeck_results.borrow().type_dependent_def_id(expr.hir_id).map(
                                 |did| {
                                     let ai = self.tcx.associated_item(did);
-                                    ai.container == ty::TraitContainer(clone_trait)
+                                    ai.trait_container(self.tcx) == Some(clone_trait)
                                 },
                             ),
                             segment.ident.name,
@@ -793,7 +794,6 @@ pub fn check_ref(
                             _ if is_range_literal(expr) => true,
                             _ => false,
                         };
-                        let sugg_expr = if needs_parens { format!("({src})") } else { src };
 
                         if let Some(sugg) = self.can_use_as_ref(expr) {
                             return Some((
@@ -821,6 +821,7 @@ pub fn check_ref(
                             }
                         }
 
+                        let sugg_expr = if needs_parens { format!("({src})") } else { src };
                         return Some(match mutability {
                             hir::Mutability::Mut => (
                                 sp,
@@ -1418,25 +1419,4 @@ pub fn check_for_cast(
             _ => false,
         }
     }
-
-    // Report the type inferred by the return statement.
-    fn report_closure_inferred_return_type(&self, err: &mut Diagnostic, expected: Ty<'tcx>) {
-        if let Some(sp) = self.ret_coercion_span.get()
-            // If the closure has an explicit return type annotation, or if
-            // the closure's return type has been inferred from outside
-            // requirements (such as an Fn* trait bound), then a type error
-            // may occur at the first return expression we see in the closure
-            // (if it conflicts with the declared return type). Skip adding a
-            // note in this case, since it would be incorrect.
-            && !self.return_type_pre_known
-        {
-            err.span_note(
-                sp,
-                &format!(
-                    "return type inferred to be `{}` here",
-                    self.resolve_vars_if_possible(expected)
-                ),
-            );
-        }
-    }
 }
index e20c6a2d99a8a99ff05c09207d108a6d8e1ca329..6a6c03a8cba836dfaabfad107b95d7a88e80fea8 100644 (file)
@@ -28,7 +28,7 @@
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::{
     pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticId,
-    EmissionGuarantee, ErrorGuaranteed,
+    ErrorGuaranteed,
 };
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
@@ -50,7 +50,6 @@
 use rustc_span::lev_distance::find_best_match_for_name;
 use rustc_span::source_map::{Span, Spanned};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::{BytePos, Pos};
 use rustc_target::spec::abi::Abi::RustIntrinsic;
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::{self, ObligationCauseCode};
@@ -880,7 +879,7 @@ pub(crate) fn check_lhs_assignable(
         lhs: &'tcx hir::Expr<'tcx>,
         err_code: &'static str,
         op_span: Span,
-        adjust_err: impl FnOnce(&mut DiagnosticBuilder<'tcx, ErrorGuaranteed>),
+        adjust_err: impl FnOnce(&mut Diagnostic),
     ) {
         if lhs.is_syntactic_place_expr() {
             return;
@@ -1002,9 +1001,16 @@ fn check_then_else(
             let else_ty = self.check_expr_with_expectation(else_expr, expected);
             let else_diverges = self.diverges.get();
 
-            let opt_suggest_box_span = self.opt_suggest_box_span(else_ty, orig_expected);
-            let if_cause =
-                self.if_cause(sp, then_expr, else_expr, then_ty, else_ty, opt_suggest_box_span);
+            let opt_suggest_box_span = self.opt_suggest_box_span(then_ty, else_ty, orig_expected);
+            let if_cause = self.if_cause(
+                sp,
+                cond_expr.span,
+                then_expr,
+                else_expr,
+                then_ty,
+                else_ty,
+                opt_suggest_box_span,
+            );
 
             coerce.coerce(self, &if_cause, else_expr, else_ty);
 
@@ -1083,8 +1089,7 @@ fn check_expr_assign(
 
         let lhs_ty = self.check_expr_with_needs(&lhs, Needs::MutPlace);
 
-        let suggest_deref_binop = |err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
-                                   rhs_ty: Ty<'tcx>| {
+        let suggest_deref_binop = |err: &mut Diagnostic, rhs_ty: Ty<'tcx>| {
             if let Some(lhs_deref_ty) = self.deref_once_mutably_for_diagnostic(lhs_ty) {
                 // Can only assign if the type is sized, so if `DerefMut` yields a type that is
                 // unsized, do not suggest dereferencing it.
@@ -2199,9 +2204,9 @@ fn check_field(
         self.tcx().ty_error()
     }
 
-    fn check_call_constructor<G: EmissionGuarantee>(
+    fn check_call_constructor(
         &self,
-        err: &mut DiagnosticBuilder<'_, G>,
+        err: &mut Diagnostic,
         base: &'tcx hir::Expr<'tcx>,
         def_id: DefId,
     ) {
@@ -2391,37 +2396,29 @@ fn ban_take_value_of_method(&self, expr: &hir::Expr<'_>, expr_t: Ty<'tcx>, field
                 expr,
                 Some(span),
             );
+        } else if let ty::RawPtr(ty_and_mut) = expr_t.kind()
+            && let ty::Adt(adt_def, _) = ty_and_mut.ty.kind()
+            && let ExprKind::Field(base_expr, _) = expr.kind
+            && adt_def.variants().len() == 1
+            && adt_def
+                .variants()
+                .iter()
+                .next()
+                .unwrap()
+                .fields
+                .iter()
+                .any(|f| f.ident(self.tcx) == field)
+        {
+            err.multipart_suggestion(
+                "to access the field, dereference first",
+                vec![
+                    (base_expr.span.shrink_to_lo(), "(*".to_string()),
+                    (base_expr.span.shrink_to_hi(), ")".to_string()),
+                ],
+                Applicability::MaybeIncorrect,
+            );
         } else {
-            let mut found = false;
-
-            if let ty::RawPtr(ty_and_mut) = expr_t.kind()
-                && let ty::Adt(adt_def, _) = ty_and_mut.ty.kind()
-            {
-                if adt_def.variants().len() == 1
-                    && adt_def
-                        .variants()
-                        .iter()
-                        .next()
-                        .unwrap()
-                        .fields
-                        .iter()
-                        .any(|f| f.ident(self.tcx) == field)
-                {
-                    if let Some(dot_loc) = expr_snippet.rfind('.') {
-                        found = true;
-                        err.span_suggestion(
-                            expr.span.with_hi(expr.span.lo() + BytePos::from_usize(dot_loc)),
-                            "to access the field, dereference first",
-                            format!("(*{})", &expr_snippet[0..dot_loc]),
-                            Applicability::MaybeIncorrect,
-                        );
-                    }
-                }
-            }
-
-            if !found {
-                err.help("methods are immutable and cannot be assigned to");
-            }
+            err.help("methods are immutable and cannot be assigned to");
         }
 
         err.emit();
@@ -2528,15 +2525,18 @@ fn no_such_field_err(
         );
 
         // try to add a suggestion in case the field is a nested field of a field of the Adt
-        if let Some((fields, substs)) = self.get_field_candidates(span, expr_t) {
-            for candidate_field in fields.iter() {
+        let mod_id = self.tcx.parent_module(id).to_def_id();
+        if let Some((fields, substs)) =
+            self.get_field_candidates_considering_privacy(span, expr_t, mod_id)
+        {
+            for candidate_field in fields {
                 if let Some(mut field_path) = self.check_for_nested_field_satisfying(
                     span,
                     &|candidate_field, _| candidate_field.ident(self.tcx()) == field,
                     candidate_field,
                     substs,
                     vec![],
-                    self.tcx.parent_module(id).to_def_id(),
+                    mod_id,
                 ) {
                     // field_path includes `field` that we're looking for, so pop it.
                     field_path.pop();
@@ -2560,22 +2560,33 @@ fn no_such_field_err(
         err
     }
 
-    pub(crate) fn get_field_candidates(
+    pub(crate) fn get_field_candidates_considering_privacy(
         &self,
         span: Span,
-        base_t: Ty<'tcx>,
-    ) -> Option<(&[ty::FieldDef], SubstsRef<'tcx>)> {
-        debug!("get_field_candidates(span: {:?}, base_t: {:?}", span, base_t);
+        base_ty: Ty<'tcx>,
+        mod_id: DefId,
+    ) -> Option<(impl Iterator<Item = &'tcx ty::FieldDef> + 'tcx, SubstsRef<'tcx>)> {
+        debug!("get_field_candidates(span: {:?}, base_t: {:?}", span, base_ty);
 
-        for (base_t, _) in self.autoderef(span, base_t) {
+        for (base_t, _) in self.autoderef(span, base_ty) {
             match base_t.kind() {
                 ty::Adt(base_def, substs) if !base_def.is_enum() => {
+                    let tcx = self.tcx;
                     let fields = &base_def.non_enum_variant().fields;
-                    // For compile-time reasons put a limit on number of fields we search
-                    if fields.len() > 100 {
-                        return None;
+                    // Some struct, e.g. some that impl `Deref`, have all private fields
+                    // because you're expected to deref them to access the _real_ fields.
+                    // This, for example, will help us suggest accessing a field through a `Box<T>`.
+                    if fields.iter().all(|field| !field.vis.is_accessible_from(mod_id, tcx)) {
+                        continue;
                     }
-                    return Some((fields, substs));
+                    return Some((
+                        fields
+                            .iter()
+                            .filter(move |field| field.vis.is_accessible_from(mod_id, tcx))
+                            // For compile-time reasons put a limit on number of fields we search
+                            .take(100),
+                        substs,
+                    ));
                 }
                 _ => {}
             }
@@ -2592,7 +2603,7 @@ pub(crate) fn check_for_nested_field_satisfying(
         candidate_field: &ty::FieldDef,
         subst: SubstsRef<'tcx>,
         mut field_path: Vec<Ident>,
-        id: DefId,
+        mod_id: DefId,
     ) -> Option<Vec<Ident>> {
         debug!(
             "check_for_nested_field_satisfying(span: {:?}, candidate_field: {:?}, field_path: {:?}",
@@ -2604,24 +2615,24 @@ pub(crate) fn check_for_nested_field_satisfying(
             // up to a depth of three
             None
         } else {
-            // recursively search fields of `candidate_field` if it's a ty::Adt
             field_path.push(candidate_field.ident(self.tcx).normalize_to_macros_2_0());
             let field_ty = candidate_field.ty(self.tcx, subst);
-            if let Some((nested_fields, subst)) = self.get_field_candidates(span, field_ty) {
-                for field in nested_fields.iter() {
-                    if field.vis.is_accessible_from(id, self.tcx) {
-                        if matches(candidate_field, field_ty) {
-                            return Some(field_path);
-                        } else if let Some(field_path) = self.check_for_nested_field_satisfying(
-                            span,
-                            matches,
-                            field,
-                            subst,
-                            field_path.clone(),
-                            id,
-                        ) {
-                            return Some(field_path);
-                        }
+            if matches(candidate_field, field_ty) {
+                return Some(field_path);
+            } else if let Some((nested_fields, subst)) =
+                self.get_field_candidates_considering_privacy(span, field_ty, mod_id)
+            {
+                // recursively search fields of `candidate_field` if it's a ty::Adt
+                for field in nested_fields {
+                    if let Some(field_path) = self.check_for_nested_field_satisfying(
+                        span,
+                        matches,
+                        field,
+                        subst,
+                        field_path.clone(),
+                        mod_id,
+                    ) {
+                        return Some(field_path);
                     }
                 }
             }
index 22087219667b21df772b0e5ddf3a153e4d1bc83f..3a8093345119f2f5f3c9f0e33628cd66b196ccc9 100644 (file)
@@ -1090,13 +1090,15 @@ pub fn instantiate_value_path(
                 is_alias_variant_ctor = true;
             }
             Res::Def(DefKind::AssocFn | DefKind::AssocConst, def_id) => {
-                let container = tcx.associated_item(def_id).container;
-                debug!(?def_id, ?container);
+                let assoc_item = tcx.associated_item(def_id);
+                let container = assoc_item.container;
+                let container_id = assoc_item.container_id(tcx);
+                debug!(?def_id, ?container, ?container_id);
                 match container {
-                    ty::TraitContainer(trait_did) => {
-                        callee::check_legal_trait_for_method_call(tcx, span, None, span, trait_did)
+                    ty::TraitContainer => {
+                        callee::check_legal_trait_for_method_call(tcx, span, None, span, container_id)
                     }
-                    ty::ImplContainer(impl_def_id) => {
+                    ty::ImplContainer => {
                         if segments.len() == 1 {
                             // `<T>::assoc` will end up here, and so
                             // can `T::assoc`. It this came from an
@@ -1104,7 +1106,7 @@ pub fn instantiate_value_path(
                             // `T` for posterity (see `UserSelfTy` for
                             // details).
                             let self_ty = self_ty.expect("UFCS sugared assoc missing Self");
-                            user_self_ty = Some(UserSelfTy { impl_def_id, self_ty });
+                            user_self_ty = Some(UserSelfTy { impl_def_id: container_id, self_ty });
                         }
                     }
                 }
index 33a3f825ac27111bfe7be4623a20accd49b7aa2c..1d1f755947fdcde4a167d5776f08a80c8746af3c 100644 (file)
@@ -1761,13 +1761,13 @@ fn point_at_type_arg_instead_of_call_if_possible(
                             .filter_map(|seg| seg.args.as_ref())
                             .flat_map(|a| a.args.iter())
                         {
-                            if let hir::GenericArg::Type(hir_ty) = &arg {
-                                let ty = self.resolve_vars_if_possible(
-                                    self.typeck_results.borrow().node_type(hir_ty.hir_id),
-                                );
-                                if ty == predicate.self_ty() {
-                                    error.obligation.cause.span = hir_ty.span;
-                                }
+                            if let hir::GenericArg::Type(hir_ty) = &arg
+                                && let Some(ty) =
+                                    self.typeck_results.borrow().node_type_opt(hir_ty.hir_id)
+                                && self.resolve_vars_if_possible(ty) == predicate.self_ty()
+                            {
+                                error.obligation.cause.span = hir_ty.span;
+                                break;
                             }
                         }
                     }
@@ -1778,7 +1778,7 @@ fn point_at_type_arg_instead_of_call_if_possible(
 
     fn label_fn_like(
         &self,
-        err: &mut rustc_errors::DiagnosticBuilder<'tcx, rustc_errors::ErrorGuaranteed>,
+        err: &mut Diagnostic,
         callable_def_id: Option<DefId>,
         callee_ty: Option<Ty<'tcx>>,
     ) {
index 05bcc710e16258977dad795ed29b2ba1b55ca9e7..e008d50aa514a44b3eaf892010bb8ea3c6dc0372 100644 (file)
 use std::cell::{Cell, RefCell};
 use std::ops::Deref;
 
+/// The `FnCtxt` stores type-checking context needed to type-check bodies of
+/// functions, closures, and `const`s, including performing type inference
+/// with [`InferCtxt`].
+///
+/// This is in contrast to [`ItemCtxt`], which is used to type-check item *signatures*
+/// and thus does not perform type inference.
+///
+/// See [`ItemCtxt`]'s docs for more.
+///
+/// [`ItemCtxt`]: crate::collect::ItemCtxt
+/// [`InferCtxt`]: infer::InferCtxt
 pub struct FnCtxt<'a, 'tcx> {
     pub(super) body_id: hir::HirId,
 
index 097fff6418e11acc05555871a9c0244ce52b624a..57771e0969bac5c80143bcf8c04b8a9217b35ec0 100644 (file)
@@ -839,8 +839,9 @@ pub(crate) fn note_type_is_not_clone(
             && results.type_dependent_def_id(expr.hir_id).map_or(
                 false,
                 |did| {
-                    self.tcx.associated_item(did).container
-                        == ty::AssocItemContainer::TraitContainer(clone_trait_did)
+                    let assoc_item = self.tcx.associated_item(did);
+                    assoc_item.container == ty::AssocItemContainer::TraitContainer
+                        && assoc_item.container_id(self.tcx) == clone_trait_did
                 },
             )
             // If that clone call hasn't already dereferenced the self type (i.e. don't give this
index b14f3d6de4ef1be75c45b024136dd6a31328c41e..2c89b63ae84f813be5350bfbb200bede9c163548 100644 (file)
@@ -238,7 +238,7 @@ fn fresh_receiver_substs(
     ) -> SubstsRef<'tcx> {
         match pick.kind {
             probe::InherentImplPick => {
-                let impl_def_id = pick.item.container.id();
+                let impl_def_id = pick.item.container_id(self.tcx);
                 assert!(
                     self.tcx.impl_trait_ref(impl_def_id).is_none(),
                     "impl {:?} is not an inherent impl",
@@ -248,7 +248,7 @@ fn fresh_receiver_substs(
             }
 
             probe::ObjectPick => {
-                let trait_def_id = pick.item.container.id();
+                let trait_def_id = pick.item.container_id(self.tcx);
                 self.extract_existential_trait_ref(self_ty, |this, object_ty, principal| {
                     // The object data has no entry for the Self
                     // Type. For the purposes of this method call, we
@@ -273,7 +273,7 @@ fn fresh_receiver_substs(
             }
 
             probe::TraitPick => {
-                let trait_def_id = pick.item.container.id();
+                let trait_def_id = pick.item.container_id(self.tcx);
 
                 // Make a trait reference `$0 : Trait<$1...$n>`
                 // consisting entirely of type variables. Later on in
@@ -540,15 +540,14 @@ fn predicates_require_illegal_sized_bound(
 
     fn enforce_illegal_method_limitations(&self, pick: &probe::Pick<'_>) {
         // Disallow calls to the method `drop` defined in the `Drop` trait.
-        match pick.item.container {
-            ty::TraitContainer(trait_def_id) => callee::check_legal_trait_for_method_call(
+        if let Some(trait_def_id) = pick.item.trait_container(self.tcx) {
+            callee::check_legal_trait_for_method_call(
                 self.tcx,
                 self.span,
                 Some(self.self_expr.span),
                 self.call_expr.span,
                 trait_def_id,
-            ),
-            ty::ImplContainer(..) => {}
+            )
         }
     }
 
index c09f63f1e8f117844bc06b014718c8a6351d44e4..0e678c41f8b40047d66a6a18ecda35ad46b50092 100644 (file)
@@ -231,7 +231,7 @@ pub fn lookup_method(
                 ProbeScope::AllTraits,
             ) {
                 // If we find a different result the caller probably forgot to import a trait.
-                Ok(ref new_pick) if *new_pick != pick => vec![new_pick.item.container.id()],
+                Ok(ref new_pick) if *new_pick != pick => vec![new_pick.item.container_id(self.tcx)],
                 Err(Ambiguity(ref sources)) => sources
                     .iter()
                     .filter_map(|source| {
index a2f1f5692c731b3cea2548e7c58c3fc18106a70c..7c68d93040556fb8f74992e36bce3ff596e3d437 100644 (file)
@@ -148,7 +148,7 @@ pub(super) fn lint_dot_call_from_2018(
                     let trait_name = self.trait_path_or_bare_name(
                         span,
                         call_expr.hir_id,
-                        pick.item.container.id(),
+                        pick.item.container_id(self.tcx),
                     );
 
                     let mut lint = lint.build(&format!(
@@ -261,8 +261,9 @@ pub(super) fn lint_fully_qualified_call_from_2018(
         self.tcx.struct_span_lint_hir(RUST_2021_PRELUDE_COLLISIONS, expr_id, span, |lint| {
             // "type" refers to either a type or, more likely, a trait from which
             // the associated function or method is from.
-            let trait_path = self.trait_path_or_bare_name(span, expr_id, pick.item.container.id());
-            let trait_generics = self.tcx.generics_of(pick.item.container.id());
+            let container_id = pick.item.container_id(self.tcx);
+            let trait_path = self.trait_path_or_bare_name(span, expr_id, container_id);
+            let trait_generics = self.tcx.generics_of(container_id);
 
             let trait_name =
                 if trait_generics.params.len() <= trait_generics.has_self as usize {
index 8f5f3657fc972eb628875867fc33a9deae88124d..efe15fec7cbfa0ba88a6e0f281cff93bf665e81d 100644 (file)
@@ -592,9 +592,11 @@ fn reset(&mut self) {
     fn push_candidate(&mut self, candidate: Candidate<'tcx>, is_inherent: bool) {
         let is_accessible = if let Some(name) = self.method_name {
             let item = candidate.item;
-            let def_scope =
-                self.tcx.adjust_ident_and_get_scope(name, item.container.id(), self.body_id).1;
-            item.vis.is_accessible_from(def_scope, self.tcx)
+            let def_scope = self
+                .tcx
+                .adjust_ident_and_get_scope(name, item.container_id(self.tcx), self.body_id)
+                .1;
+            item.visibility(self.tcx).is_accessible_from(def_scope, self.tcx)
         } else {
             true
         };
@@ -1025,7 +1027,7 @@ fn pick(mut self) -> PickResult<'tcx> {
         self.assemble_extension_candidates_for_all_traits();
 
         let out_of_scope_traits = match self.pick_core() {
-            Some(Ok(p)) => vec![p.item.container.id()],
+            Some(Ok(p)) => vec![p.item.container_id(self.tcx)],
             //Some(Ok(p)) => p.iter().map(|p| p.item.container().id()).collect(),
             Some(Err(MethodError::Ambiguity(v))) => v
                 .into_iter()
@@ -1387,7 +1389,8 @@ fn emit_unstable_name_collision_hint(
                             self.tcx.def_path_str(stable_pick.item.def_id),
                         ));
                     }
-                    (ty::AssocKind::Const, ty::AssocItemContainer::TraitContainer(def_id)) => {
+                    (ty::AssocKind::Const, ty::AssocItemContainer::TraitContainer) => {
+                        let def_id = stable_pick.item.container_id(self.tcx);
                         diag.span_suggestion(
                             self.span,
                             "use the fully qualified path to the associated const",
@@ -1429,9 +1432,11 @@ fn select_trait_candidate(
 
     fn candidate_source(&self, candidate: &Candidate<'tcx>, self_ty: Ty<'tcx>) -> CandidateSource {
         match candidate.kind {
-            InherentImplCandidate(..) => CandidateSource::Impl(candidate.item.container.id()),
+            InherentImplCandidate(..) => {
+                CandidateSource::Impl(candidate.item.container_id(self.tcx))
+            }
             ObjectCandidate | WhereClauseCandidate(_) => {
-                CandidateSource::Trait(candidate.item.container.id())
+                CandidateSource::Trait(candidate.item.container_id(self.tcx))
             }
             TraitCandidate(trait_ref) => self.probe(|_| {
                 let _ = self
@@ -1444,7 +1449,7 @@ fn candidate_source(&self, candidate: &Candidate<'tcx>, self_ty: Ty<'tcx>) -> Ca
                         // to that impl.
                         CandidateSource::Impl(impl_data.impl_def_id)
                     }
-                    _ => CandidateSource::Trait(candidate.item.container.id()),
+                    _ => CandidateSource::Trait(candidate.item.container_id(self.tcx)),
                 }
             }),
         }
@@ -1502,7 +1507,7 @@ fn consider_probe(
                     debug!("xform_ret_ty after normalization: {:?}", xform_ret_ty);
 
                     // Check whether the impl imposes obligations we have to worry about.
-                    let impl_def_id = probe.item.container.id();
+                    let impl_def_id = probe.item.container_id(self.tcx);
                     let impl_bounds = self.tcx.predicates_of(impl_def_id);
                     let impl_bounds = impl_bounds.instantiate(self.tcx, substs);
                     let traits::Normalized { value: impl_bounds, obligations: norm_obligations } =
@@ -1653,12 +1658,12 @@ fn collapse_candidates_to_trait_pick(
         probes: &[(&Candidate<'tcx>, ProbeResult)],
     ) -> Option<Pick<'tcx>> {
         // Do all probes correspond to the same trait?
-        let container = probes[0].0.item.container;
-        if let ty::ImplContainer(_) = container {
-            return None;
-        }
-        if probes[1..].iter().any(|&(p, _)| p.item.container != container) {
-            return None;
+        let container = probes[0].0.item.trait_container(self.tcx)?;
+        for (p, _) in &probes[1..] {
+            let p_container = p.item.trait_container(self.tcx)?;
+            if p_container != container {
+                return None;
+            }
         }
 
         // FIXME: check the return type here somehow.
index 56fcd9e0a890743c93f6a118969957760ede4f31..44c7c148c7533145606e83e4275cec0f84e31b1e 100644 (file)
@@ -904,7 +904,7 @@ trait bound{s}",
                     }
                 }
 
-                let label_span_not_found = |err: &mut DiagnosticBuilder<'_, _>| {
+                let label_span_not_found = |err: &mut Diagnostic| {
                     if unsatisfied_predicates.is_empty() {
                         err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
                         let is_string_or_ref_str = match actual.kind() {
@@ -1000,7 +1000,11 @@ trait bound{s}",
                     label_span_not_found(&mut err);
                 }
 
-                self.check_for_field_method(&mut err, source, span, actual, item_name);
+                // Don't suggest (for example) `expr.field.method()` if `expr.method()`
+                // doesn't exist due to unsatisfied predicates.
+                if unsatisfied_predicates.is_empty() {
+                    self.check_for_field_method(&mut err, source, span, actual, item_name);
+                }
 
                 self.check_for_unwrap_self(&mut err, source, span, actual, item_name);
 
@@ -1150,7 +1154,7 @@ fn suggest_field_call(
         rcvr_ty: Ty<'tcx>,
         expr: &hir::Expr<'_>,
         item_name: Ident,
-        err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+        err: &mut Diagnostic,
     ) -> bool {
         let tcx = self.tcx;
         let field_receiver = self.autoderef(span, rcvr_ty).find_map(|(ty, _)| match ty.kind() {
@@ -1327,17 +1331,18 @@ fn suggest_constraining_numerical_ty(
 
     fn check_for_field_method(
         &self,
-        err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+        err: &mut Diagnostic,
         source: SelfSource<'tcx>,
         span: Span,
         actual: Ty<'tcx>,
         item_name: Ident,
     ) {
         if let SelfSource::MethodCall(expr) = source
-            && let Some((fields, substs)) = self.get_field_candidates(span, actual)
+            && let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id()
+            && let Some((fields, substs)) = self.get_field_candidates_considering_privacy(span, actual, mod_id)
         {
             let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
-            for candidate_field in fields.iter() {
+            for candidate_field in fields {
                 if let Some(field_path) = self.check_for_nested_field_satisfying(
                     span,
                     &|_, field_ty| {
@@ -1353,7 +1358,7 @@ fn check_for_field_method(
                     candidate_field,
                     substs,
                     vec![],
-                    self.tcx.parent_module(expr.hir_id).to_def_id(),
+                    mod_id,
                 ) {
                     let field_path_str = field_path
                         .iter()
@@ -1375,7 +1380,7 @@ fn check_for_field_method(
 
     fn check_for_unwrap_self(
         &self,
-        err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+        err: &mut Diagnostic,
         source: SelfSource<'tcx>,
         span: Span,
         actual: Ty<'tcx>,
@@ -1789,7 +1794,7 @@ fn suggest_traits_to_import(
                         // We point at the method, but we just skip the rest of the check for arbitrary
                         // self types and rely on the suggestion to `use` the trait from
                         // `suggest_valid_traits`.
-                        let did = Some(pick.item.container.id());
+                        let did = Some(pick.item.container_id(self.tcx));
                         let skip = skippable.contains(&did);
                         if pick.autoderefs == 0 && !skip {
                             err.span_label(
@@ -1825,7 +1830,7 @@ fn suggest_traits_to_import(
                         )
                     {
                         debug!("try_alt_rcvr: pick candidate {:?}", pick);
-                        let did = Some(pick.item.container.id());
+                        let did = Some(pick.item.container_id(self.tcx));
                         // We don't want to suggest a container type when the missing
                         // method is `.clone()` or `.deref()` otherwise we'd suggest
                         // `Arc::new(foo).clone()`, which is far from what the user wants.
@@ -1937,7 +1942,7 @@ fn suggest_traits_to_import(
                                 }
                             }
                             // We only want to suggest public or local traits (#45781).
-                            item.vis.is_public() || info.def_id.is_local()
+                            item.visibility(self.tcx).is_public() || info.def_id.is_local()
                         })
                         .is_some()
             })
index 17c2e4868aac70e3e03eacd37fae0dc9d74b5a2d..1b50209ee64ccdc1443e5d538760b5ba471957ce 100644 (file)
 use crate::check::gather_locals::GatherLocalsVisitor;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{
-    pluralize, struct_span_err, Applicability, DiagnosticBuilder, EmissionGuarantee, MultiSpan,
+    pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan,
 };
 use rustc_hir as hir;
 use rustc_hir::def::Res;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::{HirIdMap, ImplicitSelfKind, Node};
 use rustc_index::bit_set::BitSet;
-use rustc_index::vec::Idx;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
 use rustc_session::Session;
 use rustc_span::source_map::DUMMY_SP;
 use rustc_span::symbol::{kw, Ident};
-use rustc_span::{self, BytePos, Span};
+use rustc_span::{self, BytePos, Span, Symbol};
 use rustc_target::abi::VariantIdx;
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::traits;
 use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error;
 use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
 use std::cell::RefCell;
+use std::num::NonZeroU32;
 
 use crate::require_c_abi_if_c_variadic;
 use crate::util::common::indenter;
@@ -662,6 +662,37 @@ fn missing_items_must_implement_one_of_err(
     err.emit();
 }
 
+fn default_body_is_unstable(
+    tcx: TyCtxt<'_>,
+    impl_span: Span,
+    item_did: DefId,
+    feature: Symbol,
+    reason: Option<Symbol>,
+    issue: Option<NonZeroU32>,
+) {
+    let missing_item_name = &tcx.associated_item(item_did).name;
+    let use_of_unstable_library_feature_note = match reason {
+        Some(r) => format!("use of unstable library feature '{feature}': {r}"),
+        None => format!("use of unstable library feature '{feature}'"),
+    };
+
+    let mut err = struct_span_err!(
+        tcx.sess,
+        impl_span,
+        E0046,
+        "not all trait items implemented, missing: `{missing_item_name}`",
+    );
+    err.note(format!("default implementation of `{missing_item_name}` is unstable"));
+    err.note(use_of_unstable_library_feature_note);
+    rustc_session::parse::add_feature_diagnostics_for_issue(
+        &mut err,
+        &tcx.sess.parse_sess,
+        feature,
+        rustc_feature::GateIssue::Library(issue),
+    );
+    err.emit();
+}
+
 /// Re-sugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions.
 fn bounds_from_generic_predicates<'tcx>(
     tcx: TyCtxt<'tcx>,
@@ -942,12 +973,7 @@ fn has_expected_num_generic_args<'tcx>(
 /// * `span` - The span of the snippet
 /// * `params` - The number of parameters the constructor accepts
 /// * `err` - A mutable diagnostic builder to add the suggestion to
-fn suggest_call_constructor<G: EmissionGuarantee>(
-    span: Span,
-    kind: CtorOf,
-    params: usize,
-    err: &mut DiagnosticBuilder<'_, G>,
-) {
+fn suggest_call_constructor(span: Span, kind: CtorOf, params: usize, err: &mut Diagnostic) {
     // Note: tuple-structs don't have named fields, so just use placeholders
     let args = vec!["_"; params].join(", ");
     let applicable = if params > 0 {
index 920b3e688089b1f1070c4737b695eaf47c7bf043..eb0c51bb2f9795052a3c7eac68668edeed476e31 100644 (file)
@@ -59,7 +59,7 @@ pub fn check_binop_assign(
                 {
                     // Suppress this error, since we already emitted
                     // a deref suggestion in check_overloaded_binop
-                    err.delay_as_bug();
+                    err.downgrade_to_delayed_bug();
                 }
             }
         });
index 837c323553c60e698349a6023a7162fae81824b7..a13c7152582077defba80f87f24df6a44adc8c4e 100644 (file)
@@ -600,7 +600,7 @@ fn check_pat_ident(
         // If there are multiple arms, make sure they all agree on
         // what the type of the binding `x` ought to be.
         if var_id != pat.hir_id {
-            self.check_binding_alt_eq_ty(pat.span, var_id, local_ty, ti);
+            self.check_binding_alt_eq_ty(ba, pat.span, var_id, local_ty, ti);
         }
 
         if let Some(p) = sub {
@@ -610,7 +610,14 @@ fn check_pat_ident(
         local_ty
     }
 
-    fn check_binding_alt_eq_ty(&self, span: Span, var_id: HirId, ty: Ty<'tcx>, ti: TopInfo<'tcx>) {
+    fn check_binding_alt_eq_ty(
+        &self,
+        ba: hir::BindingAnnotation,
+        span: Span,
+        var_id: HirId,
+        ty: Ty<'tcx>,
+        ti: TopInfo<'tcx>,
+    ) {
         let var_ty = self.local_ty(span, var_id).decl_ty;
         if let Some(mut err) = self.demand_eqtype_pat_diag(span, var_ty, ty, ti) {
             let hir = self.tcx.hir();
@@ -628,12 +635,50 @@ fn check_binding_alt_eq_ty(&self, span: Span, var_id: HirId, ty: Ty<'tcx>, ti: T
             });
             let pre = if in_match { "in the same arm, " } else { "" };
             err.note(&format!("{}a binding must have the same type in all alternatives", pre));
-            // FIXME: check if `var_ty` and `ty` can be made the same type by adding or removing
-            // `ref` or `&` to the pattern.
+            self.suggest_adding_missing_ref_or_removing_ref(
+                &mut err,
+                span,
+                var_ty,
+                self.resolve_vars_with_obligations(ty),
+                ba,
+            );
             err.emit();
         }
     }
 
+    fn suggest_adding_missing_ref_or_removing_ref(
+        &self,
+        err: &mut Diagnostic,
+        span: Span,
+        expected: Ty<'tcx>,
+        actual: Ty<'tcx>,
+        ba: hir::BindingAnnotation,
+    ) {
+        match (expected.kind(), actual.kind(), ba) {
+            (ty::Ref(_, inner_ty, _), _, hir::BindingAnnotation::Unannotated)
+                if self.can_eq(self.param_env, *inner_ty, actual).is_ok() =>
+            {
+                err.span_suggestion_verbose(
+                    span.shrink_to_lo(),
+                    "consider adding `ref`",
+                    "ref ",
+                    Applicability::MaybeIncorrect,
+                );
+            }
+            (_, ty::Ref(_, inner_ty, _), hir::BindingAnnotation::Ref)
+                if self.can_eq(self.param_env, expected, *inner_ty).is_ok() =>
+            {
+                err.span_suggestion_verbose(
+                    span.with_hi(span.lo() + BytePos(4)),
+                    "consider removing `ref`",
+                    "",
+                    Applicability::MaybeIncorrect,
+                );
+            }
+            _ => (),
+        }
+    }
+
     // Precondition: pat is a Ref(_) pattern
     fn borrow_pat_suggestion(&self, err: &mut Diagnostic, pat: &Pat<'_>) {
         let tcx = self.tcx;
index faab862cc3c3c2d6cc255342523795081389c297..d0334cd0df7bbf97f1818038469215160b5c4a3a 100644 (file)
@@ -15,8 +15,8 @@
 use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst};
 use rustc_middle::ty::trait_def::TraitSpecializationKind;
 use rustc_middle::ty::{
-    self, AdtKind, DefIdTree, EarlyBinder, GenericParamDefKind, ToPredicate, Ty, TyCtxt,
-    TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor,
+    self, AdtKind, DefIdTree, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable,
+    TypeSuperVisitable, TypeVisitable, TypeVisitor,
 };
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::{sym, Ident, Symbol};
@@ -977,11 +977,14 @@ fn check_associated_item(
         let item = tcx.associated_item(item_id);
 
         let (mut implied_bounds, self_ty) = match item.container {
-            ty::TraitContainer(_) => (FxHashSet::default(), tcx.types.self_param),
-            ty::ImplContainer(def_id) => (
-                impl_implied_bounds(tcx, wfcx.param_env, def_id.expect_local(), span),
-                tcx.type_of(def_id),
-            ),
+            ty::TraitContainer => (FxHashSet::default(), tcx.types.self_param),
+            ty::ImplContainer => {
+                let def_id = item.container_id(tcx);
+                (
+                    impl_implied_bounds(tcx, wfcx.param_env, def_id.expect_local(), span),
+                    tcx.type_of(def_id),
+                )
+            }
         };
 
         match item.kind {
@@ -1004,10 +1007,10 @@ fn check_associated_item(
                 check_method_receiver(wfcx, hir_sig, item, self_ty);
             }
             ty::AssocKind::Type => {
-                if let ty::AssocItemContainer::TraitContainer(_) = item.container {
+                if let ty::AssocItemContainer::TraitContainer = item.container {
                     check_associated_type_bounds(wfcx, item, span)
                 }
-                if item.defaultness.has_value() {
+                if item.defaultness(tcx).has_value() {
                     let ty = tcx.type_of(item.def_id);
                     let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty);
                     wfcx.register_wf_obligation(span, loc, ty.into());
@@ -1292,7 +1295,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
     let infcx = wfcx.infcx;
     let tcx = wfcx.tcx();
 
-    let predicates = tcx.predicates_of(def_id);
+    let predicates = tcx.bound_predicates_of(def_id.to_def_id());
     let generics = tcx.generics_of(def_id);
 
     let is_our_default = |def: &ty::GenericParamDef| match def.kind {
@@ -1389,6 +1392,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
 
     // Now we build the substituted predicates.
     let default_obligations = predicates
+        .0
         .predicates
         .iter()
         .flat_map(|&(pred, sp)| {
@@ -1419,7 +1423,7 @@ fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
             }
             let mut param_count = CountParams::default();
             let has_region = pred.visit_with(&mut param_count).is_break();
-            let substituted_pred = EarlyBinder(pred).subst(tcx, substs);
+            let substituted_pred = predicates.rebind(pred).subst(tcx, substs);
             // Don't check non-defaulted params, dependent defaults (including lifetimes)
             // or preds with multiple params.
             if substituted_pred.has_param_types_or_consts()
@@ -1427,7 +1431,7 @@ fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
                 || has_region
             {
                 None
-            } else if predicates.predicates.iter().any(|&(p, _)| p == substituted_pred) {
+            } else if predicates.0.predicates.iter().any(|&(p, _)| p == substituted_pred) {
                 // Avoid duplication of predicates that contain no parameters, for example.
                 None
             } else {
@@ -1453,7 +1457,7 @@ fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
             traits::Obligation::new(cause, wfcx.param_env, pred)
         });
 
-    let predicates = predicates.instantiate_identity(tcx);
+    let predicates = predicates.0.instantiate_identity(tcx);
 
     let predicates = wfcx.normalize(span, None, predicates);
 
index c23cbd71723a060194add68f932c104ba3fb8975..043e21fc1e32b320728035a9963ed879046a1123 100644 (file)
@@ -15,7 +15,7 @@
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
 use rustc_trait_selection::traits::misc::{can_type_implement_copy, CopyImplementationError};
 use rustc_trait_selection::traits::predicate_for_trait_def;
-use rustc_trait_selection::traits::{self, ObligationCause, TraitEngine, TraitEngineExt};
+use rustc_trait_selection::traits::{self, ObligationCause};
 use std::collections::BTreeMap;
 
 pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) {
@@ -109,15 +109,13 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
                 // it is not immediately clear why Copy is not implemented for a field, since
                 // all we point at is the field itself.
                 tcx.infer_ctxt().ignoring_regions().enter(|infcx| {
-                    let mut fulfill_cx = traits::FulfillmentContext::new();
-                    fulfill_cx.register_bound(
+                    for error in traits::fully_solve_bound(
                         &infcx,
+                        traits::ObligationCause::dummy_with_span(field_ty_span),
                         param_env,
                         ty,
                         tcx.lang_items().copy_trait().unwrap(),
-                        traits::ObligationCause::dummy_with_span(field_ty_span),
-                    );
-                    for error in fulfill_cx.select_all_or_error(&infcx) {
+                    ) {
                         let error_predicate = error.obligation.predicate;
                         // Only note if it's not the root obligation, otherwise it's trivial and
                         // should be self-explanatory (i.e. a field literally doesn't implement Copy).
@@ -315,24 +313,20 @@ fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did:
                     ))
                     .emit();
                 } else {
-                    let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
-
-                    for field in coerced_fields {
-                        let predicate = predicate_for_trait_def(
-                            tcx,
-                            param_env,
-                            cause.clone(),
-                            dispatch_from_dyn_trait,
-                            0,
-                            field.ty(tcx, substs_a),
-                            &[field.ty(tcx, substs_b).into()],
-                        );
-
-                        fulfill_cx.register_predicate_obligation(&infcx, predicate);
-                    }
-
-                    // Check that all transitive obligations are satisfied.
-                    let errors = fulfill_cx.select_all_or_error(&infcx);
+                    let errors = traits::fully_solve_obligations(
+                        &infcx,
+                        coerced_fields.into_iter().map(|field| {
+                            predicate_for_trait_def(
+                                tcx,
+                                param_env,
+                                cause.clone(),
+                                dispatch_from_dyn_trait,
+                                0,
+                                field.ty(tcx, substs_a),
+                                &[field.ty(tcx, substs_b).into()],
+                            )
+                        }),
+                    );
                     if !errors.is_empty() {
                         infcx.report_fulfillment_errors(&errors, None, false);
                     }
@@ -573,8 +567,6 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
             }
         };
 
-        let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
-
         // Register an obligation for `A: Trait<B>`.
         let cause = traits::ObligationCause::misc(span, impl_hir_id);
         let predicate = predicate_for_trait_def(
@@ -586,10 +578,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
             source,
             &[target.into()],
         );
-        fulfill_cx.register_predicate_obligation(&infcx, predicate);
-
-        // Check that all transitive obligations are satisfied.
-        let errors = fulfill_cx.select_all_or_error(&infcx);
+        let errors = traits::fully_solve_obligation(&infcx, predicate);
         if !errors.is_empty() {
             infcx.report_fulfillment_errors(&errors, None, false);
         }
index 36111637a561c3a83d0a69702e00cb60e3640175..e7c5ecc60ec78c7a01cafd3cee3d8aad1f38839c 100644 (file)
@@ -94,7 +94,27 @@ pub fn provide(providers: &mut Providers) {
 ///////////////////////////////////////////////////////////////////////////
 
 /// Context specific to some particular item. This is what implements
-/// `AstConv`. It has information about the predicates that are defined
+/// [`AstConv`].
+///
+/// # `ItemCtxt` vs `FnCtxt`
+///
+/// `ItemCtxt` is primarily used to type-check item signatures and lower them
+/// from HIR to their [`ty::Ty`] representation, which is exposed using [`AstConv`].
+/// It's also used for the bodies of items like structs where the body (the fields)
+/// are just signatures.
+///
+/// This is in contrast to [`FnCtxt`], which is used to type-check bodies of
+/// functions, closures, and `const`s -- anywhere that expressions and statements show up.
+///
+/// An important thing to note is that `ItemCtxt` does no inference -- it has no [`InferCtxt`] --
+/// while `FnCtxt` does do inference.
+///
+/// [`FnCtxt`]: crate::check::FnCtxt
+/// [`InferCtxt`]: rustc_infer::infer::InferCtxt
+///
+/// # Trait predicates
+///
+/// `ItemCtxt` has information about the predicates that are defined
 /// on the trait. Unfortunately, this predicate information is
 /// available in various different forms at various points in the
 /// process. So we can't just store a pointer to e.g., the AST or the
@@ -1234,7 +1254,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
 
                 match item {
                     Some(item) if matches!(item.kind, hir::AssocItemKind::Fn { .. }) => {
-                        if !item.defaultness.has_value() {
+                        if !tcx.impl_defaultness(item.id.def_id).has_value() {
                             tcx.sess
                                 .struct_span_err(
                                     item.span,
@@ -2433,7 +2453,7 @@ fn explicit_predicates_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::Generic
             //   supertrait).
             if let ty::Projection(projection) = ty.kind() {
                 projection.substs == trait_identity_substs
-                    && tcx.associated_item(projection.item_def_id).container.id() == def_id
+                    && tcx.associated_item(projection.item_def_id).container_id(tcx) == def_id
             } else {
                 false
             }
@@ -3264,7 +3284,7 @@ fn asm_target_features<'tcx>(tcx: TyCtxt<'tcx>, did: DefId) -> &'tcx FxHashSet<S
 /// applied to the method prototype.
 fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
     if let Some(impl_item) = tcx.opt_associated_item(def_id)
-        && let ty::AssocItemContainer::ImplContainer(_) = impl_item.container
+        && let ty::AssocItemContainer::ImplContainer = impl_item.container
         && let Some(trait_item) = impl_item.trait_item_def_id
     {
         return tcx
index 8801d0260bffce02a0074f5dd49315a7d15da7c5..0d2b75d3328fcc3bfb27b9ac27d48db7414b2a4d 100644 (file)
@@ -3,7 +3,7 @@
 use rustc_hir as hir;
 use rustc_infer::traits::util;
 use rustc_middle::ty::subst::InternalSubsts;
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::{self, DefIdTree, TyCtxt};
 use rustc_span::def_id::DefId;
 use rustc_span::Span;
 
@@ -30,7 +30,7 @@ fn associated_type_bounds<'tcx>(
     // Associated types are implicitly sized unless a `?Sized` bound is found
     <dyn AstConv<'_>>::add_implicitly_sized(&icx, &mut bounds, ast_bounds, None, span);
 
-    let trait_def_id = tcx.associated_item(assoc_item_def_id).container.id();
+    let trait_def_id = tcx.parent(assoc_item_def_id);
     let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id.expect_local());
 
     let bounds_from_parent = trait_predicates.predicates.iter().copied().filter(|(pred, _)| {
index 534ddfa9531c160494c75f86564078a4be572f6c..f1dbe64f13abbb33e3cb4a323abb015be0288489 100644 (file)
@@ -801,6 +801,9 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
     match tcx.sess.diagnostic().steal_diagnostic(span, StashKey::ItemNoType) {
         Some(mut err) => {
             if !ty.references_error() {
+                // Only suggest adding `:` if it was missing (and suggested by parsing diagnostic)
+                let colon = if span == item_ident.span.shrink_to_hi() { ":" } else { "" };
+
                 // The parser provided a sub-optimal `HasPlaceholders` suggestion for the type.
                 // We are typeck and have the real type, so remove that and suggest the actual type.
                 // FIXME(eddyb) this looks like it should be functionality on `Diagnostic`.
@@ -816,7 +819,7 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
                     err.span_suggestion(
                         span,
                         &format!("provide a type for the {item}", item = kind),
-                        format!("{}: {}", item_ident, sugg_ty),
+                        format!("{colon} {sugg_ty}"),
                         Applicability::MachineApplicable,
                     );
                 } else {
index 3dc728271b07a87441a63f0269023393f5501495..fd9715e6ca37481b7f6b038a5838a2ba465abec8 100644 (file)
@@ -3,7 +3,6 @@
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{ForeignItem, ForeignItemKind, HirId};
 use rustc_infer::infer::TyCtxtInferExt;
-use rustc_infer::traits::TraitEngine;
 use rustc_infer::traits::{ObligationCause, WellFormedLoc};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, Region, ToPredicate, TyCtxt, TypeFoldable, TypeFolder};
@@ -66,7 +65,6 @@ struct HirWfCheck<'tcx> {
     impl<'tcx> Visitor<'tcx> for HirWfCheck<'tcx> {
         fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
             self.tcx.infer_ctxt().enter(|infcx| {
-                let mut fulfill = traits::FulfillmentContext::new();
                 let tcx_ty =
                     self.icx.to_ty(ty).fold_with(&mut EraseAllBoundRegions { tcx: self.tcx });
                 let cause = traits::ObligationCause::new(
@@ -74,7 +72,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
                     self.hir_id,
                     traits::ObligationCauseCode::WellFormed(None),
                 );
-                fulfill.register_predicate_obligation(
+                let errors = traits::fully_solve_obligation(
                     &infcx,
                     traits::Obligation::new(
                         cause,
@@ -83,8 +81,6 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
                             .to_predicate(self.tcx),
                     ),
                 );
-
-                let errors = fulfill.select_all_or_error(&infcx);
                 if !errors.is_empty() {
                     debug!("Wf-check got errors for {:?}: {:?}", ty, errors);
                     for error in errors {
index 8c26c96816d9bbab16dec6c22ad260a88bacb360..9fee1eaaec9836e90fa9f4afb381743af7f3ef23 100644 (file)
@@ -106,7 +106,7 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId)
             let item = tcx.associated_item(def_id);
             match item.kind {
                 ty::AssocKind::Type => {
-                    if item.defaultness.has_value() {
+                    if item.defaultness(tcx).has_value() {
                         cgp::parameters_for(&tcx.type_of(def_id), true)
                     } else {
                         Vec::new()
index 706b9ee40aa993519f7100d979655e761a7a9628..1563f3552c54133457088b77ce526b58e8fc8139 100644 (file)
 use rustc_hir::def_id::DefId;
 use rustc_hir::{Node, CRATE_HIR_ID};
 use rustc_infer::infer::{InferOk, TyCtxtInferExt};
-use rustc_infer::traits::TraitEngineExt as _;
 use rustc_middle::middle;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::config::EntryFnType;
 use rustc_span::{symbol::sym, Span, DUMMY_SP};
 use rustc_target::spec::abi::Abi;
-use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
-use rustc_trait_selection::traits::{
-    self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt as _,
-};
+use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
 
 use std::iter;
 
@@ -148,18 +144,15 @@ fn require_same_types<'tcx>(
 ) -> bool {
     tcx.infer_ctxt().enter(|ref infcx| {
         let param_env = ty::ParamEnv::empty();
-        let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
-        match infcx.at(cause, param_env).eq(expected, actual) {
-            Ok(InferOk { obligations, .. }) => {
-                fulfill_cx.register_predicate_obligations(infcx, obligations);
-            }
+        let errors = match infcx.at(cause, param_env).eq(expected, actual) {
+            Ok(InferOk { obligations, .. }) => traits::fully_solve_obligations(infcx, obligations),
             Err(err) => {
                 infcx.report_mismatched_types(cause, expected, actual, err).emit();
                 return false;
             }
-        }
+        };
 
-        match fulfill_cx.select_all_or_error(infcx).as_slice() {
+        match &errors[..] {
             [] => true,
             errors => {
                 infcx.report_fulfillment_errors(errors, None, false);
@@ -303,7 +296,7 @@ fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
     }
 
     let expected_return_type;
-    if let Some(term_id) = tcx.lang_items().termination() {
+    if let Some(term_did) = tcx.lang_items().termination() {
         let return_ty = main_fnsig.output();
         let return_ty_span = main_fn_return_type_span(tcx, main_def_id).unwrap_or(main_span);
         if !return_ty.bound_vars().is_empty() {
@@ -314,33 +307,17 @@ fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
         }
         let return_ty = return_ty.skip_binder();
         tcx.infer_ctxt().enter(|infcx| {
+            // Main should have no WC, so empty param env is OK here.
+            let param_env = ty::ParamEnv::empty();
             let cause = traits::ObligationCause::new(
                 return_ty_span,
                 main_diagnostics_hir_id,
                 ObligationCauseCode::MainFunctionType,
             );
-            let mut fulfillment_cx = traits::FulfillmentContext::new();
-            // normalize any potential projections in the return type, then add
-            // any possible obligations to the fulfillment context.
-            // HACK(ThePuzzlemaker) this feels symptomatic of a problem within
-            // checking trait fulfillment, not this here. I'm not sure why it
-            // works in the example in `fn test()` given in #88609? This also
-            // probably isn't the best way to do this.
-            let InferOk { value: norm_return_ty, obligations } = infcx
-                .partially_normalize_associated_types_in(
-                    cause.clone(),
-                    ty::ParamEnv::empty(),
-                    return_ty,
-                );
-            fulfillment_cx.register_predicate_obligations(&infcx, obligations);
-            fulfillment_cx.register_bound(
-                &infcx,
-                ty::ParamEnv::empty(),
-                norm_return_ty,
-                term_id,
-                cause,
-            );
-            let errors = fulfillment_cx.select_all_or_error(&infcx);
+            let ocx = traits::ObligationCtxt::new(&infcx);
+            let norm_return_ty = ocx.normalize(cause.clone(), param_env, return_ty);
+            ocx.register_bound(cause, param_env, norm_return_ty, term_did);
+            let errors = ocx.select_all_or_error();
             if !errors.is_empty() {
                 infcx.report_fulfillment_errors(&errors, None, false);
                 error = true;
index 257a9520eeb25f87fc269e8197fd32096430ba08..3b779280eda66168d9418ff9cc6a8391f74d9e7c 100644 (file)
@@ -2,7 +2,7 @@
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt};
 use rustc_span::Span;
 
 use super::explicit::ExplicitPredicatesMap;
@@ -202,7 +202,7 @@ fn insert_required_predicates_to_be_wf<'tcx>(
                 debug!("Projection");
                 check_explicit_predicates(
                     tcx,
-                    tcx.associated_item(obj.item_def_id).container.id(),
+                    tcx.parent(obj.item_def_id),
                     obj.substs,
                     required_predicates,
                     explicit_map,
index 70b8bcd02208ddd92c91beda2e14cd9fbf90d43b..229a64650848cff7eae1401fe3a5cff720d1354a 100644 (file)
@@ -3,7 +3,7 @@
 use rustc_trait_selection::infer::InferCtxt;
 use rustc_trait_selection::traits::query::type_op::{self, TypeOp, TypeOpOutput};
 use rustc_trait_selection::traits::query::NoSolution;
-use rustc_trait_selection::traits::{FulfillmentContext, ObligationCause, TraitEngine};
+use rustc_trait_selection::traits::{ObligationCause, TraitEngine, TraitEngineExt};
 
 pub use rustc_middle::traits::query::OutlivesBound;
 
@@ -63,7 +63,7 @@ fn implied_outlives_bounds(
         if let Some(constraints) = constraints {
             // Instantiation may have produced new inference variables and constraints on those
             // variables. Process these constraints.
-            let mut fulfill_cx = FulfillmentContext::new();
+            let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(self.tcx);
             let cause = ObligationCause::misc(span, body_id);
             for &constraint in &constraints.outlives {
                 let obligation = self.query_outlives_constraint_to_obligation(
index b3284050f0530fff17fc550bf2d4677e71668f6c..b320cdcc109ddc061fec4a33b2fea4b379ed89e3 100644 (file)
@@ -721,6 +721,10 @@ changelog-seen = 2
 # probably don't want to use this.
 #qemu-rootfs = <none> (path)
 
+# Skip building the `std` library for this target. Enabled by default for
+# target triples containing `-none`, `nvptx`, `switch`, or `-uefi`.
+#no-std = <platform-specific> (bool)
+
 # =============================================================================
 # Distribution options
 #
index 19864d2d4676a6d1cf9bd3c3460b03546e1628a2..3c01e2998cd2f02d4a5c2e8fe49a3fd402793467 100644 (file)
@@ -9,7 +9,7 @@ fn $predictable(bench: &mut Bencher) {
                 for n in 0..(<$t>::BITS / 8) {
                     for i in 1..=(100 as $t) {
                         let x = black_box(i << (n * 8));
-                        black_box(x.log10());
+                        black_box(x.ilog10());
                     }
                 }
             });
@@ -27,7 +27,7 @@ fn $random(bench: &mut Bencher) {
                 .collect();
             bench.iter(|| {
                 for x in &numbers {
-                    black_box(black_box(x).log10());
+                    black_box(black_box(x).ilog10());
                 }
             });
         }
@@ -44,7 +44,7 @@ fn $random_small(bench: &mut Bencher) {
                 .collect();
             bench.iter(|| {
                 for x in &numbers {
-                    black_box(black_box(x).log10());
+                    black_box(black_box(x).ilog10());
                 }
             });
         }
index 59ebe5fbe022776d76fa887b6d773d59aee80381..3473ac09e956fe3a95aec2f497074ebffb90ad5f 100644 (file)
@@ -72,9 +72,8 @@ pub const fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutEr
         Layout::from_size_valid_align(size, unsafe { ValidAlign::new_unchecked(align) })
     }
 
-    /// Internal helper constructor to skip revalidating alignment validity.
-    #[inline]
-    const fn from_size_valid_align(size: usize, align: ValidAlign) -> Result<Self, LayoutError> {
+    #[inline(always)]
+    const fn max_size_for_align(align: ValidAlign) -> usize {
         // (power-of-two implies align != 0.)
 
         // Rounded up size is:
@@ -89,7 +88,13 @@ const fn from_size_valid_align(size: usize, align: ValidAlign) -> Result<Self, L
         //
         // Above implies that checking for summation overflow is both
         // necessary and sufficient.
-        if size > isize::MAX as usize - (align.as_nonzero().get() - 1) {
+        isize::MAX as usize - (align.as_usize() - 1)
+    }
+
+    /// Internal helper constructor to skip revalidating alignment validity.
+    #[inline]
+    const fn from_size_valid_align(size: usize, align: ValidAlign) -> Result<Self, LayoutError> {
+        if size > Self::max_size_for_align(align) {
             return Err(LayoutError);
         }
 
@@ -128,7 +133,7 @@ pub const fn size(&self) -> usize {
                   without modifying the layout"]
     #[inline]
     pub const fn align(&self) -> usize {
-        self.align.as_nonzero().get()
+        self.align.as_usize()
     }
 
     /// Constructs a `Layout` suitable for holding a value of type `T`.
@@ -410,13 +415,33 @@ pub fn extend_packed(&self, next: Self) -> Result<Self, LayoutError> {
 
     /// Creates a layout describing the record for a `[T; n]`.
     ///
-    /// On arithmetic overflow, returns `LayoutError`.
+    /// On arithmetic overflow or when the total size would exceed
+    /// `isize::MAX`, returns `LayoutError`.
     #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")]
     #[inline]
     pub fn array<T>(n: usize) -> Result<Self, LayoutError> {
-        let array_size = mem::size_of::<T>().checked_mul(n).ok_or(LayoutError)?;
-        // The safe constructor is called here to enforce the isize size limit.
-        Layout::from_size_valid_align(array_size, ValidAlign::of::<T>())
+        // Reduce the amount of code we need to monomorphize per `T`.
+        return inner(mem::size_of::<T>(), ValidAlign::of::<T>(), n);
+
+        #[inline]
+        fn inner(element_size: usize, align: ValidAlign, n: usize) -> Result<Layout, LayoutError> {
+            // We need to check two things about the size:
+            //  - That the total size won't overflow a `usize`, and
+            //  - That the total size still fits in an `isize`.
+            // By using division we can check them both with a single threshold.
+            // That'd usually be a bad idea, but thankfully here the element size
+            // and alignment are constants, so the compiler will fold all of it.
+            if element_size != 0 && n > Layout::max_size_for_align(align) / element_size {
+                return Err(LayoutError);
+            }
+
+            let array_size = element_size * n;
+
+            // SAFETY: We just checked above that the `array_size` will not
+            // exceed `isize::MAX` even when rounded up to the alignment.
+            // And `ValidAlign` guarantees it's a power of two.
+            unsafe { Ok(Layout::from_size_align_unchecked(array_size, align.as_usize())) }
+        }
     }
 }
 
index 33f7f494e9d8443e46552e2a0dd3ef8f41ee6b03..b2c895f882c6a6f3f5afabc82a265feb09253595 100644 (file)
@@ -173,13 +173,14 @@ unsafe impl IsRawEqComparable<$t> for $t {}
     )+};
 }
 
-// SAFETY: All the ordinary integer types allow all bit patterns as distinct values
+// SAFETY: All the ordinary integer types have no padding, and are not pointers.
 is_raw_eq_comparable!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
 
-// SAFETY: bool and char have *niches*, but no *padding*, so this is sound
+// SAFETY: bool and char have *niches*, but no *padding* (and these are not pointer types), so this
+// is sound
 is_raw_eq_comparable!(bool, char);
 
-// SAFETY: Similarly, the non-zero types have a niche, but no undef,
+// SAFETY: Similarly, the non-zero types have a niche, but no undef and no pointers,
 // and they compare like their underlying numeric type.
 is_raw_eq_comparable!(
     NonZeroU8,
index eae567cad00e62b7ddf7d5cdfe0e80fa91c020f7..2433139a592b568b9399c8ec0306ac1d9df1e01f 100644 (file)
@@ -892,8 +892,7 @@ pub(crate) fn is_grapheme_extended(self) -> bool {
     ///
     /// The general categories for numbers (`Nd` for decimal digits, `Nl` for letter-like numeric
     /// characters, and `No` for other numeric characters) are specified in the [Unicode Character
-    /// Database][ucd] [`UnicodeData.txt`]. Note that this means ideographic numbers like '三'
-    /// are considered alphabetic, not numeric. Please consider to use `is_ascii_digit` or `is_digit`.
+    /// Database][ucd] [`UnicodeData.txt`].
     ///
     /// This method doesn't cover everything that could be considered a number, e.g. ideographic numbers like '三'.
     /// If you want everything including characters with overlapping purposes then you might want to use
index 59066a33c965eecce361b9869e2b593d3b7a775a..d8b8ac4d8710be98a5efa629b0fdd35d8c4ad48b 100644 (file)
@@ -2,6 +2,7 @@
 use crate::cmp::Ordering;
 use crate::ffi::c_char;
 use crate::fmt::{self, Write};
+use crate::intrinsics;
 use crate::ops;
 use crate::slice;
 use crate::slice::memchr;
@@ -384,21 +385,42 @@ pub fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, FromBytesWithNulError>
     #[must_use]
     #[stable(feature = "cstr_from_bytes", since = "1.10.0")]
     #[rustc_const_stable(feature = "const_cstr_unchecked", since = "1.59.0")]
+    #[rustc_allow_const_fn_unstable(const_eval_select)]
     pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
-        // We're in a const fn, so this is the best we can do
-        debug_assert!(!bytes.is_empty() && bytes[bytes.len() - 1] == 0);
-        // SAFETY: Calling an inner function with the same prerequisites.
-        unsafe { Self::_from_bytes_with_nul_unchecked(bytes) }
-    }
+        #[inline]
+        fn rt_impl(bytes: &[u8]) -> &CStr {
+            // Chance at catching some UB at runtime with debug builds.
+            debug_assert!(!bytes.is_empty() && bytes[bytes.len() - 1] == 0);
 
-    #[inline]
-    const unsafe fn _from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
-        // SAFETY: Casting to CStr is safe because its internal representation
-        // is a [u8] too (safe only inside std).
-        // Dereferencing the obtained pointer is safe because it comes from a
-        // reference. Making a reference is then safe because its lifetime
-        // is bound by the lifetime of the given `bytes`.
-        unsafe { &*(bytes as *const [u8] as *const CStr) }
+            // SAFETY: Casting to CStr is safe because its internal representation
+            // is a [u8] too (safe only inside std).
+            // Dereferencing the obtained pointer is safe because it comes from a
+            // reference. Making a reference is then safe because its lifetime
+            // is bound by the lifetime of the given `bytes`.
+            unsafe { &*(bytes as *const [u8] as *const CStr) }
+        }
+
+        const fn const_impl(bytes: &[u8]) -> &CStr {
+            // Saturating so that an empty slice panics in the assert with a good
+            // message, not here due to underflow.
+            let mut i = bytes.len().saturating_sub(1);
+            assert!(!bytes.is_empty() && bytes[i] == 0, "input was not nul-terminated");
+
+            // Ending null byte exists, skip to the rest.
+            while i != 0 {
+                i -= 1;
+                let byte = bytes[i];
+                assert!(byte != 0, "input contained interior nul");
+            }
+
+            // SAFETY: See `rt_impl` cast.
+            unsafe { &*(bytes as *const [u8] as *const CStr) }
+        }
+
+        // SAFETY: The const and runtime versions have identical behavior
+        // unless the safety contract of `from_bytes_with_nul_unchecked` is
+        // violated, which is UB.
+        unsafe { intrinsics::const_eval_select((bytes,), const_impl, rt_impl) }
     }
 
     /// Returns the inner pointer to this C string.
index 7e65f4ebdad8ae0c9ca4356559ce2469ec89b889..2d44feb15f873b7ae34c2a4be9e7655c9dbecce5 100644 (file)
@@ -1207,13 +1207,26 @@ mod atomics {
 
     /// Reinterprets the bits of a value of one type as another type.
     ///
-    /// Both types must have the same size. Neither the original, nor the result,
-    /// may be an [invalid value](../../nomicon/what-unsafe-does.html).
+    /// Both types must have the same size. Compilation will fail if this is not guaranteed.
     ///
     /// `transmute` is semantically equivalent to a bitwise move of one type
     /// into another. It copies the bits from the source value into the
-    /// destination value, then forgets the original. It's equivalent to C's
-    /// `memcpy` under the hood, just like `transmute_copy`.
+    /// destination value, then forgets the original. Note that source and destination
+    /// are passed by-value, which means if `T` or `U` contain padding, that padding
+    /// is *not* guaranteed to be preserved by `transmute`.
+    ///
+    /// Both the argument and the result must be [valid](../../nomicon/what-unsafe-does.html) at
+    /// their given type. Violating this condition leads to [undefined behavior][ub]. The compiler
+    /// will generate code *assuming that you, the programmer, ensure that there will never be
+    /// undefined behavior*. It is therefore your responsibility to guarantee that every value
+    /// passed to `transmute` is valid at both types `T` and `U`. Failing to uphold this condition
+    /// may lead to unexpected and unstable compilation results. This makes `transmute` **incredibly
+    /// unsafe**. `transmute` should be the absolute last resort.
+    ///
+    /// Transmuting pointers to integers in a `const` context is [undefined behavior][ub].
+    /// Any attempt to use the resulting value for integer operations will abort const-evaluation.
+    /// (And even outside `const`, such transmutation is touching on many unspecified aspects of the
+    /// Rust memory model and should be avoided. See below for alternatives.)
     ///
     /// Because `transmute` is a by-value operation, alignment of the *transmuted values
     /// themselves* is not a concern. As with any other function, the compiler already ensures
@@ -1221,15 +1234,7 @@ mod atomics {
     /// elsewhere* (such as pointers, references, boxes…), the caller has to ensure proper
     /// alignment of the pointed-to values.
     ///
-    /// `transmute` is **incredibly** unsafe. There are a vast number of ways to
-    /// cause [undefined behavior][ub] with this function. `transmute` should be
-    /// the absolute last resort.
-    ///
-    /// Transmuting pointers to integers in a `const` context is [undefined behavior][ub].
-    /// Any attempt to use the resulting value for integer operations will abort const-evaluation.
-    ///
-    /// The [nomicon](../../nomicon/transmutes.html) has additional
-    /// documentation.
+    /// The [nomicon](../../nomicon/transmutes.html) has additional documentation.
     ///
     /// [ub]: ../../reference/behavior-considered-undefined.html
     ///
@@ -2277,7 +2282,8 @@ mod atomics {
     ///
     /// # Safety
     ///
-    /// It's UB to call this if any of the *bytes* in `*a` or `*b` are uninitialized.
+    /// It's UB to call this if any of the *bytes* in `*a` or `*b` are uninitialized or carry a
+    /// pointer value.
     /// Note that this is a stricter criterion than just the *values* being
     /// fully-initialized: if `T` has padding, it's UB to call this intrinsic.
     ///
index 6351e6fbd13748536f0680dccc6efab24daba8f3..20b2d5e2681c23f611466b44f2e54da0db93210a 100644 (file)
 // alignment as a parameter, such as `Layout::padding_needed_for`.
 pub(crate) use valid_align::ValidAlign;
 
+mod transmutability;
+#[unstable(feature = "transmutability", issue = "99571")]
+pub use transmutability::{Assume, BikeshedIntrinsicFrom};
+
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(inline)]
 pub use crate::intrinsics::transmute;
diff --git a/library/core/src/mem/transmutability.rs b/library/core/src/mem/transmutability.rs
new file mode 100644 (file)
index 0000000..b59a5b8
--- /dev/null
@@ -0,0 +1,43 @@
+/// Are values of a type transmutable into values of another type?
+///
+/// This trait is implemented on-the-fly by the compiler for types `Src` and `Self` when the bits of
+/// any value of type `Self` are safely transmutable into a value of type `Dst`, in a given `Context`,
+/// notwithstanding whatever safety checks you have asked the compiler to [`Assume`] are satisfied.
+#[unstable(feature = "transmutability", issue = "99571")]
+#[cfg_attr(not(bootstrap), lang = "transmute_trait")]
+#[rustc_on_unimplemented(
+    message = "`{Src}` cannot be safely transmuted into `{Self}` in the defining scope of `{Context}`.",
+    label = "`{Src}` cannot be safely transmuted into `{Self}` in the defining scope of `{Context}`."
+)]
+pub unsafe trait BikeshedIntrinsicFrom<
+    Src,
+    Context,
+    const ASSUME_ALIGNMENT: bool,
+    const ASSUME_LIFETIMES: bool,
+    const ASSUME_VALIDITY: bool,
+    const ASSUME_VISIBILITY: bool,
+> where
+    Src: ?Sized,
+{
+}
+
+/// What transmutation safety conditions shall the compiler assume that *you* are checking?
+#[unstable(feature = "transmutability", issue = "99571")]
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct Assume {
+    /// When `true`, the compiler assumes that *you* are ensuring (either dynamically or statically) that
+    /// destination referents do not have stricter alignment requirements than source referents.
+    pub alignment: bool,
+
+    /// When `true`, the compiler assume that *you* are ensuring that lifetimes are not extended in a manner
+    /// that violates Rust's memory model.
+    pub lifetimes: bool,
+
+    /// When `true`, the compiler assumes that *you* are ensuring that the source type is actually a valid
+    /// instance of the destination type.
+    pub validity: bool,
+
+    /// When `true`, the compiler assumes that *you* have ensured that it is safe for you to violate the
+    /// type and field privacy of the destination type (and sometimes of the source type, too).
+    pub visibility: bool,
+}
index 4ce6d13cf9027be56fbacae7a81e504770a681b0..b9ccc0b4c799f3763ce520805d16d034744bc24f 100644 (file)
@@ -35,10 +35,15 @@ impl ValidAlign {
         unsafe { mem::transmute::<usize, ValidAlign>(align) }
     }
 
+    #[inline]
+    pub(crate) const fn as_usize(self) -> usize {
+        self.0 as usize
+    }
+
     #[inline]
     pub(crate) const fn as_nonzero(self) -> NonZeroUsize {
         // SAFETY: All the discriminants are non-zero.
-        unsafe { NonZeroUsize::new_unchecked(self.0 as usize) }
+        unsafe { NonZeroUsize::new_unchecked(self.as_usize()) }
     }
 
     /// Returns the base 2 logarithm of the alignment.
index de85fdd6ed2462dcd48c83e7d90144ff34089f34..d2a21b6b38260770323a2d68b39bc0471b09c47b 100644 (file)
@@ -137,7 +137,7 @@ pub fn bit_length(&self) -> usize {
                 // Find the most significant non-zero digit.
                 let msd = digits.iter().rposition(|&x| x != 0);
                 match msd {
-                    Some(msd) => msd * digitbits + digits[msd].log2() as usize + 1,
+                    Some(msd) => msd * digitbits + digits[msd].ilog2() as usize + 1,
                     // There are no non-zero digits, i.e., the number is zero.
                     _ => 0,
                 }
index a66de19bad0edb636f8f2f649cd607203c2a8c64..92b12ed33528db86c9cf897d785bc6347bf72353 100644 (file)
@@ -2204,7 +2204,7 @@ pub const fn checked_next_multiple_of(self, rhs: Self) -> Option<Self> {
         /// rounded down.
         ///
         /// This method might not be optimized owing to implementation details;
-        /// `log2` can produce results more efficiently for base 2, and `log10`
+        /// `ilog2` can produce results more efficiently for base 2, and `ilog10`
         /// can produce results more efficiently for base 10.
         ///
         /// # Panics
@@ -2217,7 +2217,7 @@ pub const fn checked_next_multiple_of(self, rhs: Self) -> Option<Self> {
         ///
         /// ```
         /// #![feature(int_log)]
-        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".log(5), 1);")]
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".ilog(5), 1);")]
         /// ```
         #[unstable(feature = "int_log", issue = "70887")]
         #[must_use = "this returns the result of the operation, \
@@ -2226,8 +2226,8 @@ pub const fn checked_next_multiple_of(self, rhs: Self) -> Option<Self> {
         #[track_caller]
         #[rustc_inherit_overflow_checks]
         #[allow(arithmetic_overflow)]
-        pub const fn log(self, base: Self) -> u32 {
-            match self.checked_log(base) {
+        pub const fn ilog(self, base: Self) -> u32 {
+            match self.checked_ilog(base) {
                 Some(n) => n,
                 None => {
                     // In debug builds, trigger a panic on None.
@@ -2250,7 +2250,7 @@ pub const fn log(self, base: Self) -> u32 {
         ///
         /// ```
         /// #![feature(int_log)]
-        #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".log2(), 1);")]
+        #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".ilog2(), 1);")]
         /// ```
         #[unstable(feature = "int_log", issue = "70887")]
         #[must_use = "this returns the result of the operation, \
@@ -2259,8 +2259,8 @@ pub const fn log(self, base: Self) -> u32 {
         #[track_caller]
         #[rustc_inherit_overflow_checks]
         #[allow(arithmetic_overflow)]
-        pub const fn log2(self) -> u32 {
-            match self.checked_log2() {
+        pub const fn ilog2(self) -> u32 {
+            match self.checked_ilog2() {
                 Some(n) => n,
                 None => {
                     // In debug builds, trigger a panic on None.
@@ -2283,7 +2283,7 @@ pub const fn log2(self) -> u32 {
         ///
         /// ```
         /// #![feature(int_log)]
-        #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".log10(), 1);")]
+        #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".ilog10(), 1);")]
         /// ```
         #[unstable(feature = "int_log", issue = "70887")]
         #[must_use = "this returns the result of the operation, \
@@ -2292,8 +2292,8 @@ pub const fn log2(self) -> u32 {
         #[track_caller]
         #[rustc_inherit_overflow_checks]
         #[allow(arithmetic_overflow)]
-        pub const fn log10(self) -> u32 {
-            match self.checked_log10() {
+        pub const fn ilog10(self) -> u32 {
+            match self.checked_ilog10() {
                 Some(n) => n,
                 None => {
                     // In debug builds, trigger a panic on None.
@@ -2311,20 +2311,20 @@ pub const fn log10(self) -> u32 {
         /// Returns `None` if the number is negative or zero, or if the base is not at least 2.
         ///
         /// This method might not be optimized owing to implementation details;
-        /// `checked_log2` can produce results more efficiently for base 2, and
-        /// `checked_log10` can produce results more efficiently for base 10.
+        /// `checked_ilog2` can produce results more efficiently for base 2, and
+        /// `checked_ilog10` can produce results more efficiently for base 10.
         ///
         /// # Examples
         ///
         /// ```
         /// #![feature(int_log)]
-        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_log(5), Some(1));")]
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_ilog(5), Some(1));")]
         /// ```
         #[unstable(feature = "int_log", issue = "70887")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
-        pub const fn checked_log(self, base: Self) -> Option<u32> {
+        pub const fn checked_ilog(self, base: Self) -> Option<u32> {
             if self <= 0 || base <= 1 {
                 None
             } else {
@@ -2333,7 +2333,7 @@ pub const fn checked_log(self, base: Self) -> Option<u32> {
 
                 // Optimization for 128 bit wide integers.
                 if Self::BITS == 128 {
-                    let b = Self::log2(self) / (Self::log2(base) + 1);
+                    let b = Self::ilog2(self) / (Self::ilog2(base) + 1);
                     n += b;
                     r /= base.pow(b as u32);
                 }
@@ -2354,13 +2354,13 @@ pub const fn checked_log(self, base: Self) -> Option<u32> {
         ///
         /// ```
         /// #![feature(int_log)]
-        #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_log2(), Some(1));")]
+        #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_ilog2(), Some(1));")]
         /// ```
         #[unstable(feature = "int_log", issue = "70887")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
-        pub const fn checked_log2(self) -> Option<u32> {
+        pub const fn checked_ilog2(self) -> Option<u32> {
             if self <= 0 {
                 None
             } else {
@@ -2378,13 +2378,13 @@ pub const fn checked_log2(self) -> Option<u32> {
         ///
         /// ```
         /// #![feature(int_log)]
-        #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_log10(), Some(1));")]
+        #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_ilog10(), Some(1));")]
         /// ```
         #[unstable(feature = "int_log", issue = "70887")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
-        pub const fn checked_log10(self) -> Option<u32> {
+        pub const fn checked_ilog10(self) -> Option<u32> {
             if self > 0 {
                 Some(int_log10::$ActualT(self as $ActualT))
             } else {
index 4de0a0cf564c576928718c32ed85fa2f623d01f4..6196c4da4e32928670529a82433ff98baaea50ba 100644 (file)
@@ -450,7 +450,7 @@ pub const fn checked_next_power_of_two(self) -> Option<$Ty> {
                 /// Returns the base 2 logarithm of the number, rounded down.
                 ///
                 /// This is the same operation as
-                #[doc = concat!("[`", stringify!($Int), "::log2`],")]
+                #[doc = concat!("[`", stringify!($Int), "::ilog2`],")]
                 /// except that it has no failure cases to worry about
                 /// since this value can never be zero.
                 ///
@@ -460,22 +460,22 @@ pub const fn checked_next_power_of_two(self) -> Option<$Ty> {
                 /// #![feature(int_log)]
                 #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
                 ///
-                #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(7).unwrap().log2(), 2);")]
-                #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(8).unwrap().log2(), 3);")]
-                #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(9).unwrap().log2(), 3);")]
+                #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(7).unwrap().ilog2(), 2);")]
+                #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(8).unwrap().ilog2(), 3);")]
+                #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(9).unwrap().ilog2(), 3);")]
                 /// ```
                 #[unstable(feature = "int_log", issue = "70887")]
                 #[must_use = "this returns the result of the operation, \
                               without modifying the original"]
                 #[inline]
-                pub const fn log2(self) -> u32 {
+                pub const fn ilog2(self) -> u32 {
                     Self::BITS - 1 - self.leading_zeros()
                 }
 
                 /// Returns the base 10 logarithm of the number, rounded down.
                 ///
                 /// This is the same operation as
-                #[doc = concat!("[`", stringify!($Int), "::log10`],")]
+                #[doc = concat!("[`", stringify!($Int), "::ilog10`],")]
                 /// except that it has no failure cases to worry about
                 /// since this value can never be zero.
                 ///
@@ -485,15 +485,15 @@ pub const fn log2(self) -> u32 {
                 /// #![feature(int_log)]
                 #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
                 ///
-                #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(99).unwrap().log10(), 1);")]
-                #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(100).unwrap().log10(), 2);")]
-                #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(101).unwrap().log10(), 2);")]
+                #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(99).unwrap().ilog10(), 1);")]
+                #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(100).unwrap().ilog10(), 2);")]
+                #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(101).unwrap().ilog10(), 2);")]
                 /// ```
                 #[unstable(feature = "int_log", issue = "70887")]
                 #[must_use = "this returns the result of the operation, \
                               without modifying the original"]
                 #[inline]
-                pub const fn log10(self) -> u32 {
+                pub const fn ilog10(self) -> u32 {
                     super::int_log10::$Int(self.0)
                 }
             }
index 73365544233eb40815a87bea16d6abf8f8fe4360..aa3e8b9974ecb9e820f287330a3bd84e21d65d4a 100644 (file)
@@ -700,7 +700,7 @@ pub const fn checked_rem_euclid(self, rhs: Self) -> Option<Self> {
         ///
         /// ```
         /// #![feature(int_log)]
-        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".log(5), 1);")]
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".ilog(5), 1);")]
         /// ```
         #[unstable(feature = "int_log", issue = "70887")]
         #[must_use = "this returns the result of the operation, \
@@ -709,8 +709,8 @@ pub const fn checked_rem_euclid(self, rhs: Self) -> Option<Self> {
         #[track_caller]
         #[rustc_inherit_overflow_checks]
         #[allow(arithmetic_overflow)]
-        pub const fn log(self, base: Self) -> u32 {
-            match self.checked_log(base) {
+        pub const fn ilog(self, base: Self) -> u32 {
+            match self.checked_ilog(base) {
                 Some(n) => n,
                 None => {
                     // In debug builds, trigger a panic on None.
@@ -733,7 +733,7 @@ pub const fn log(self, base: Self) -> u32 {
         ///
         /// ```
         /// #![feature(int_log)]
-        #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".log2(), 1);")]
+        #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".ilog2(), 1);")]
         /// ```
         #[unstable(feature = "int_log", issue = "70887")]
         #[must_use = "this returns the result of the operation, \
@@ -742,8 +742,8 @@ pub const fn log(self, base: Self) -> u32 {
         #[track_caller]
         #[rustc_inherit_overflow_checks]
         #[allow(arithmetic_overflow)]
-        pub const fn log2(self) -> u32 {
-            match self.checked_log2() {
+        pub const fn ilog2(self) -> u32 {
+            match self.checked_ilog2() {
                 Some(n) => n,
                 None => {
                     // In debug builds, trigger a panic on None.
@@ -766,7 +766,7 @@ pub const fn log2(self) -> u32 {
         ///
         /// ```
         /// #![feature(int_log)]
-        #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".log10(), 1);")]
+        #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".ilog10(), 1);")]
         /// ```
         #[unstable(feature = "int_log", issue = "70887")]
         #[must_use = "this returns the result of the operation, \
@@ -775,8 +775,8 @@ pub const fn log2(self) -> u32 {
         #[track_caller]
         #[rustc_inherit_overflow_checks]
         #[allow(arithmetic_overflow)]
-        pub const fn log10(self) -> u32 {
-            match self.checked_log10() {
+        pub const fn ilog10(self) -> u32 {
+            match self.checked_ilog10() {
                 Some(n) => n,
                 None => {
                     // In debug builds, trigger a panic on None.
@@ -794,20 +794,20 @@ pub const fn log10(self) -> u32 {
         /// Returns `None` if the number is zero, or if the base is not at least 2.
         ///
         /// This method might not be optimized owing to implementation details;
-        /// `checked_log2` can produce results more efficiently for base 2, and
-        /// `checked_log10` can produce results more efficiently for base 10.
+        /// `checked_ilog2` can produce results more efficiently for base 2, and
+        /// `checked_ilog10` can produce results more efficiently for base 10.
         ///
         /// # Examples
         ///
         /// ```
         /// #![feature(int_log)]
-        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_log(5), Some(1));")]
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_ilog(5), Some(1));")]
         /// ```
         #[unstable(feature = "int_log", issue = "70887")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
-        pub const fn checked_log(self, base: Self) -> Option<u32> {
+        pub const fn checked_ilog(self, base: Self) -> Option<u32> {
             if self <= 0 || base <= 1 {
                 None
             } else {
@@ -816,7 +816,7 @@ pub const fn checked_log(self, base: Self) -> Option<u32> {
 
                 // Optimization for 128 bit wide integers.
                 if Self::BITS == 128 {
-                    let b = Self::log2(self) / (Self::log2(base) + 1);
+                    let b = Self::ilog2(self) / (Self::ilog2(base) + 1);
                     n += b;
                     r /= base.pow(b as u32);
                 }
@@ -837,15 +837,15 @@ pub const fn checked_log(self, base: Self) -> Option<u32> {
         ///
         /// ```
         /// #![feature(int_log)]
-        #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_log2(), Some(1));")]
+        #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_ilog2(), Some(1));")]
         /// ```
         #[unstable(feature = "int_log", issue = "70887")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
-        pub const fn checked_log2(self) -> Option<u32> {
+        pub const fn checked_ilog2(self) -> Option<u32> {
             if let Some(x) = <$NonZeroT>::new(self) {
-                Some(x.log2())
+                Some(x.ilog2())
             } else {
                 None
             }
@@ -859,15 +859,15 @@ pub const fn checked_log2(self) -> Option<u32> {
         ///
         /// ```
         /// #![feature(int_log)]
-        #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_log10(), Some(1));")]
+        #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_ilog10(), Some(1));")]
         /// ```
         #[unstable(feature = "int_log", issue = "70887")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
-        pub const fn checked_log10(self) -> Option<u32> {
+        pub const fn checked_ilog10(self) -> Option<u32> {
             if let Some(x) = <$NonZeroT>::new(self) {
-                Some(x.log10())
+                Some(x.ilog10())
             } else {
                 None
             }
index 716f7c6af8f34c07a788da2d25737941ce94b254..c25b159c533a19ae0f951745301db71fbc18ac77 100644 (file)
@@ -95,8 +95,8 @@ pub fn with_metadata_of<U>(self, mut val: *const U) -> *const U
     ///
     /// This is a bit safer than `as` because it wouldn't silently change the type if the code is
     /// refactored.
-    #[unstable(feature = "ptr_const_cast", issue = "92675")]
-    #[rustc_const_unstable(feature = "ptr_const_cast", issue = "92675")]
+    #[stable(feature = "ptr_const_cast", since = "1.65.0")]
+    #[rustc_const_stable(feature = "ptr_const_cast", since = "1.65.0")]
     pub const fn cast_mut(self) -> *mut T {
         self as _
     }
@@ -1337,11 +1337,8 @@ pub fn is_aligned_to(self, align: usize) -> bool {
             panic!("is_aligned_to: align is not a power-of-two");
         }
 
-        // SAFETY: `is_power_of_two()` will return `false` for zero.
-        unsafe { core::intrinsics::assume(align != 0) };
-
         // Cast is needed for `T: !Sized`
-        self.cast::<u8>().addr() % align == 0
+        self.cast::<u8>().addr() & align - 1 == 0
     }
 }
 
index bd2cadef7742e862f28913ed31b9d4e2e35e159f..fff06b458c7c132a43580491672863369bb4b5f5 100644 (file)
@@ -100,8 +100,8 @@ pub fn with_metadata_of<U>(self, mut val: *mut U) -> *mut U
     /// coercion.
     ///
     /// [`cast_mut`]: #method.cast_mut
-    #[unstable(feature = "ptr_const_cast", issue = "92675")]
-    #[rustc_const_unstable(feature = "ptr_const_cast", issue = "92675")]
+    #[stable(feature = "ptr_const_cast", since = "1.65.0")]
+    #[rustc_const_stable(feature = "ptr_const_cast", since = "1.65.0")]
     pub const fn cast_const(self) -> *const T {
         self as _
     }
@@ -1617,11 +1617,8 @@ pub fn is_aligned_to(self, align: usize) -> bool {
             panic!("is_aligned_to: align is not a power-of-two");
         }
 
-        // SAFETY: `is_power_of_two()` will return `false` for zero.
-        unsafe { core::intrinsics::assume(align != 0) };
-
         // Cast is needed for `T: !Sized`
-        self.cast::<u8>().addr() % align == 0
+        self.cast::<u8>().addr() & align - 1 == 0
     }
 }
 
index c310ffe091d2c77aab0b1c2b7147ad37bafe7881..f43b780ec9a900a18f202d2e8e3cf55a574894d1 100644 (file)
@@ -1788,6 +1788,12 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for ChunksMut<'a, T> {
     const MAY_HAVE_SIDE_EFFECT: bool = false;
 }
 
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<T> Send for ChunksMut<'_, T> where T: Send {}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<T> Sync for ChunksMut<'_, T> where T: Sync {}
+
 /// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a
 /// time), starting at the beginning of the slice.
 ///
@@ -2114,6 +2120,12 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for ChunksExactMut<'a, T> {
     const MAY_HAVE_SIDE_EFFECT: bool = false;
 }
 
+#[stable(feature = "chunks_exact", since = "1.31.0")]
+unsafe impl<T> Send for ChunksExactMut<'_, T> where T: Send {}
+
+#[stable(feature = "chunks_exact", since = "1.31.0")]
+unsafe impl<T> Sync for ChunksExactMut<'_, T> where T: Sync {}
+
 /// A windowed iterator over a slice in overlapping chunks (`N` elements at a
 /// time), starting at the beginning of the slice
 ///
@@ -2835,6 +2847,12 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for RChunksMut<'a, T> {
     const MAY_HAVE_SIDE_EFFECT: bool = false;
 }
 
+#[stable(feature = "rchunks", since = "1.31.0")]
+unsafe impl<T> Send for RChunksMut<'_, T> where T: Send {}
+
+#[stable(feature = "rchunks", since = "1.31.0")]
+unsafe impl<T> Sync for RChunksMut<'_, T> where T: Sync {}
+
 /// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a
 /// time), starting at the end of the slice.
 ///
@@ -3168,6 +3186,12 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for RChunksExactMut<'a, T> {
     const MAY_HAVE_SIDE_EFFECT: bool = false;
 }
 
+#[stable(feature = "rchunks", since = "1.31.0")]
+unsafe impl<T> Send for RChunksExactMut<'_, T> where T: Send {}
+
+#[stable(feature = "rchunks", since = "1.31.0")]
+unsafe impl<T> Sync for RChunksExactMut<'_, T> where T: Sync {}
+
 #[doc(hidden)]
 #[unstable(feature = "trusted_random_access", issue = "none")]
 unsafe impl<'a, T> TrustedRandomAccess for Iter<'a, T> {}
index c4f2e283eb3bc6081b7c1bd4f0c71e0a64942c89..ee66895a7ed2a9dfa6caf796e42cc0e3d9b4da78 100644 (file)
@@ -2353,7 +2353,7 @@ pub fn parse<F: FromStr>(&self) -> Result<F, F::Err> {
     #[inline]
     pub fn is_ascii(&self) -> bool {
         // We can treat each byte as character here: all multibyte characters
-        // start with a byte that is not in the ascii range, so we will stop
+        // start with a byte that is not in the ASCII range, so we will stop
         // there already.
         self.as_bytes().is_ascii()
     }
index 756f1a1663ca718e227732ab7ae1b2a5234ae67d..153dc4dbb0835e02c74493061fe904eb1e65e8fc 100644 (file)
@@ -318,19 +318,11 @@ pub const fn is_zero(&self) -> bool {
     /// assert_eq!(duration.as_secs(), 5);
     /// ```
     ///
-    /// To determine the total number of seconds represented by the `Duration`,
-    /// use `as_secs` in combination with [`subsec_nanos`]:
-    ///
-    /// ```
-    /// use std::time::Duration;
-    ///
-    /// let duration = Duration::new(5, 730023852);
-    ///
-    /// assert_eq!(5.730023852,
-    ///            duration.as_secs() as f64
-    ///            + duration.subsec_nanos() as f64 * 1e-9);
-    /// ```
+    /// To determine the total number of seconds represented by the `Duration`
+    /// including the fractional part, use [`as_secs_f64`] or [`as_secs_f32`]
     ///
+    /// [`as_secs_f64`]: Duration::as_secs_f64
+    /// [`as_secs_f32`]: Duration::as_secs_f32
     /// [`subsec_nanos`]: Duration::subsec_nanos
     #[stable(feature = "duration", since = "1.3.0")]
     #[rustc_const_stable(feature = "duration_consts", since = "1.32.0")]
@@ -1143,7 +1135,7 @@ fn fmt_decimal(
                     // 2. The postfix: can be "µs" so we have to count UTF8 characters.
                     let mut actual_w = prefix.len() + postfix.chars().count();
                     // 3. The integer part:
-                    if let Some(log) = integer_part.checked_log10() {
+                    if let Some(log) = integer_part.checked_ilog10() {
                         // integer_part is > 0, so has length log10(x)+1
                         actual_w += 1 + log as usize;
                     } else {
index 8a5a06b3440f85cf33b614091b26759a442c90e9..3ceaeadcec6c36d8bc0ca34d78a06e185ecdc62c 100644 (file)
@@ -1,4 +1,5 @@
 use core::alloc::Layout;
+use core::mem::size_of;
 use core::ptr::{self, NonNull};
 
 #[test]
@@ -12,6 +13,49 @@ fn const_unchecked_layout() {
     assert_eq!(Some(DANGLING), NonNull::new(ptr::invalid_mut(ALIGN)));
 }
 
+#[test]
+fn layout_round_up_to_align_edge_cases() {
+    const MAX_SIZE: usize = isize::MAX as usize;
+
+    for shift in 0..usize::BITS {
+        let align = 1_usize << shift;
+        let edge = (MAX_SIZE + 1) - align;
+        let low = edge.saturating_sub(10);
+        let high = edge.saturating_add(10);
+        assert!(Layout::from_size_align(low, align).is_ok());
+        assert!(Layout::from_size_align(high, align).is_err());
+        for size in low..=high {
+            assert_eq!(
+                Layout::from_size_align(size, align).is_ok(),
+                size.next_multiple_of(align) <= MAX_SIZE,
+            );
+        }
+    }
+}
+
+#[test]
+fn layout_array_edge_cases() {
+    for_type::<i64>();
+    for_type::<[i32; 0b10101]>();
+    for_type::<[u8; 0b1010101]>();
+
+    // Make sure ZSTs don't lead to divide-by-zero
+    assert_eq!(Layout::array::<()>(usize::MAX).unwrap(), Layout::from_size_align(0, 1).unwrap());
+
+    fn for_type<T>() {
+        const MAX_SIZE: usize = isize::MAX as usize;
+
+        let edge = (MAX_SIZE + 1) / size_of::<T>();
+        let low = edge.saturating_sub(10);
+        let high = edge.saturating_add(10);
+        assert!(Layout::array::<T>(low).is_ok());
+        assert!(Layout::array::<T>(high).is_err());
+        for n in low..=high {
+            assert_eq!(Layout::array::<T>(n).is_ok(), n * size_of::<T>() <= MAX_SIZE);
+        }
+    }
+}
+
 #[test]
 fn layout_debug_shows_log2_of_alignment() {
     // `Debug` is not stable, but here's what it does right now
index dc3092e1486bcb554afaf0b40971880d090195e6..be203fb5c04ff00eb04757cec2448f43db1adf68 100644 (file)
-//! This tests the `Integer::{log,log2,log10}` methods. These tests are in a
+//! This tests the `Integer::{ilog,log2,log10}` methods. These tests are in a
 //! separate file because there's both a large number of them, and not all tests
-//! can be run on Android. This is because in Android `log2` uses an imprecise
+//! can be run on Android. This is because in Android `ilog2` uses an imprecise
 //! approximation:https://github.com/rust-lang/rust/blob/4825e12fc9c79954aa0fe18f5521efa6c19c7539/src/libstd/sys/unix/android.rs#L27-L53
 
 #[test]
-fn checked_log() {
-    assert_eq!(999u32.checked_log(10), Some(2));
-    assert_eq!(1000u32.checked_log(10), Some(3));
-    assert_eq!(555u32.checked_log(13), Some(2));
-    assert_eq!(63u32.checked_log(4), Some(2));
-    assert_eq!(64u32.checked_log(4), Some(3));
-    assert_eq!(10460353203u64.checked_log(3), Some(21));
-    assert_eq!(10460353202u64.checked_log(3), Some(20));
-    assert_eq!(147808829414345923316083210206383297601u128.checked_log(3), Some(80));
-    assert_eq!(147808829414345923316083210206383297600u128.checked_log(3), Some(79));
-    assert_eq!(22528399544939174411840147874772641u128.checked_log(19683), Some(8));
-    assert_eq!(22528399544939174411840147874772631i128.checked_log(19683), Some(7));
-
-    assert_eq!(0u8.checked_log(4), None);
-    assert_eq!(0u16.checked_log(4), None);
-    assert_eq!(0i8.checked_log(4), None);
-    assert_eq!(0i16.checked_log(4), None);
+fn checked_ilog() {
+    assert_eq!(999u32.checked_ilog(10), Some(2));
+    assert_eq!(1000u32.checked_ilog(10), Some(3));
+    assert_eq!(555u32.checked_ilog(13), Some(2));
+    assert_eq!(63u32.checked_ilog(4), Some(2));
+    assert_eq!(64u32.checked_ilog(4), Some(3));
+    assert_eq!(10460353203u64.checked_ilog(3), Some(21));
+    assert_eq!(10460353202u64.checked_ilog(3), Some(20));
+    assert_eq!(147808829414345923316083210206383297601u128.checked_ilog(3), Some(80));
+    assert_eq!(147808829414345923316083210206383297600u128.checked_ilog(3), Some(79));
+    assert_eq!(22528399544939174411840147874772641u128.checked_ilog(19683), Some(8));
+    assert_eq!(22528399544939174411840147874772631i128.checked_ilog(19683), Some(7));
+
+    assert_eq!(0u8.checked_ilog(4), None);
+    assert_eq!(0u16.checked_ilog(4), None);
+    assert_eq!(0i8.checked_ilog(4), None);
+    assert_eq!(0i16.checked_ilog(4), None);
 
     #[cfg(not(miri))] // Miri is too slow
     for i in i16::MIN..=0 {
-        assert_eq!(i.checked_log(4), None);
+        assert_eq!(i.checked_ilog(4), None);
     }
     #[cfg(not(miri))] // Miri is too slow
     for i in 1..=i16::MAX {
-        assert_eq!(i.checked_log(13), Some((i as f32).log(13.0) as u32));
+        assert_eq!(i.checked_ilog(13), Some((i as f32).log(13.0) as u32));
     }
     #[cfg(not(miri))] // Miri is too slow
     for i in 1..=u16::MAX {
-        assert_eq!(i.checked_log(13), Some((i as f32).log(13.0) as u32));
+        assert_eq!(i.checked_ilog(13), Some((i as f32).log(13.0) as u32));
     }
 }
 
 #[test]
-fn checked_log2() {
-    assert_eq!(5u32.checked_log2(), Some(2));
-    assert_eq!(0u64.checked_log2(), None);
-    assert_eq!(128i32.checked_log2(), Some(7));
-    assert_eq!((-55i16).checked_log2(), None);
+fn checked_ilog2() {
+    assert_eq!(5u32.checked_ilog2(), Some(2));
+    assert_eq!(0u64.checked_ilog2(), None);
+    assert_eq!(128i32.checked_ilog2(), Some(7));
+    assert_eq!((-55i16).checked_ilog2(), None);
 
-    assert_eq!(0u8.checked_log2(), None);
-    assert_eq!(0u16.checked_log2(), None);
-    assert_eq!(0i8.checked_log2(), None);
-    assert_eq!(0i16.checked_log2(), None);
+    assert_eq!(0u8.checked_ilog2(), None);
+    assert_eq!(0u16.checked_ilog2(), None);
+    assert_eq!(0i8.checked_ilog2(), None);
+    assert_eq!(0i16.checked_ilog2(), None);
 
     for i in 1..=u8::MAX {
-        assert_eq!(i.checked_log2(), Some((i as f32).log2() as u32));
+        assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32));
     }
     #[cfg(not(miri))] // Miri is too slow
     for i in 1..=u16::MAX {
-        // Guard against Android's imprecise f32::log2 implementation.
+        // Guard against Android's imprecise f32::ilog2 implementation.
         if i != 8192 && i != 32768 {
-            assert_eq!(i.checked_log2(), Some((i as f32).log2() as u32));
+            assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32));
         }
     }
     for i in i8::MIN..=0 {
-        assert_eq!(i.checked_log2(), None);
+        assert_eq!(i.checked_ilog2(), None);
     }
     for i in 1..=i8::MAX {
-        assert_eq!(i.checked_log2(), Some((i as f32).log2() as u32));
+        assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32));
     }
     #[cfg(not(miri))] // Miri is too slow
     for i in i16::MIN..=0 {
-        assert_eq!(i.checked_log2(), None);
+        assert_eq!(i.checked_ilog2(), None);
     }
     #[cfg(not(miri))] // Miri is too slow
     for i in 1..=i16::MAX {
-        // Guard against Android's imprecise f32::log2 implementation.
+        // Guard against Android's imprecise f32::ilog2 implementation.
         if i != 8192 {
-            assert_eq!(i.checked_log2(), Some((i as f32).log2() as u32));
+            assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32));
         }
     }
 }
 
-// Validate cases that fail on Android's imprecise float log2 implementation.
+// Validate cases that fail on Android's imprecise float ilog2 implementation.
 #[test]
 #[cfg(not(target_os = "android"))]
-fn checked_log2_not_android() {
-    assert_eq!(8192u16.checked_log2(), Some((8192f32).log2() as u32));
-    assert_eq!(32768u16.checked_log2(), Some((32768f32).log2() as u32));
-    assert_eq!(8192i16.checked_log2(), Some((8192f32).log2() as u32));
+fn checked_ilog2_not_android() {
+    assert_eq!(8192u16.checked_ilog2(), Some((8192f32).log2() as u32));
+    assert_eq!(32768u16.checked_ilog2(), Some((32768f32).log2() as u32));
+    assert_eq!(8192i16.checked_ilog2(), Some((8192f32).log2() as u32));
 }
 
 #[test]
-fn checked_log10() {
-    assert_eq!(0u8.checked_log10(), None);
-    assert_eq!(0u16.checked_log10(), None);
-    assert_eq!(0i8.checked_log10(), None);
-    assert_eq!(0i16.checked_log10(), None);
+fn checked_ilog10() {
+    assert_eq!(0u8.checked_ilog10(), None);
+    assert_eq!(0u16.checked_ilog10(), None);
+    assert_eq!(0i8.checked_ilog10(), None);
+    assert_eq!(0i16.checked_ilog10(), None);
 
     #[cfg(not(miri))] // Miri is too slow
     for i in i16::MIN..=0 {
-        assert_eq!(i.checked_log10(), None);
+        assert_eq!(i.checked_ilog10(), None);
     }
     #[cfg(not(miri))] // Miri is too slow
     for i in 1..=i16::MAX {
-        assert_eq!(i.checked_log10(), Some((i as f32).log10() as u32));
+        assert_eq!(i.checked_ilog10(), Some((i as f32).log10() as u32));
     }
     #[cfg(not(miri))] // Miri is too slow
     for i in 1..=u16::MAX {
-        assert_eq!(i.checked_log10(), Some((i as f32).log10() as u32));
+        assert_eq!(i.checked_ilog10(), Some((i as f32).log10() as u32));
     }
     #[cfg(not(miri))] // Miri is too slow
     for i in 1..=100_000u32 {
-        assert_eq!(i.checked_log10(), Some((i as f32).log10() as u32));
+        assert_eq!(i.checked_ilog10(), Some((i as f32).log10() as u32));
     }
 }
 
-macro_rules! log10_loop {
-    ($T:ty, $log10_max:expr) => {
-        assert_eq!(<$T>::MAX.log10(), $log10_max);
-        for i in 0..=$log10_max {
+macro_rules! ilog10_loop {
+    ($T:ty, $ilog10_max:expr) => {
+        assert_eq!(<$T>::MAX.ilog10(), $ilog10_max);
+        for i in 0..=$ilog10_max {
             let p = (10 as $T).pow(i as u32);
             if p >= 10 {
-                assert_eq!((p - 9).log10(), i - 1);
-                assert_eq!((p - 1).log10(), i - 1);
+                assert_eq!((p - 9).ilog10(), i - 1);
+                assert_eq!((p - 1).ilog10(), i - 1);
             }
-            assert_eq!(p.log10(), i);
-            assert_eq!((p + 1).log10(), i);
+            assert_eq!(p.ilog10(), i);
+            assert_eq!((p + 1).ilog10(), i);
             if p >= 10 {
-                assert_eq!((p + 9).log10(), i);
+                assert_eq!((p + 9).ilog10(), i);
             }
 
-            // also check `x.log(10)`
+            // also check `x.ilog(10)`
             if p >= 10 {
-                assert_eq!((p - 9).log(10), i - 1);
-                assert_eq!((p - 1).log(10), i - 1);
+                assert_eq!((p - 9).ilog(10), i - 1);
+                assert_eq!((p - 1).ilog(10), i - 1);
             }
-            assert_eq!(p.log(10), i);
-            assert_eq!((p + 1).log(10), i);
+            assert_eq!(p.ilog(10), i);
+            assert_eq!((p + 1).ilog(10), i);
             if p >= 10 {
-                assert_eq!((p + 9).log(10), i);
+                assert_eq!((p + 9).ilog(10), i);
             }
         }
     };
 }
 
 #[test]
-fn log10_u8() {
-    log10_loop! { u8, 2 }
+fn ilog10_u8() {
+    ilog10_loop! { u8, 2 }
 }
 
 #[test]
-fn log10_u16() {
-    log10_loop! { u16, 4 }
+fn ilog10_u16() {
+    ilog10_loop! { u16, 4 }
 }
 
 #[test]
-fn log10_u32() {
-    log10_loop! { u32, 9 }
+fn ilog10_u32() {
+    ilog10_loop! { u32, 9 }
 }
 
 #[test]
-fn log10_u64() {
-    log10_loop! { u64, 19 }
+fn ilog10_u64() {
+    ilog10_loop! { u64, 19 }
 }
 
 #[test]
-fn log10_u128() {
-    log10_loop! { u128, 38 }
+fn ilog10_u128() {
+    ilog10_loop! { u128, 38 }
 }
index 6d1516958f39bd49b38217d196bcb1d11fb16c8c..b8f6fe6961a8edbac5fd821d1146e47a665bdde9 100644 (file)
@@ -1191,6 +1191,28 @@ fn test_rchunks_exact_mut_zip() {
     assert_eq!(v1, [0, 16, 17, 22, 23]);
 }
 
+#[test]
+fn chunks_mut_are_send_and_sync() {
+    use std::cell::Cell;
+    use std::slice::{ChunksExactMut, ChunksMut, RChunksExactMut, RChunksMut};
+    use std::sync::MutexGuard;
+
+    fn assert_send_and_sync()
+    where
+        ChunksMut<'static, Cell<i32>>: Send,
+        ChunksMut<'static, MutexGuard<'static, u32>>: Sync,
+        ChunksExactMut<'static, Cell<i32>>: Send,
+        ChunksExactMut<'static, MutexGuard<'static, u32>>: Sync,
+        RChunksMut<'static, Cell<i32>>: Send,
+        RChunksMut<'static, MutexGuard<'static, u32>>: Sync,
+        RChunksExactMut<'static, Cell<i32>>: Send,
+        RChunksExactMut<'static, MutexGuard<'static, u32>>: Sync,
+    {
+    }
+
+    assert_send_and_sync();
+}
+
 #[test]
 fn test_windows_count() {
     let v: &[i32] = &[0, 1, 2, 3, 4, 5];
index 05e9b2eb6bc3cb64b513a7d0a1b454ce4d475f5d..5cf6ec8178928f710ff11c022271b4cac3488a48 100644 (file)
@@ -9,12 +9,6 @@
 //! implementing `std::error::Error`) to get a causal chain of where an error
 //! was generated.
 //!
-//! > **Note**: this module is unstable and is designed in [RFC 2504], and you
-//! > can learn more about its status in the [tracking issue].
-//!
-//! [RFC 2504]: https://github.com/rust-lang/rfcs/blob/master/text/2504-fix-error.md
-//! [tracking issue]: https://github.com/rust-lang/rust/issues/53487
-//!
 //! ## Accuracy
 //!
 //! Backtraces are attempted to be as accurate as possible, but no guarantees
@@ -64,7 +58,7 @@
 //! `RUST_LIB_BACKTRACE` or `RUST_BACKTRACE` at runtime might not actually change
 //! how backtraces are captured.
 
-#![unstable(feature = "backtrace", issue = "53487")]
+#![stable(feature = "backtrace", since = "1.65.0")]
 
 #[cfg(test)]
 mod tests;
 /// previous point in time. In some instances the `Backtrace` type may
 /// internally be empty due to configuration. For more information see
 /// `Backtrace::capture`.
+#[stable(feature = "backtrace", since = "1.65.0")]
 #[must_use]
 pub struct Backtrace {
     inner: Inner,
@@ -117,17 +112,21 @@ pub struct Backtrace {
 
 /// The current status of a backtrace, indicating whether it was captured or
 /// whether it is empty for some other reason.
+#[stable(feature = "backtrace", since = "1.65.0")]
 #[non_exhaustive]
 #[derive(Debug, PartialEq, Eq)]
 pub enum BacktraceStatus {
     /// Capturing a backtrace is not supported, likely because it's not
     /// implemented for the current platform.
+    #[stable(feature = "backtrace", since = "1.65.0")]
     Unsupported,
     /// Capturing a backtrace has been disabled through either the
     /// `RUST_LIB_BACKTRACE` or `RUST_BACKTRACE` environment variables.
+    #[stable(feature = "backtrace", since = "1.65.0")]
     Disabled,
     /// A backtrace has been captured and the `Backtrace` should print
     /// reasonable information when rendered.
+    #[stable(feature = "backtrace", since = "1.65.0")]
     Captured,
 }
 
@@ -174,6 +173,7 @@ enum BytesOrWide {
     Wide(Vec<u16>),
 }
 
+#[stable(feature = "backtrace", since = "1.65.0")]
 impl fmt::Debug for Backtrace {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         let capture = match &self.inner {
@@ -200,6 +200,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
+#[unstable(feature = "backtrace_frames", issue = "79676")]
 impl fmt::Debug for BacktraceFrame {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         let mut dbg = fmt.debug_list();
@@ -288,6 +289,7 @@ fn enabled() -> bool {
     ///
     /// To forcibly capture a backtrace regardless of environment variables, use
     /// the `Backtrace::force_capture` function.
+    #[stable(feature = "backtrace", since = "1.65.0")]
     #[inline(never)] // want to make sure there's a frame here to remove
     pub fn capture() -> Backtrace {
         if !Backtrace::enabled() {
@@ -306,6 +308,7 @@ pub fn capture() -> Backtrace {
     /// Note that capturing a backtrace can be an expensive operation on some
     /// platforms, so this should be used with caution in performance-sensitive
     /// parts of code.
+    #[stable(feature = "backtrace", since = "1.65.0")]
     #[inline(never)] // want to make sure there's a frame here to remove
     pub fn force_capture() -> Backtrace {
         Backtrace::create(Backtrace::force_capture as usize)
@@ -313,6 +316,8 @@ pub fn force_capture() -> Backtrace {
 
     /// Forcibly captures a disabled backtrace, regardless of environment
     /// variable configuration.
+    #[stable(feature = "backtrace", since = "1.65.0")]
+    #[rustc_const_stable(feature = "backtrace", since = "1.65.0")]
     pub const fn disabled() -> Backtrace {
         Backtrace { inner: Inner::Disabled }
     }
@@ -356,6 +361,7 @@ fn create(ip: usize) -> Backtrace {
     /// Returns the status of this backtrace, indicating whether this backtrace
     /// request was unsupported, disabled, or a stack trace was actually
     /// captured.
+    #[stable(feature = "backtrace", since = "1.65.0")]
     #[must_use]
     pub fn status(&self) -> BacktraceStatus {
         match self.inner {
@@ -375,6 +381,7 @@ pub fn frames(&'a self) -> &'a [BacktraceFrame] {
     }
 }
 
+#[stable(feature = "backtrace", since = "1.65.0")]
 impl fmt::Display for Backtrace {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         let capture = match &self.inner {
index ff7b70c328daf6b62e29e7b3b1aa5b34a4c3ddb2..df7a49d258282488ff8e1e8e54d13da68bdb0f61 100644 (file)
@@ -260,20 +260,6 @@ fn type_id(&self, _: private::Internal) -> TypeId
         TypeId::of::<Self>()
     }
 
-    /// Returns a stack backtrace, if available, of where this error occurred.
-    ///
-    /// This function allows inspecting the location, in code, of where an error
-    /// happened. The returned `Backtrace` contains information about the stack
-    /// trace of the OS thread of execution of where the error originated from.
-    ///
-    /// Note that not all errors contain a `Backtrace`. Also note that a
-    /// `Backtrace` may actually be empty. For more information consult the
-    /// `Backtrace` type itself.
-    #[unstable(feature = "backtrace", issue = "53487")]
-    fn backtrace(&self) -> Option<&Backtrace> {
-        None
-    }
-
     /// ```
     /// if let Err(e) = "xc".parse::<u32>() {
     ///     // Print `e` itself, no need for description().
@@ -370,7 +356,7 @@ fn provide<'a>(&'a self, req: &mut Demand<'a>) {}
 }
 
 #[unstable(feature = "error_generic_member_access", issue = "99301")]
-impl Provider for dyn Error + 'static {
+impl<'b> Provider for dyn Error + 'b {
     fn provide<'a>(&'a self, req: &mut Demand<'a>) {
         self.provide(req)
     }
@@ -757,8 +743,8 @@ fn source(&self) -> Option<&(dyn Error + 'static)> {
         Error::source(&**self)
     }
 
-    fn backtrace(&self) -> Option<&Backtrace> {
-        Error::backtrace(&**self)
+    fn provide<'b>(&'b self, req: &mut Demand<'b>) {
+        Error::provide(&**self, req);
     }
 }
 
@@ -778,8 +764,8 @@ fn source(&self) -> Option<&(dyn Error + 'static)> {
         Error::source(&**self)
     }
 
-    fn backtrace(&self) -> Option<&Backtrace> {
-        Error::backtrace(&**self)
+    fn provide<'a>(&'a self, req: &mut Demand<'a>) {
+        Error::provide(&**self, req);
     }
 }
 
@@ -871,6 +857,20 @@ fn source(&self) -> Option<&(dyn Error + 'static)> {
     }
 }
 
+impl<'a> dyn Error + 'a {
+    /// Request a reference of type `T` as context about this error.
+    #[unstable(feature = "error_generic_member_access", issue = "99301")]
+    pub fn request_ref<T: ?Sized + 'static>(&'a self) -> Option<&'a T> {
+        core::any::request_ref(self)
+    }
+
+    /// Request a value of type `T` as context about this error.
+    #[unstable(feature = "error_generic_member_access", issue = "99301")]
+    pub fn request_value<T: 'static>(&'a self) -> Option<T> {
+        core::any::request_value(self)
+    }
+}
+
 // Copied from `any.rs`.
 impl dyn Error + 'static {
     /// Returns `true` if the inner type is the same as `T`.
@@ -910,18 +910,6 @@ pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
             None
         }
     }
-
-    /// Request a reference of type `T` as context about this error.
-    #[unstable(feature = "error_generic_member_access", issue = "99301")]
-    pub fn request_ref<T: ?Sized + 'static>(&self) -> Option<&T> {
-        core::any::request_ref(self)
-    }
-
-    /// Request a value of type `T` as context about this error.
-    #[unstable(feature = "error_generic_member_access", issue = "99301")]
-    pub fn request_value<T: 'static>(&self) -> Option<T> {
-        core::any::request_value(self)
-    }
 }
 
 impl dyn Error + 'static + Send {
@@ -949,13 +937,13 @@ pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
     /// Request a reference of type `T` as context about this error.
     #[unstable(feature = "error_generic_member_access", issue = "99301")]
     pub fn request_ref<T: ?Sized + 'static>(&self) -> Option<&T> {
-        <dyn Error + 'static>::request_ref(self)
+        <dyn Error>::request_ref(self)
     }
 
     /// Request a value of type `T` as context about this error.
     #[unstable(feature = "error_generic_member_access", issue = "99301")]
     pub fn request_value<T: 'static>(&self) -> Option<T> {
-        <dyn Error + 'static>::request_value(self)
+        <dyn Error>::request_value(self)
     }
 }
 
@@ -984,13 +972,13 @@ pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
     /// Request a reference of type `T` as context about this error.
     #[unstable(feature = "error_generic_member_access", issue = "99301")]
     pub fn request_ref<T: ?Sized + 'static>(&self) -> Option<&T> {
-        <dyn Error + 'static>::request_ref(self)
+        <dyn Error>::request_ref(self)
     }
 
     /// Request a value of type `T` as context about this error.
     #[unstable(feature = "error_generic_member_access", issue = "99301")]
     pub fn request_value<T: 'static>(&self) -> Option<T> {
-        <dyn Error + 'static>::request_value(self)
+        <dyn Error>::request_value(self)
     }
 }
 
@@ -1466,9 +1454,11 @@ pub fn pretty(mut self, pretty: bool) -> Self {
     ///
     /// ```rust
     /// #![feature(error_reporter)]
-    /// #![feature(backtrace)]
+    /// #![feature(provide_any)]
+    /// #![feature(error_generic_member_access)]
     /// # use std::error::Error;
     /// # use std::fmt;
+    /// use std::any::Demand;
     /// use std::error::Report;
     /// use std::backtrace::Backtrace;
     ///
@@ -1498,8 +1488,9 @@ pub fn pretty(mut self, pretty: bool) -> Self {
     /// }
     ///
     /// impl Error for SuperErrorSideKick {
-    ///     fn backtrace(&self) -> Option<&Backtrace> {
-    ///         Some(&self.backtrace)
+    ///     fn provide<'a>(&'a self, req: &mut Demand<'a>) {
+    ///         req
+    ///             .provide_ref::<Backtrace>(&self.backtrace);
     ///     }
     /// }
     ///
@@ -1552,11 +1543,11 @@ impl<E> Report<E>
     fn backtrace(&self) -> Option<&Backtrace> {
         // have to grab the backtrace on the first error directly since that error may not be
         // 'static
-        let backtrace = self.error.backtrace();
+        let backtrace = (&self.error as &dyn Error).request_ref();
         let backtrace = backtrace.or_else(|| {
             self.error
                 .source()
-                .map(|source| source.chain().find_map(|source| source.backtrace()))
+                .map(|source| source.chain().find_map(|source| source.request_ref()))
                 .flatten()
         });
         backtrace
@@ -1618,11 +1609,11 @@ impl Report<Box<dyn Error>> {
     fn backtrace(&self) -> Option<&Backtrace> {
         // have to grab the backtrace on the first error directly since that error may not be
         // 'static
-        let backtrace = self.error.backtrace();
+        let backtrace = self.error.request_ref();
         let backtrace = backtrace.or_else(|| {
             self.error
                 .source()
-                .map(|source| source.chain().find_map(|source| source.backtrace()))
+                .map(|source| source.chain().find_map(|source| source.request_ref()))
                 .flatten()
         });
         backtrace
index a2a35d96ec918a5b91ead9e51053df3524fb24fa..ee999bd65c3c94cefc7035bca80961648456a98e 100644 (file)
@@ -1,5 +1,6 @@
 use super::Error;
 use crate::fmt;
+use core::any::Demand;
 
 #[derive(Debug, PartialEq)]
 struct A;
@@ -198,8 +199,8 @@ fn source(&self) -> Option<&(dyn Error + 'static)> {
         self.source.as_deref()
     }
 
-    fn backtrace(&self) -> Option<&Backtrace> {
-        self.backtrace.as_ref()
+    fn provide<'a>(&'a self, req: &mut Demand<'a>) {
+        self.backtrace.as_ref().map(|bt| req.provide_ref::<Backtrace>(bt));
     }
 }
 
index 6b0c0ad7c2166c0b108a70a79c4682a1c3b4af86..ebe0ccbdc0b2d4211b047bef1ba739d640c8f067 100644 (file)
 #![cfg_attr(bootstrap, feature(let_chains))]
 #![feature(let_else)]
 #![feature(linkage)]
+#![feature(link_cfg)]
 #![feature(min_specialization)]
 #![feature(must_not_suspend)]
 #![feature(needs_panic_runtime)]
index a2cbee4dcf07b7ad8d665fb31417479c8c77e952..772b29f3a11a3a868afde58c582d802935ff68ab 100644 (file)
@@ -77,6 +77,9 @@ pub struct OpenOptions {
     custom_flags: i32,
 }
 
+#[derive(Copy, Clone, Debug, Default)]
+pub struct FileTimes {}
+
 #[derive(Clone, PartialEq, Eq, Debug)]
 pub struct FilePermissions(c_short);
 
@@ -126,6 +129,11 @@ pub fn set_readonly(&mut self, readonly: bool) {
     }
 }
 
+impl FileTimes {
+    pub fn set_accessed(&mut self, _t: SystemTime) {}
+    pub fn set_modified(&mut self, _t: SystemTime) {}
+}
+
 impl FileType {
     pub fn is_dir(&self) -> bool {
         self.is(abi::S_IFDIR)
@@ -452,6 +460,10 @@ pub fn duplicate(&self) -> io::Result<File> {
     pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
         unsupported()
     }
+
+    pub fn set_times(&self, _times: FileTimes) -> io::Result<()> {
+        unsupported()
+    }
 }
 
 impl Drop for File {
index faeda5a854d9f3981a0f1bd85272db8d89c10057..1b98ef993b04a199a1252cbecd55a88a0dd8a053 100644 (file)
@@ -230,8 +230,8 @@ pub fn new_raw(fam: c_int, ty: c_int) -> io::Result<Socket> {
     pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> {
         self.set_nonblocking(true)?;
         let r = unsafe {
-            let (addrp, len) = addr.into_inner();
-            cvt(netc::connect(self.0.raw(), addrp, len))
+            let (addr, len) = addr.into_inner();
+            cvt(netc::connect(self.0.raw(), addr.as_ptr(), len))
         };
         self.set_nonblocking(false)?;
 
index 41405cbf65703a1e7712c0587a4b4c5b038df390..1f2f9d97bddbbb1e837b1b844ade995c853ca9c6 100644 (file)
@@ -544,9 +544,11 @@ impl Default for FileTimes {
     fn default() -> Self {
         // Redox doesn't appear to support `UTIME_OMIT`, so we stub it out here, and always return
         // an error in `set_times`.
-        #[cfg(target_os = "redox")]
+        // ESP-IDF does not support `futimens` at all and the behavior for that OS is therefore
+        // the same as for Redox.
+        #[cfg(any(target_os = "redox", target_os = "espidf"))]
         let omit = libc::timespec { tv_sec: 0, tv_nsec: 0 };
-        #[cfg(not(target_os = "redox"))]
+        #[cfg(not(any(target_os = "redox", target_os = "espidf")))]
         let omit = libc::timespec { tv_sec: 0, tv_nsec: libc::UTIME_OMIT as _ };
         Self([omit; 2])
     }
@@ -685,7 +687,11 @@ fn next(&mut self) -> Option<io::Result<DirEntry>> {
 impl Drop for Dir {
     fn drop(&mut self) {
         let r = unsafe { libc::closedir(self.0) };
-        debug_assert_eq!(r, 0);
+        assert!(
+            r == 0 || crate::io::Error::last_os_error().kind() == crate::io::ErrorKind::Interrupted,
+            "unexpected error during closedir: {:?}",
+            crate::io::Error::last_os_error()
+        );
     }
 }
 
@@ -1077,8 +1083,10 @@ pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> {
 
     pub fn set_times(&self, times: FileTimes) -> io::Result<()> {
         cfg_if::cfg_if! {
-            if #[cfg(target_os = "redox")] {
+            if #[cfg(any(target_os = "redox", target_os = "espidf"))] {
                 // Redox doesn't appear to support `UTIME_OMIT`.
+                // ESP-IDF does not support `futimens` at all and the behavior for that OS is therefore
+                // the same as for Redox.
                 drop(times);
                 Err(io::const_io_error!(
                     io::ErrorKind::Unsupported,
index abf27e7db78c7c0e30467e56289ede3c5f87e873..4741c0c6736e37f1a28c6a1b9468df1eceeabe84 100644 (file)
@@ -172,7 +172,7 @@ pub unsafe fn wait_timeout(&self, mutex: &Mutex, mut dur: Duration) -> bool {
         let mut sys_now = libc::timeval { tv_sec: 0, tv_usec: 0 };
         let stable_now = Instant::now();
         let r = libc::gettimeofday(&mut sys_now, ptr::null_mut());
-        debug_assert_eq!(r, 0);
+        assert_eq!(r, 0, "unexpected error: {:?}", crate::io::Error::last_os_error());
 
         let nsec = dur.subsec_nanos() as libc::c_long + (sys_now.tv_usec * 1000) as libc::c_long;
         let extra = (nsec / 1_000_000_000) as libc::time_t;
index 3d0d91460f706229f4aa8ea786e926e22f874af8..3a3750930998509fca767f8decf488a8f30797d5 100644 (file)
@@ -295,8 +295,10 @@ pub fn abort_internal() -> ! {
 
 cfg_if::cfg_if! {
     if #[cfg(target_os = "android")] {
-        #[link(name = "dl")]
-        #[link(name = "log")]
+        #[link(name = "dl", kind = "static", modifiers = "-bundle",
+            cfg(target_feature = "crt-static"))]
+        #[link(name = "dl", cfg(not(target_feature = "crt-static")))]
+        #[link(name = "log", cfg(not(target_feature = "crt-static")))]
         extern "C" {}
     } else if #[cfg(target_os = "freebsd")] {
         #[link(name = "execinfo")]
index bf49204881d1643ef95ce45ca4f990698a88344f..a6fe07873d7ee4263b9362d9a5dda75c35916582 100644 (file)
@@ -1,13 +1,13 @@
-use crate::mem;
-use crate::slice;
-
 pub fn hashmap_random_keys() -> (u64, u64) {
-    let mut v = (0, 0);
-    unsafe {
-        let view = slice::from_raw_parts_mut(&mut v as *mut _ as *mut u8, mem::size_of_val(&v));
-        imp::fill_bytes(view);
-    }
-    v
+    const KEY_LEN: usize = core::mem::size_of::<u64>();
+
+    let mut v = [0u8; KEY_LEN * 2];
+    imp::fill_bytes(&mut v);
+
+    let key1 = v[0..KEY_LEN].try_into().unwrap();
+    let key2 = v[KEY_LEN..].try_into().unwrap();
+
+    (u64::from_ne_bytes(key1), u64::from_ne_bytes(key2))
 }
 
 #[cfg(all(
index 36a3fa6023bfb1424771ba6a859d4bcd63e35986..7db3065dee0838c1e014b43bf9694d1dc7ecaad0 100644 (file)
@@ -116,11 +116,9 @@ pub fn yield_now() {
         debug_assert_eq!(ret, 0);
     }
 
-    #[cfg(any(target_os = "linux", target_os = "android"))]
+    #[cfg(target_os = "android")]
     pub fn set_name(name: &CStr) {
         const PR_SET_NAME: libc::c_int = 15;
-        // pthread wrapper only appeared in glibc 2.12, so we use syscall
-        // directly.
         unsafe {
             libc::prctl(
                 PR_SET_NAME,
@@ -132,6 +130,14 @@ pub fn set_name(name: &CStr) {
         }
     }
 
+    #[cfg(target_os = "linux")]
+    pub fn set_name(name: &CStr) {
+        unsafe {
+            // Available since glibc 2.12, musl 1.1.16, and uClibc 1.0.20.
+            libc::pthread_setname_np(libc::pthread_self(), name.as_ptr());
+        }
+    }
+
     #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd"))]
     pub fn set_name(name: &CStr) {
         unsafe {
index 42a1ff730e37997ca3b6c0362e513cdea51b9d0e..633f17c054bc670c59d6f17c4a51003ba2c92e3b 100644 (file)
@@ -200,6 +200,9 @@ impl<'a> Iterator for CommandArgs<'a> {
     fn next(&mut self) -> Option<&'a OsStr> {
         None
     }
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        (0, Some(0))
+    }
 }
 
 impl<'a> ExactSizeIterator for CommandArgs<'a> {}
index 55b5ad314daf023ab0b3ca11d835ec740c10a827..4159efe2a0523e2b8688a6796e189136261bd94c 100644 (file)
         #[path = "../unix/locks"]
         pub mod locks {
             #![allow(unsafe_op_in_unsafe_fn)]
-            mod futex;
+            mod futex_condvar;
+            mod futex_mutex;
             mod futex_rwlock;
-            pub(crate) use futex::{Mutex, MovableMutex, Condvar, MovableCondvar};
+            pub(crate) use futex_condvar::{Condvar, MovableCondvar};
+            pub(crate) use futex_mutex::{Mutex, MovableMutex};
             pub(crate) use futex_rwlock::{RwLock, MovableRwLock};
         }
         #[path = "atomics/futex.rs"]
index 478068c73ba88bb3c09cc611fa5b6a61d7f18dae..c5a30f8bac86d1687919e0e11a1ea28d1d10b1cd 100644 (file)
@@ -1250,19 +1250,21 @@ pub fn GetTempPath2W(nBufferLength: DWORD, lpBuffer: LPCWSTR) -> DWORD {
     }
 }
 
-compat_fn_optional! {
+compat_fn_with_fallback! {
     pub static SYNCH_API: &CStr = ansi_str!("api-ms-win-core-synch-l1-2-0");
-
-    // >= Windows 8 / Server 2012
-    // https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitonaddress
-    pub fn WaitOnAddress(
-        Address: LPVOID,
-        CompareAddress: LPVOID,
-        AddressSize: SIZE_T,
-        dwMilliseconds: DWORD
-    ) -> BOOL;
-    pub fn WakeByAddressSingle(Address: LPVOID) -> ();
+    #[allow(unused)]
+    fn WakeByAddressSingle(Address: LPVOID) -> () {
+        // This fallback is currently tightly coupled to its use in Parker::unpark.
+        //
+        // FIXME: If `WakeByAddressSingle` needs to be used anywhere other than
+        // Parker::unpark then this fallback will be wrong and will need to be decoupled.
+        crate::sys::windows::thread_parker::unpark_keyed_event(Address)
+    }
 }
+pub use crate::sys::compat::WaitOnAddress;
+// Change exported name of `WakeByAddressSingle` to make the strange fallback
+// behaviour clear.
+pub use WakeByAddressSingle::call as wake_by_address_single_or_unpark_keyed_event;
 
 compat_fn_with_fallback! {
     pub static NTDLL: &CStr = ansi_str!("ntdll");
index ccc90177a2034740f83e1ffd2bebc0a0f839c93e..473544c4d4f7b99c231209dba5a1765cdacc3fd6 100644 (file)
@@ -7,47 +7,17 @@
 //! `GetModuleHandle` and `GetProcAddress` to look up DLL entry points at
 //! runtime.
 //!
-//! This implementation uses a static initializer to look up the DLL entry
-//! points. The CRT (C runtime) executes static initializers before `main`
-//! is called (for binaries) and before `DllMain` is called (for DLLs).
-//! This is the ideal time to look up DLL imports, because we are guaranteed
-//! that no other threads will attempt to call these entry points. Thus,
-//! we can look up the imports and store them in `static mut` fields
-//! without any synchronization.
+//! This is implemented simply by storing a function pointer in an atomic.
+//! Loading and calling this function will have little or no overhead
+//! compared with calling any other dynamically imported function.
 //!
-//! This has an additional advantage: Because the DLL import lookup happens
-//! at module initialization, the cost of these lookups is deterministic,
-//! and is removed from the code paths that actually call the DLL imports.
-//! That is, there is no unpredictable "cache miss" that occurs when calling
-//! a DLL import. For applications that benefit from predictable delays,
-//! this is a benefit. This also eliminates the comparison-and-branch
-//! from the hot path.
-//!
-//! Currently, the standard library uses only a small number of dynamic
-//! DLL imports. If this number grows substantially, then the cost of
-//! performing all of the lookups at initialization time might become
-//! substantial.
-//!
-//! The mechanism of registering a static initializer with the CRT is
-//! documented in
-//! [CRT Initialization](https://docs.microsoft.com/en-us/cpp/c-runtime-library/crt-initialization?view=msvc-160).
-//! It works by contributing a global symbol to the `.CRT$XCU` section.
-//! The linker builds a table of all static initializer functions.
-//! The CRT startup code then iterates that table, calling each
-//! initializer function.
-//!
-//! # **WARNING!!*
-//! The environment that a static initializer function runs in is highly
-//! constrained. There are **many** restrictions on what static initializers
-//! can safely do. Static initializer functions **MUST NOT** do any of the
-//! following (this list is not comprehensive):
-//! * touch any other static field that is used by a different static
-//!   initializer, because the order that static initializers run in
-//!   is not defined.
-//! * call `LoadLibrary` or any other function that acquires the DLL
-//!   loader lock.
-//! * call any Rust function or CRT function that touches any static
-//!   (global) state.
+//! The stored function pointer starts out as an importer function which will
+//! swap itself with the real function when it's called for the first time. If
+//! the real function can't be imported then a fallback function is used in its
+//! place. While this is low cost for the happy path (where the function is
+//! already loaded) it does mean there's some overhead the first time the
+//! function is called. In the worst case, multiple threads may all end up
+//! importing the same function unnecessarily.
 
 use crate::ffi::{c_void, CStr};
 use crate::ptr::NonNull;
@@ -85,39 +55,6 @@ pub(crate) const fn const_cstr_from_bytes(bytes: &'static [u8]) -> &'static CStr
     unsafe { crate::ffi::CStr::from_bytes_with_nul_unchecked(bytes) }
 }
 
-#[used]
-#[link_section = ".CRT$XCU"]
-static INIT_TABLE_ENTRY: unsafe extern "C" fn() = init;
-
-/// This is where the magic preloading of symbols happens.
-///
-/// Note that any functions included here will be unconditionally included in
-/// the final binary, regardless of whether or not they're actually used.
-///
-/// Therefore, this is limited to `compat_fn_optional` functions which must be
-/// preloaded and any functions which may be more time sensitive, even for the first call.
-unsafe extern "C" fn init() {
-    // There is no locking here. This code is executed before main() is entered, and
-    // is guaranteed to be single-threaded.
-    //
-    // DO NOT do anything interesting or complicated in this function! DO NOT call
-    // any Rust functions or CRT functions if those functions touch any global state,
-    // because this function runs during global initialization. For example, DO NOT
-    // do any dynamic allocation, don't call LoadLibrary, etc.
-
-    if let Some(synch) = Module::new(c::SYNCH_API) {
-        // These are optional and so we must manually attempt to load them
-        // before they can be used.
-        c::WaitOnAddress::preload(synch);
-        c::WakeByAddressSingle::preload(synch);
-    }
-
-    if let Some(kernel32) = Module::new(c::KERNEL32) {
-        // Preloading this means getting a precise time will be as fast as possible.
-        c::GetSystemTimePreciseAsFileTime::preload(kernel32);
-    }
-}
-
 /// Represents a loaded module.
 ///
 /// Note that the modules std depends on must not be unloaded.
@@ -151,7 +88,7 @@ pub fn proc_address(self, name: &CStr) -> Option<NonNull<c_void>> {
 macro_rules! compat_fn_with_fallback {
     (pub static $module:ident: &CStr = $name:expr; $(
         $(#[$meta:meta])*
-        pub fn $symbol:ident($($argname:ident: $argtype:ty),*) -> $rettype:ty $fallback_body:block
+        $vis:vis fn $symbol:ident($($argname:ident: $argtype:ty),*) -> $rettype:ty $fallback_body:block
     )*) => (
         pub static $module: &CStr = $name;
     $(
@@ -196,11 +133,6 @@ fn load_from_module(module: Option<Module>) -> F {
                 $fallback_body
             }
 
-            #[allow(unused)]
-            pub(in crate::sys) fn preload(module: Module) {
-                load_from_module(Some(module));
-            }
-
             #[inline(always)]
             pub unsafe fn call($($argname: $argtype),*) -> $rettype {
                 let func: F = mem::transmute(PTR.load(Ordering::Relaxed));
@@ -208,66 +140,65 @@ pub unsafe fn call($($argname: $argtype),*) -> $rettype {
             }
         }
         $(#[$meta])*
-        pub use $symbol::call as $symbol;
+        $vis use $symbol::call as $symbol;
     )*)
 }
 
-/// A function that either exists or doesn't.
+/// Optionally load `WaitOnAddress`.
+/// Unlike the dynamic loading described above, this does not have a fallback.
 ///
-/// NOTE: Optional functions must be preloaded in the `init` function above, or they will always be None.
-macro_rules! compat_fn_optional {
-    (pub static $module:ident: &CStr = $name:expr; $(
-        $(#[$meta:meta])*
-        pub fn $symbol:ident($($argname:ident: $argtype:ty),*) -> $rettype:ty;
-    )*) => (
-        pub static $module: &CStr = $name;
-    $(
-        $(#[$meta])*
-        pub mod $symbol {
-            #[allow(unused_imports)]
-            use super::*;
-            use crate::mem;
-            use crate::sync::atomic::{AtomicPtr, Ordering};
-            use crate::sys::compat::Module;
-            use crate::ptr::{self, NonNull};
-
-            type F = unsafe extern "system" fn($($argtype),*) -> $rettype;
-
-            /// `PTR` will either be `null()` or set to the loaded function.
-            static PTR: AtomicPtr<c_void> = AtomicPtr::new(ptr::null_mut());
-
-            /// Only allow access to the function if it has loaded successfully.
-            #[inline(always)]
-            #[cfg(not(miri))]
-            pub fn option() -> Option<F> {
-                unsafe {
-                    NonNull::new(PTR.load(Ordering::Relaxed)).map(|f| mem::transmute(f))
-                }
-            }
-
-            // Miri does not understand the way we do preloading
-            // therefore load the function here instead.
-            #[cfg(miri)]
-            pub fn option() -> Option<F> {
-                let mut func = NonNull::new(PTR.load(Ordering::Relaxed));
-                if func.is_none() {
-                    unsafe { Module::new($module).map(preload) };
-                    func = NonNull::new(PTR.load(Ordering::Relaxed));
-                }
-                unsafe {
-                    func.map(|f| mem::transmute(f))
-                }
-            }
+/// This is rexported from sys::c. You should prefer to import
+/// from there in case this changes again in the future.
+pub mod WaitOnAddress {
+    use super::*;
+    use crate::mem;
+    use crate::ptr;
+    use crate::sync::atomic::{AtomicBool, AtomicPtr, Ordering};
+    use crate::sys::c;
+
+    static MODULE_NAME: &CStr = ansi_str!("api-ms-win-core-synch-l1-2-0");
+    static SYMBOL_NAME: &CStr = ansi_str!("WaitOnAddress");
+
+    // WaitOnAddress function signature.
+    type F = unsafe extern "system" fn(
+        Address: c::LPVOID,
+        CompareAddress: c::LPVOID,
+        AddressSize: c::SIZE_T,
+        dwMilliseconds: c::DWORD,
+    );
+
+    // A place to store the loaded function atomically.
+    static WAIT_ON_ADDRESS: AtomicPtr<c_void> = AtomicPtr::new(ptr::null_mut());
+
+    // We can skip trying to load again if we already tried.
+    static LOAD_MODULE: AtomicBool = AtomicBool::new(true);
+
+    #[inline(always)]
+    pub fn option() -> Option<F> {
+        let f = WAIT_ON_ADDRESS.load(Ordering::Acquire);
+        if !f.is_null() { Some(unsafe { mem::transmute(f) }) } else { try_load() }
+    }
 
-            #[allow(unused)]
-            pub(in crate::sys) fn preload(module: Module) {
-                unsafe {
-                    static SYMBOL_NAME: &CStr = ansi_str!(sym $symbol);
-                    if let Some(f) = module.proc_address(SYMBOL_NAME) {
-                        PTR.store(f.as_ptr(), Ordering::Relaxed);
-                    }
-                }
+    #[cold]
+    fn try_load() -> Option<F> {
+        if LOAD_MODULE.load(Ordering::Acquire) {
+            // load the module
+            let mut wait_on_address = None;
+            if let Some(func) = try_load_inner() {
+                WAIT_ON_ADDRESS.store(func.as_ptr(), Ordering::Release);
+                wait_on_address = Some(unsafe { mem::transmute(func) });
             }
+            // Don't try to load the module again even if loading failed.
+            LOAD_MODULE.store(false, Ordering::Release);
+            wait_on_address
+        } else {
+            None
         }
-    )*)
+    }
+
+    // In the future this could be a `try` block but until then I think it's a
+    // little bit cleaner as a separate function.
+    fn try_load_inner() -> Option<NonNull<c_void>> {
+        unsafe { Module::new(MODULE_NAME)?.proc_address(SYMBOL_NAME) }
+    }
 }
index 57248e3651ba2773806eddeb34e6b1abb939c9f2..f8fd93a7398e1b75c35d255e30e24447461b9cc4 100644 (file)
@@ -1,62 +1,9 @@
 use crate::io;
 use crate::mem;
-use crate::sync;
+use crate::ptr;
 use crate::sys::c;
 
-/// The kinds of HashMap RNG that may be available
-#[derive(Clone, Copy, Debug, PartialEq)]
-enum HashMapRng {
-    Preferred,
-    Fallback,
-}
-
 pub fn hashmap_random_keys() -> (u64, u64) {
-    match get_hashmap_rng() {
-        HashMapRng::Preferred => {
-            preferred_rng().expect("couldn't generate random bytes with preferred RNG")
-        }
-        HashMapRng::Fallback => {
-            fallback_rng().expect("couldn't generate random bytes with fallback RNG")
-        }
-    }
-}
-
-/// Returns the HashMap RNG that should be used
-///
-/// Panics if they are both broken
-fn get_hashmap_rng() -> HashMapRng {
-    // Assume that if the preferred RNG is broken the first time we use it, it likely means
-    // that: the DLL has failed to load, there is no point to calling it over-and-over again,
-    // and we should cache the result
-    static VALUE: sync::OnceLock<HashMapRng> = sync::OnceLock::new();
-    *VALUE.get_or_init(choose_hashmap_rng)
-}
-
-/// Test whether we should use the preferred or fallback RNG
-///
-/// If the preferred RNG is successful, we choose it. Otherwise, if the fallback RNG is successful,
-/// we choose that
-///
-/// Panics if both the preferred and the fallback RNG are both non-functional
-fn choose_hashmap_rng() -> HashMapRng {
-    let preferred_error = match preferred_rng() {
-        Ok(_) => return HashMapRng::Preferred,
-        Err(e) => e,
-    };
-
-    match fallback_rng() {
-        Ok(_) => return HashMapRng::Fallback,
-        Err(fallback_error) => panic!(
-            "preferred RNG broken: `{}`, fallback RNG broken: `{}`",
-            preferred_error, fallback_error
-        ),
-    }
-}
-
-/// Generate random numbers using the preferred RNG function (BCryptGenRandom)
-fn preferred_rng() -> Result<(u64, u64), io::Error> {
-    use crate::ptr;
-
     let mut v = (0, 0);
     let ret = unsafe {
         c::BCryptGenRandom(
@@ -66,22 +13,23 @@ fn preferred_rng() -> Result<(u64, u64), io::Error> {
             c::BCRYPT_USE_SYSTEM_PREFERRED_RNG,
         )
     };
-
-    if ret == 0 { Ok(v) } else { Err(io::Error::last_os_error()) }
+    if ret != 0 { fallback_rng() } else { v }
 }
 
 /// Generate random numbers using the fallback RNG function (RtlGenRandom)
 #[cfg(not(target_vendor = "uwp"))]
-fn fallback_rng() -> Result<(u64, u64), io::Error> {
+#[inline(never)]
+fn fallback_rng() -> (u64, u64) {
     let mut v = (0, 0);
     let ret =
         unsafe { c::RtlGenRandom(&mut v as *mut _ as *mut u8, mem::size_of_val(&v) as c::ULONG) };
 
-    if ret != 0 { Ok(v) } else { Err(io::Error::last_os_error()) }
+    if ret != 0 { v } else { panic!("fallback RNG broken: {}", io::Error::last_os_error()) }
 }
 
 /// We can't use RtlGenRandom with UWP, so there is no fallback
 #[cfg(target_vendor = "uwp")]
-fn fallback_rng() -> Result<(u64, u64), io::Error> {
-    Err(io::const_io_error!(io::ErrorKind::Unsupported, "RtlGenRandom() not supported on UWP"))
+#[inline(never)]
+fn fallback_rng() -> (u64, u64) {
+    panic!("fallback RNG broken: RtlGenRandom() not supported on UWP");
 }
index d876e0f6f3c03b5bf8a590d78c4461b1429585de..16863c9903ac7f76a5947fd2b386941c19575fcd 100644 (file)
@@ -197,21 +197,9 @@ pub fn unpark(self: Pin<&Self>) {
         // purpose, to make sure every unpark() has a release-acquire ordering
         // with park().
         if self.state.swap(NOTIFIED, Release) == PARKED {
-            if let Some(wake_by_address_single) = c::WakeByAddressSingle::option() {
-                unsafe {
-                    wake_by_address_single(self.ptr());
-                }
-            } else {
-                // If we run NtReleaseKeyedEvent before the waiting thread runs
-                // NtWaitForKeyedEvent, this (shortly) blocks until we can wake it up.
-                // If the waiting thread wakes up before we run NtReleaseKeyedEvent
-                // (e.g. due to a timeout), this blocks until we do wake up a thread.
-                // To prevent this thread from blocking indefinitely in that case,
-                // park_impl() will, after seeing the state set to NOTIFIED after
-                // waking up, call NtWaitForKeyedEvent again to unblock us.
-                unsafe {
-                    c::NtReleaseKeyedEvent(keyed_event_handle(), self.ptr(), 0, ptr::null_mut());
-                }
+            unsafe {
+                // This calls either WakeByAddressSingle or unpark_keyed_event (see below).
+                c::wake_by_address_single_or_unpark_keyed_event(self.ptr());
             }
         }
     }
@@ -221,6 +209,19 @@ fn ptr(&self) -> c::LPVOID {
     }
 }
 
+// This function signature makes it compatible with c::WakeByAddressSingle
+// so that it can be used as a fallback for that function.
+pub unsafe extern "C" fn unpark_keyed_event(address: c::LPVOID) {
+    // If we run NtReleaseKeyedEvent before the waiting thread runs
+    // NtWaitForKeyedEvent, this (shortly) blocks until we can wake it up.
+    // If the waiting thread wakes up before we run NtReleaseKeyedEvent
+    // (e.g. due to a timeout), this blocks until we do wake up a thread.
+    // To prevent this thread from blocking indefinitely in that case,
+    // park_impl() will, after seeing the state set to NOTIFIED after
+    // waking up, call NtWaitForKeyedEvent again to unblock us.
+    c::NtReleaseKeyedEvent(keyed_event_handle(), address, 0, ptr::null_mut());
+}
+
 fn keyed_event_handle() -> c::HANDLE {
     const INVALID: c::HANDLE = ptr::invalid_mut(!0);
     static HANDLE: AtomicPtr<libc::c_void> = AtomicPtr::new(INVALID);
index 44c8a50fd860a0a121df1ef5d00d2b8bbb7b45c2..479669647c12843c743b19ebabd9b6743e6919f2 100644 (file)
 use crate::str;
 use crate::sync::Arc;
 use crate::sys::thread as imp;
-use crate::sys_common::mutex;
 use crate::sys_common::thread;
 use crate::sys_common::thread_info;
 use crate::sys_common::thread_parker::Parker;
@@ -1033,24 +1032,48 @@ pub fn park_timeout(dur: Duration) {
 impl ThreadId {
     // Generate a new unique thread ID.
     fn new() -> ThreadId {
-        // It is UB to attempt to acquire this mutex reentrantly!
-        static GUARD: mutex::StaticMutex = mutex::StaticMutex::new();
-        static mut COUNTER: u64 = 1;
-
-        unsafe {
-            let guard = GUARD.lock();
-
-            // If we somehow use up all our bits, panic so that we're not
-            // covering up subtle bugs of IDs being reused.
-            if COUNTER == u64::MAX {
-                drop(guard); // in case the panic handler ends up calling `ThreadId::new()`, avoid reentrant lock acquire.
-                panic!("failed to generate unique thread ID: bitspace exhausted");
-            }
-
-            let id = COUNTER;
-            COUNTER += 1;
+        #[cold]
+        fn exhausted() -> ! {
+            panic!("failed to generate unique thread ID: bitspace exhausted")
+        }
 
-            ThreadId(NonZeroU64::new(id).unwrap())
+        cfg_if::cfg_if! {
+            if #[cfg(target_has_atomic = "64")] {
+                use crate::sync::atomic::{AtomicU64, Ordering::Relaxed};
+
+                static COUNTER: AtomicU64 = AtomicU64::new(0);
+
+                let mut last = COUNTER.load(Relaxed);
+                loop {
+                    let Some(id) = last.checked_add(1) else {
+                        exhausted();
+                    };
+
+                    match COUNTER.compare_exchange_weak(last, id, Relaxed, Relaxed) {
+                        Ok(_) => return ThreadId(NonZeroU64::new(id).unwrap()),
+                        Err(id) => last = id,
+                    }
+                }
+            } else {
+                use crate::sys_common::mutex::StaticMutex;
+
+                // It is UB to attempt to acquire this mutex reentrantly!
+                static GUARD: StaticMutex = StaticMutex::new();
+                static mut COUNTER: u64 = 0;
+
+                unsafe {
+                    let guard = GUARD.lock();
+
+                    let Some(id) = COUNTER.checked_add(1) else {
+                        drop(guard); // in case the panic handler ends up calling `ThreadId::new()`, avoid reentrant lock acquire.
+                        exhausted();
+                    };
+
+                    COUNTER = id;
+                    drop(guard);
+                    ThreadId(NonZeroU64::new(id).unwrap())
+                }
+            }
         }
     }
 
index 694473f52c1a79970e86b1888b737e305db37041..355859019714b5e17f86e3717ffae6d05fa022b1 100644 (file)
@@ -80,6 +80,17 @@ pub(crate) fn from_env() -> Result<TermInfo, Error> {
 
     /// Creates a TermInfo for the named terminal.
     pub(crate) fn from_name(name: &str) -> Result<TermInfo, Error> {
+        if cfg!(miri) {
+            // Avoid all the work of parsing the terminfo (it's pretty slow under Miri), and just
+            // assume that the standard color codes work (like e.g. the 'colored' crate).
+            return Ok(TermInfo {
+                names: Default::default(),
+                bools: Default::default(),
+                numbers: Default::default(),
+                strings: Default::default(),
+            });
+        }
+
         get_dbpath_for_term(name)
             .ok_or_else(|| {
                 Error::IoError(io::Error::new(io::ErrorKind::NotFound, "terminfo file not found"))
@@ -119,6 +130,12 @@ pub(crate) struct TerminfoTerminal<T> {
 impl<T: Write + Send> Terminal for TerminfoTerminal<T> {
     fn fg(&mut self, color: color::Color) -> io::Result<bool> {
         let color = self.dim_if_necessary(color);
+        if cfg!(miri) && color < 8 {
+            // The Miri logic for this only works for the most basic 8 colors, which we just assume
+            // the terminal will support. (`num_colors` is always 0 in Miri, so higher colors will
+            // just fail. But libtest doesn't use any higher colors anyway.)
+            return write!(self.out, "\x1B[3{color}m").and(Ok(true));
+        }
         if self.num_colors > color {
             return self.apply_cap("setaf", &[Param::Number(color as i32)]);
         }
@@ -126,6 +143,9 @@ fn fg(&mut self, color: color::Color) -> io::Result<bool> {
     }
 
     fn reset(&mut self) -> io::Result<bool> {
+        if cfg!(miri) {
+            return write!(self.out, "\x1B[0m").and(Ok(true));
+        }
         // are there any terminals that have color/attrs and not sgr0?
         // Try falling back to sgr, then op
         let cmd = match ["sgr0", "sgr", "op"].iter().find_map(|cap| self.ti.strings.get(*cap)) {
index f88e6a924b5f04ef9bb756b5192f722c018f551f..126e41d1e2015ecc5c930904222c1f45598dba06 100644 (file)
@@ -13,13 +13,8 @@ fn main() {
         let has_unwind = build.is_flag_supported("-lunwind").expect("Unable to invoke compiler");
 
         if has_unwind {
-            println!("cargo:rustc-link-lib=unwind");
-        } else {
-            println!("cargo:rustc-link-lib=gcc");
+            println!("cargo:rustc-cfg=feature=\"system-llvm-libunwind\"");
         }
-
-        // Android's unwinding library depends on dl_iterate_phdr in `libdl`.
-        println!("cargo:rustc-link-lib=dl");
     } else if target.contains("freebsd") {
         println!("cargo:rustc-link-lib=gcc_s");
     } else if target.contains("netbsd") {
index 4a6ba6e10c334f429c706d49de81381cd27c4fe0..46fe50cb9453d9b045d95688e178146ff7b608ed 100644 (file)
     }
 }
 
+#[cfg(target_os = "android")]
+cfg_if::cfg_if! {
+    if #[cfg(feature = "llvm-libunwind")] {
+        compile_error!("`llvm-libunwind` is not supported for Android targets");
+    } else if #[cfg(feature = "system-llvm-libunwind")] {
+        #[link(name = "unwind", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))]
+        #[link(name = "unwind", cfg(not(target_feature = "crt-static")))]
+        extern "C" {}
+    } else {
+        #[link(name = "gcc", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))]
+        #[link(name = "gcc", cfg(not(target_feature = "crt-static")))]
+        extern "C" {}
+    }
+}
+// Android's unwinding library depends on dl_iterate_phdr in `libdl`.
+#[cfg(target_os = "android")]
+#[link(name = "dl", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))]
+#[link(name = "dl", cfg(not(target_feature = "crt-static")))]
+extern "C" {}
+
 // When building with crt-static, we get `gcc_eh` from the `libc` crate, since
 // glibc needs it, and needs it listed later on the linker command line. We
 // don't want to duplicate it here.
index c084e77d3a9943c120395d961e2272788c938e43..280eba75f0c19166407927afcc17229edf38662b 100644 (file)
@@ -547,7 +547,6 @@ fn test_with_no_doc_stage0() {
         config.stage = 0;
         config.cmd = Subcommand::Test {
             paths: vec!["library/std".into()],
-            skip: vec![],
             test_args: vec![],
             rustc_args: vec![],
             fail_fast: true,
@@ -618,7 +617,6 @@ fn test_docs() {
         let mut config = configure(&["A"], &["A"]);
         config.cmd = Subcommand::Test {
             paths: vec![],
-            skip: vec![],
             test_args: vec![],
             rustc_args: vec![],
             fail_fast: true,
index 394bd8b4e282564b8dcfac19b99e50884d1aa3d3..4e1e8ef9dead812b380578eef085c175f458fc5c 100644 (file)
@@ -140,7 +140,13 @@ fn run(self, builder: &Builder<'_>) {
             cargo_subcommand(builder.kind),
         );
 
-        cargo.arg("--all-targets");
+        // If we're not in stage 0, tests and examples will fail to compile
+        // from `core` definitions being loaded from two different `libcore`
+        // .rmeta and .rlib files.
+        if compiler.stage == 0 {
+            cargo.arg("--all-targets");
+        }
+
         std_cargo(builder, target, compiler.stage, &mut cargo);
 
         // Explicitly pass -p for all dependencies krates -- this will force cargo
index 80b3bcce860163d23eea28a976de06ac3647385c..39d9ce1621ba2a751ae1007632f75a0d0012fa4b 100644 (file)
@@ -115,7 +115,6 @@ pub enum Subcommand {
         compare_mode: Option<String>,
         pass: Option<String>,
         run: Option<String>,
-        skip: Vec<String>,
         test_args: Vec<String>,
         rustc_args: Vec<String>,
         fail_fast: bool,
@@ -568,7 +567,6 @@ pub fn parse(args: &[String]) -> Flags {
                 compare_mode: matches.opt_str("compare-mode"),
                 pass: matches.opt_str("pass"),
                 run: matches.opt_str("run"),
-                skip: matches.opt_strs("skip"),
                 test_args: matches.opt_strs("test-args"),
                 rustc_args: matches.opt_strs("rustc-args"),
                 fail_fast: !matches.opt_present("no-fail-fast"),
@@ -707,16 +705,6 @@ pub fn kind(&self) -> Kind {
     pub fn test_args(&self) -> Vec<&str> {
         let mut args = vec![];
 
-        match *self {
-            Subcommand::Test { ref skip, .. } => {
-                for s in skip {
-                    args.push("--skip");
-                    args.push(s.as_str());
-                }
-            }
-            _ => (),
-        };
-
         match *self {
             Subcommand::Test { ref test_args, .. } | Subcommand::Bench { ref test_args, .. } => {
                 args.extend(test_args.iter().flat_map(|s| s.split_whitespace()))
index cd421c249d8da660eb7f0fe5d9391b64a418182b..a242243aaafa91f38576b90f9466f54f1ee199d4 100644 (file)
@@ -624,20 +624,6 @@ fn dir_is_empty(dir: &Path) -> bool {
     /// If any submodule has been initialized already, sync it unconditionally.
     /// This avoids contributors checking in a submodule change by accident.
     pub fn maybe_update_submodules(&self) {
-        // WARNING: keep this in sync with the submodules hard-coded in bootstrap.py
-        let mut bootstrap_submodules: Vec<&str> = vec![
-            "src/tools/rust-installer",
-            "src/tools/cargo",
-            "src/tools/rls",
-            "src/tools/miri",
-            "library/backtrace",
-            "library/stdarch",
-        ];
-        // As in bootstrap.py, we include `rust-analyzer` if `build.vendor` was set in
-        // `config.toml`.
-        if self.config.vendor {
-            bootstrap_submodules.push("src/tools/rust-analyzer");
-        }
         // Avoid running git when there isn't a git checkout.
         if !self.config.submodules(&self.rust_info) {
             return;
@@ -653,10 +639,8 @@ pub fn maybe_update_submodules(&self) {
             // Look for `submodule.$name.path = $path`
             // Sample output: `submodule.src/rust-installer.path src/tools/rust-installer`
             let submodule = Path::new(line.splitn(2, ' ').nth(1).unwrap());
-            // avoid updating submodules twice
-            if !bootstrap_submodules.iter().any(|&p| Path::new(p) == submodule)
-                && channel::GitInfo::new(false, submodule).is_git()
-            {
+            // Don't update the submodule unless it's already been cloned.
+            if channel::GitInfo::new(false, submodule).is_git() {
                 self.update_submodule(submodule);
             }
         }
@@ -1647,14 +1631,12 @@ fn chmod(_path: &Path, _perms: u32) {}
 /// If code is not 0 (successful exit status), exit status is 101 (rust's default error code.)
 /// If the test is running and code is an error code, it will cause a panic.
 fn detail_exit(code: i32) -> ! {
-    // Successful exit
-    if code == 0 {
-        std::process::exit(0);
-    }
-    if cfg!(test) {
+    // if in test and code is an error code, panic with staus code provided
+    if cfg!(test) && code != 0 {
         panic!("status code: {}", code);
     } else {
-        std::panic::resume_unwind(Box::new(code));
+        //otherwise,exit with provided status code
+        std::process::exit(code);
     }
 }
 
index 5a1f2e70413781ddd529ffdb38ccb20cba236826..1e0f7e9acf4f2bcbc6eb6c16fe79a516115ad6c1 100644 (file)
@@ -66,16 +66,21 @@ TESTS_IN_2 := \
        src/test/ui \
        src/tools/linkchecker
 
+## MSVC native builders
+
+# these intentionally don't use `$(BOOTSTRAP)` so we can test the shebang on Windows
 ci-subset-1:
-       $(Q)$(BOOTSTRAP) test --stage 2 $(TESTS_IN_2:%=--exclude %)
+       $(Q)$(CFG_SRC_DIR)/x.py test --stage 2 $(TESTS_IN_2:%=--exclude %)
 ci-subset-2:
-       $(Q)$(BOOTSTRAP) test --stage 2 $(TESTS_IN_2)
+       $(Q)$(CFG_SRC_DIR)/x.ps1 test --stage 2 $(TESTS_IN_2)
+
+## MingW native builders
 
 TESTS_IN_MINGW_2 := \
        src/test/ui
 
 ci-mingw-subset-1:
-       $(Q)$(BOOTSTRAP) test --stage 2 $(TESTS_IN_MINGW_2:%=--exclude %)
+       $(Q)$(CFG_SRC_DIR)/x.sh test --stage 2 $(TESTS_IN_MINGW_2:%=--exclude %)
 ci-mingw-subset-2:
        $(Q)$(BOOTSTRAP) test --stage 2 $(TESTS_IN_MINGW_2)
 
index 3347246ea8f6feb2c1c37148a60db611d6a2da92..8b50d5dc52bc179ee08c33ef91dd76e37f556c0e 100644 (file)
@@ -325,6 +325,9 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
             cfg.define("LLVM_PROFDATA_FILE", &path);
         }
 
+        // Disable zstd to avoid a dependency on libzstd.so.
+        cfg.define("LLVM_ENABLE_ZSTD", "OFF");
+
         if target != "aarch64-apple-darwin" && !target.contains("windows") {
             cfg.define("LLVM_ENABLE_ZLIB", "ON");
         } else {
@@ -345,13 +348,6 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
             cfg.define("LLVM_ENABLE_ZLIB", "OFF");
         }
 
-        if builder.config.llvm_thin_lto {
-            cfg.define("LLVM_ENABLE_LTO", "Thin");
-            if !target.contains("apple") {
-                cfg.define("LLVM_ENABLE_LLD", "ON");
-            }
-        }
-
         // This setting makes the LLVM tools link to the dynamic LLVM library,
         // which saves both memory during parallel links and overall disk space
         // for the tools. We don't do this on every platform as it doesn't work
@@ -463,15 +459,8 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
             cfg.define("LLVM_VERSION_SUFFIX", suffix);
         }
 
-        if let Some(ref linker) = builder.config.llvm_use_linker {
-            cfg.define("LLVM_USE_LINKER", linker);
-        }
-
-        if builder.config.llvm_allow_old_toolchain {
-            cfg.define("LLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN", "YES");
-        }
-
         configure_cmake(builder, target, &mut cfg, true, ldflags);
+        configure_llvm(builder, target, &mut cfg);
 
         for (key, val) in &builder.config.llvm_build_config {
             cfg.define(key, val);
@@ -731,6 +720,25 @@ fn configure_cmake(
     }
 }
 
+fn configure_llvm(builder: &Builder<'_>, target: TargetSelection, cfg: &mut cmake::Config) {
+    // ThinLTO is only available when building with LLVM, enabling LLD is required.
+    // Apple's linker ld64 supports ThinLTO out of the box though, so don't use LLD on Darwin.
+    if builder.config.llvm_thin_lto {
+        cfg.define("LLVM_ENABLE_LTO", "Thin");
+        if !target.contains("apple") {
+            cfg.define("LLVM_ENABLE_LLD", "ON");
+        }
+    }
+
+    if let Some(ref linker) = builder.config.llvm_use_linker {
+        cfg.define("LLVM_USE_LINKER", linker);
+    }
+
+    if builder.config.llvm_allow_old_toolchain {
+        cfg.define("LLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN", "YES");
+    }
+}
+
 // Adapted from https://github.com/alexcrichton/cc-rs/blob/fba7feded71ee4f63cfe885673ead6d7b4f2f454/src/lib.rs#L2347-L2365
 fn get_var(var_base: &str, host: &str, target: &str) -> Option<OsString> {
     let kind = if host == target { "HOST" } else { "TARGET" };
@@ -794,6 +802,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
         }
 
         configure_cmake(builder, target, &mut cfg, true, ldflags);
+        configure_llvm(builder, target, &mut cfg);
 
         // This is an awful, awful hack. Discovered when we migrated to using
         // clang-cl to compile LLVM/LLD it turns out that LLD, when built out of
@@ -825,10 +834,6 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
             .define("LLVM_CONFIG_PATH", llvm_config_shim)
             .define("LLVM_INCLUDE_TESTS", "OFF");
 
-        if builder.config.llvm_allow_old_toolchain {
-            cfg.define("LLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN", "YES");
-        }
-
         // While we're using this horrible workaround to shim the execution of
         // llvm-config, let's just pile on more. I can't seem to figure out how
         // to build LLD as a standalone project and also cross-compile it at the
index 5c8034d53e3ad95a4c43b7f855dcb954e165de20..baad0c75295a575b03ee00c06e5b4e92e9aecce2 100644 (file)
@@ -289,8 +289,6 @@ fn run(self, builder: &Builder<'_>) {
         // Don't run cross-compile tests, we may not have cross-compiled libstd libs
         // available.
         cargo.env("CFG_DISABLE_CROSS_TESTS", "1");
-        // Disable a test that has issues with mingw.
-        cargo.env("CARGO_TEST_DISABLE_GIT_CLI", "1");
         // Forcibly disable tests using nightly features since any changes to
         // those features won't be able to land.
         cargo.env("CARGO_TEST_DISABLE_NIGHTLY", "1");
@@ -630,6 +628,10 @@ fn run(self, builder: &Builder<'_>) {
             cargo.env("MIRI_HOST_SYSROOT", sysroot);
             cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler));
             cargo.env("MIRI", miri);
+            // propagate --bless
+            if builder.config.cmd.bless() {
+                cargo.env("MIRI_BLESS", "Gesundheit");
+            }
 
             cargo.arg("--").args(builder.config.cmd.test_args());
 
@@ -922,6 +924,11 @@ fn compare_browser_ui_test_version(installed_version: &str, src: &Path) {
                      one used in the CI (`{}`)",
                     installed_version, v
                 );
+                eprintln!(
+                    "You can install this version using `npm update browser-ui-test` or by using \
+                     `npm install browser-ui-test@{}`",
+                    v,
+                );
             }
         }
         Err(e) => eprintln!("Couldn't find the CI browser-ui-test version: {:?}", e),
@@ -1488,6 +1495,11 @@ fn run(self, builder: &Builder<'_>) {
             cmd.arg("--run-clang-based-tests-with").arg(clang_exe);
         }
 
+        for exclude in &builder.config.exclude {
+            cmd.arg("--skip");
+            cmd.arg(&exclude.path);
+        }
+
         // Get paths from cmd args
         let paths = match &builder.config.cmd {
             Subcommand::Test { ref paths, .. } => &paths[..],
index 839a6d27199f1364bc7a2e433f3077537b2ce171..06fa5039fdf9243cc4b5b62d7cdcd8381311699d 100644 (file)
@@ -158,34 +158,38 @@ fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
                       a transitive dependency has different features activated \
                       than in a previous build:\n"
             );
-            eprintln!(
-                "the following dependencies are duplicated although they \
-                      have the same features enabled:"
-            );
             let (same, different): (Vec<_>, Vec<_>) =
                 duplicates.into_iter().partition(|(_, cur, prev)| cur.2 == prev.2);
-            for (id, cur, prev) in same {
-                eprintln!("  {}", id);
-                // same features
-                eprintln!("    `{}` ({:?})\n    `{}` ({:?})", cur.0, cur.1, prev.0, prev.1);
-            }
-            eprintln!("the following dependencies have different features:");
-            for (id, cur, prev) in different {
-                eprintln!("  {}", id);
-                let cur_features: HashSet<_> = cur.2.into_iter().collect();
-                let prev_features: HashSet<_> = prev.2.into_iter().collect();
-                eprintln!(
-                    "    `{}` additionally enabled features {:?} at {:?}",
-                    cur.0,
-                    &cur_features - &prev_features,
-                    cur.1
-                );
+            if !same.is_empty() {
                 eprintln!(
-                    "    `{}` additionally enabled features {:?} at {:?}",
-                    prev.0,
-                    &prev_features - &cur_features,
-                    prev.1
+                    "the following dependencies are duplicated although they \
+                      have the same features enabled:"
                 );
+                for (id, cur, prev) in same {
+                    eprintln!("  {}", id);
+                    // same features
+                    eprintln!("    `{}` ({:?})\n    `{}` ({:?})", cur.0, cur.1, prev.0, prev.1);
+                }
+            }
+            if !different.is_empty() {
+                eprintln!("the following dependencies have different features:");
+                for (id, cur, prev) in different {
+                    eprintln!("  {}", id);
+                    let cur_features: HashSet<_> = cur.2.into_iter().collect();
+                    let prev_features: HashSet<_> = prev.2.into_iter().collect();
+                    eprintln!(
+                        "    `{}` additionally enabled features {:?} at {:?}",
+                        cur.0,
+                        &cur_features - &prev_features,
+                        cur.1
+                    );
+                    eprintln!(
+                        "    `{}` additionally enabled features {:?} at {:?}",
+                        prev.0,
+                        &prev_features - &cur_features,
+                        prev.1
+                    );
+                }
             }
             eprintln!();
             eprintln!(
index 4b90b890eb2e2b1f7659638b59f156de3fb2e3df..b71a348abd9e47c18001b13d250b96e72fc4adba 100644 (file)
@@ -219,12 +219,15 @@ For targets: `armv7-unknown-linux-gnueabihf`
 For targets: `aarch64-unknown-linux-gnu`
 
 - Path and misc options > Prefix directory = /x-tools/${CT\_TARGET}
+- Path and misc options > Use a mirror = ENABLE
+- Path and misc options > Base URL = https://ci-mirrors.rust-lang.org/rustc
 - Target options > Target Architecture = arm
 - Target options > Bitness = 64-bit
 - Operating System > Target OS = linux
-- Operating System > Linux kernel version = 4.2.6
+- Operating System > Linux kernel version = 4.1.49
+- Binary utilities > Version of binutils = 2.32
 - C-library > glibc version = 2.17 -- aarch64 support was introduced in this version
-- C compiler > gcc version = 5.2.0
+- C compiler > gcc version = 8.3.0
 - C compiler > C++ = ENABLE -- to cross compile LLVM
 
 ### `powerpc-linux-gnu.config`
@@ -232,14 +235,15 @@ For targets: `aarch64-unknown-linux-gnu`
 For targets: `powerpc-unknown-linux-gnu`
 
 - Path and misc options > Prefix directory = /x-tools/${CT\_TARGET}
-- Path and misc options > Patches origin = Bundled, then local
-- Path and misc options > Local patch directory = /tmp/patches
+- Path and misc options > Use a mirror = ENABLE
+- Path and misc options > Base URL = https://ci-mirrors.rust-lang.org/rustc
 - Target options > Target Architecture = powerpc
 - Target options > Emit assembly for CPU = powerpc -- pure 32-bit PowerPC
 - Operating System > Target OS = linux
-- Operating System > Linux kernel version = 2.6.32.68 -- ~RHEL6 kernel
-- C-library > glibc version = 2.11.1 -- ~SLE11-SP4 glibc
-- C compiler > gcc version = 5.2.0
+- Operating System > Linux kernel version = 3.2.101
+- Binary utilities > Version of binutils = 2.30
+- C-library > glibc version = 2.17 -- ~RHEL7 glibc
+- C compiler > gcc version = 8.3.0
 - C compiler > C++ = ENABLE -- to cross compile LLVM
 
 ### `powerpc64-linux-gnu.config`
@@ -247,16 +251,17 @@ For targets: `powerpc-unknown-linux-gnu`
 For targets: `powerpc64-unknown-linux-gnu`
 
 - Path and misc options > Prefix directory = /x-tools/${CT\_TARGET}
-- Path and misc options > Patches origin = Bundled, then local
-- Path and misc options > Local patch directory = /tmp/patches
+- Path and misc options > Use a mirror = ENABLE
+- Path and misc options > Base URL = https://ci-mirrors.rust-lang.org/rustc
 - Target options > Target Architecture = powerpc
 - Target options > Bitness = 64-bit
 - Target options > Emit assembly for CPU = power4 -- (+)
 - Target options > Tune for CPU = power6 -- (+)
 - Operating System > Target OS = linux
-- Operating System > Linux kernel version = 2.6.32.68 -- ~RHEL6 kernel
-- C-library > glibc version = 2.11.1 -- ~SLE11-SP4 glibc
-- C compiler > gcc version = 5.2.0
+- Operating System > Linux kernel version = 3.2.101
+- Binary utilities > Version of binutils = 2.32
+- C-library > glibc version = 2.17 -- ~RHEL7 glibc
+- C compiler > gcc version = 8.3.0
 - C compiler > C++ = ENABLE -- to cross compile LLVM
 
 (+) These CPU options match the configuration of the toolchains in RHEL6.
@@ -266,13 +271,14 @@ For targets: `powerpc64-unknown-linux-gnu`
 For targets: `s390x-unknown-linux-gnu`
 
 - Path and misc options > Prefix directory = /x-tools/${CT\_TARGET}
-- Path and misc options > Patches origin = Bundled, then local
-- Path and misc options > Local patch directory = /tmp/patches
+- Path and misc options > Use a mirror = ENABLE
+- Path and misc options > Base URL = https://ci-mirrors.rust-lang.org/rustc
 - Target options > Target Architecture = s390
 - Target options > Bitness = 64-bit
 - Operating System > Target OS = linux
-- Operating System > Linux kernel version = 2.6.32.71 -- ~RHEL6 kernel
-- C-library > glibc version = 2.12.1 -- ~RHEL6 glibc
+- Operating System > Linux kernel version = 3.2.101
+- Binary utilities > Version of binutils = 2.32
+- C-library > glibc version = 2.17 -- ~RHEL7 glibc
 - C compiler > gcc version = 8.3.0
 - C compiler > gcc extra config = --with-arch=z10 -- LLVM's minimum support
 - C compiler > C++ = ENABLE -- to cross compile LLVM
index 43cdbbe92e3acfbd787d2092f7d7679d20891733..a2335687ab33568266850d9437942656b0ae0f3d 100644 (file)
@@ -29,7 +29,8 @@ ENV PATH=$PATH:/android/sdk/platform-tools
 
 ENV TARGETS=arm-linux-androideabi
 
-ENV RUST_CONFIGURE_ARGS --arm-linux-androideabi-ndk=/android/ndk/arm-14
+ENV RUST_CONFIGURE_ARGS --arm-linux-androideabi-ndk=/android/ndk/arm-14 \
+    --set llvm.allow-old-toolchain
 
 ENV SCRIPT python3 ../x.py --stage 2 test --host='' --target $TARGETS
 
index ab588ccc24999cb80bcd52c1a4da4db203770a4b..23fa23f0f2d06cf4d338e97f4272faacb2559773 100644 (file)
@@ -1,28 +1,10 @@
 FROM ubuntu:20.04
-RUN apt-get update && \
-    apt-get install -y --no-install-recommends \
-        curl \
-        ca-certificates
-WORKDIR /tmp
-RUN curl -f https://curl.se/ca/cacert.pem -o cacert.pem
-
-FROM ubuntu:16.04
-
-# The ca-certificates in ubuntu-16 is too old, so update the certificates
-# with something more recent.
-COPY --from=0 /tmp/cacert.pem /tmp/cacert.pem
-ENV CURL_CA_BUNDLE /tmp/cacert.pem
 
 COPY scripts/cross-apt-packages.sh /scripts/
 RUN sh /scripts/cross-apt-packages.sh
 
-# Ubuntu 16.04 (this container) ships with make 4, but something in the
-# toolchains we build below chokes on that, so go back to make 3
-COPY scripts/make3.sh /scripts/
-RUN sh /scripts/make3.sh
-
-COPY scripts/crosstool-ng.sh /scripts/
-RUN sh /scripts/crosstool-ng.sh
+COPY scripts/crosstool-ng-1.24.sh /scripts/
+RUN sh /scripts/crosstool-ng-1.24.sh
 
 COPY scripts/rustbuild-setup.sh /scripts/
 RUN sh /scripts/rustbuild-setup.sh
@@ -37,14 +19,11 @@ USER root
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
-
-ENV PATH=$PATH:/x-tools/aarch64-unknown-linux-gnueabi/bin
+ENV PATH=$PATH:/x-tools/aarch64-unknown-linux-gnu/bin
 
-ENV CC_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnueabi-gcc \
-    AR_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnueabi-ar \
-    CXX_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnueabi-g++
+ENV CC_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnu-gcc \
+    AR_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnu-ar \
+    CXX_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnu-g++
 
 ENV HOSTS=aarch64-unknown-linux-gnu
 
index 416fa50374fe412c89b9b3c5cdff7f890c332c58..4561e2a1ec39240d3a2bcd7d623f8ea85e048ceb 100644 (file)
@@ -1,9 +1,30 @@
 #
 # Automatically generated file; DO NOT EDIT.
-# Crosstool-NG Configuration
-#
-CT_CONFIGURE_has_make381=y
-CT_CONFIGURE_has_xz=y
+# crosstool-NG  Configuration
+#
+CT_CONFIGURE_has_static_link=y
+CT_CONFIGURE_has_cxx11=y
+CT_CONFIGURE_has_wget=y
+CT_CONFIGURE_has_curl=y
+CT_CONFIGURE_has_make_3_81_or_newer=y
+CT_CONFIGURE_has_make_4_0_or_newer=y
+CT_CONFIGURE_has_libtool_2_4_or_newer=y
+CT_CONFIGURE_has_libtoolize_2_4_or_newer=y
+CT_CONFIGURE_has_autoconf_2_65_or_newer=y
+CT_CONFIGURE_has_autoreconf_2_65_or_newer=y
+CT_CONFIGURE_has_automake_1_15_or_newer=y
+CT_CONFIGURE_has_gnu_m4_1_4_12_or_newer=y
+CT_CONFIGURE_has_python_3_4_or_newer=y
+CT_CONFIGURE_has_bison_2_7_or_newer=y
+CT_CONFIGURE_has_python=y
+CT_CONFIGURE_has_git=y
+CT_CONFIGURE_has_md5sum=y
+CT_CONFIGURE_has_sha1sum=y
+CT_CONFIGURE_has_sha256sum=y
+CT_CONFIGURE_has_sha512sum=y
+CT_CONFIGURE_has_install_with_strip_program=y
+CT_CONFIG_VERSION_CURRENT="3"
+CT_CONFIG_VERSION="3"
 CT_MODULES=y
 
 #
@@ -20,39 +41,49 @@ CT_MODULES=y
 #
 # Paths
 #
-CT_LOCAL_TARBALLS_DIR=""
+CT_LOCAL_TARBALLS_DIR="${HOME}/src"
+CT_SAVE_TARBALLS=y
+# CT_TARBALLS_BUILDROOT_LAYOUT is not set
 CT_WORK_DIR="${CT_TOP_DIR}/.build"
+CT_BUILD_TOP_DIR="${CT_WORK_DIR:-${CT_TOP_DIR}/.build}/${CT_HOST:+HOST-${CT_HOST}/}${CT_TARGET}"
 CT_PREFIX_DIR="/x-tools/${CT_TARGET}"
-CT_INSTALL_DIR="${CT_PREFIX_DIR}"
 CT_RM_RF_PREFIX_DIR=y
 CT_REMOVE_DOCS=y
-CT_INSTALL_DIR_RO=y
+CT_INSTALL_LICENSES=y
+CT_PREFIX_DIR_RO=y
 CT_STRIP_HOST_TOOLCHAIN_EXECUTABLES=y
 # CT_STRIP_TARGET_TOOLCHAIN_EXECUTABLES is not set
 
 #
 # Downloading
 #
+CT_DOWNLOAD_AGENT_WGET=y
+# CT_DOWNLOAD_AGENT_CURL is not set
+# CT_DOWNLOAD_AGENT_NONE is not set
 # CT_FORBID_DOWNLOAD is not set
 # CT_FORCE_DOWNLOAD is not set
 CT_CONNECT_TIMEOUT=10
+CT_DOWNLOAD_WGET_OPTIONS="--passive-ftp --tries=3 -nc --progress=dot:binary"
 # CT_ONLY_DOWNLOAD is not set
 CT_USE_MIRROR=y
+# CT_FORCE_MIRROR is not set
 CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc"
+CT_VERIFY_DOWNLOAD_DIGEST=y
+CT_VERIFY_DOWNLOAD_DIGEST_SHA512=y
+# CT_VERIFY_DOWNLOAD_DIGEST_SHA256 is not set
+# CT_VERIFY_DOWNLOAD_DIGEST_SHA1 is not set
+# CT_VERIFY_DOWNLOAD_DIGEST_MD5 is not set
+CT_VERIFY_DOWNLOAD_DIGEST_ALG="sha512"
+# CT_VERIFY_DOWNLOAD_SIGNATURE is not set
 
 #
 # Extracting
 #
 # CT_FORCE_EXTRACT is not set
-CT_OVERIDE_CONFIG_GUESS_SUB=y
+CT_OVERRIDE_CONFIG_GUESS_SUB=y
 # CT_ONLY_EXTRACT is not set
 CT_PATCH_BUNDLED=y
-# CT_PATCH_LOCAL is not set
 # CT_PATCH_BUNDLED_LOCAL is not set
-# CT_PATCH_LOCAL_BUNDLED is not set
-# CT_PATCH_BUNDLED_FALLBACK_LOCAL is not set
-# CT_PATCH_LOCAL_FALLBACK_BUNDLED is not set
-# CT_PATCH_NONE is not set
 CT_PATCH_ORDER="bundled"
 
 #
@@ -76,11 +107,11 @@ CT_CONFIG_SHELL="${bash}"
 #
 # CT_LOG_ERROR is not set
 # CT_LOG_WARN is not set
-CT_LOG_INFO=y
-# CT_LOG_EXTRA is not set
+# CT_LOG_INFO is not set
+CT_LOG_EXTRA=y
 # CT_LOG_ALL is not set
 # CT_LOG_DEBUG is not set
-CT_LOG_LEVEL_MAX="INFO"
+CT_LOG_LEVEL_MAX="EXTRA"
 # CT_LOG_SEE_TOOLS_WARN is not set
 CT_LOG_PROGRESS_BAR=y
 CT_LOG_TO_FILE=y
@@ -89,76 +120,76 @@ CT_LOG_FILE_COMPRESS=y
 #
 # Target options
 #
+# CT_ARCH_ALPHA is not set
+# CT_ARCH_ARC is not set
+CT_ARCH_ARM=y
+# CT_ARCH_AVR is not set
+# CT_ARCH_M68K is not set
+# CT_ARCH_MIPS is not set
+# CT_ARCH_NIOS2 is not set
+# CT_ARCH_POWERPC is not set
+# CT_ARCH_S390 is not set
+# CT_ARCH_SH is not set
+# CT_ARCH_SPARC is not set
+# CT_ARCH_X86 is not set
+# CT_ARCH_XTENSA is not set
 CT_ARCH="arm"
-CT_ARCH_SUPPORTS_BOTH_MMU=y
-CT_ARCH_SUPPORTS_BOTH_ENDIAN=y
-CT_ARCH_SUPPORTS_32=y
-CT_ARCH_SUPPORTS_64=y
-CT_ARCH_SUPPORTS_WITH_ARCH=y
-CT_ARCH_SUPPORTS_WITH_CPU=y
-CT_ARCH_SUPPORTS_WITH_TUNE=y
-CT_ARCH_DEFAULT_HAS_MMU=y
-CT_ARCH_DEFAULT_LE=y
-CT_ARCH_DEFAULT_32=y
-CT_ARCH_ARCH=""
+CT_ARCH_CHOICE_KSYM="ARM"
+# CT_ARCH_ALPHA_EV4 is not set
+# CT_ARCH_ALPHA_EV45 is not set
+# CT_ARCH_ALPHA_EV5 is not set
+# CT_ARCH_ALPHA_EV56 is not set
+# CT_ARCH_ALPHA_EV6 is not set
+# CT_ARCH_ALPHA_EV67 is not set
 CT_ARCH_CPU=""
 CT_ARCH_TUNE=""
-# CT_ARCH_BE is not set
-CT_ARCH_LE=y
-# CT_ARCH_32 is not set
-CT_ARCH_64=y
-CT_ARCH_BITNESS=64
-CT_TARGET_CFLAGS=""
-CT_TARGET_LDFLAGS=""
-# CT_ARCH_alpha is not set
-CT_ARCH_arm=y
-# CT_ARCH_avr is not set
-# CT_ARCH_m68k is not set
-# CT_ARCH_mips is not set
-# CT_ARCH_nios2 is not set
-# CT_ARCH_powerpc is not set
-# CT_ARCH_s390 is not set
-# CT_ARCH_sh is not set
-# CT_ARCH_sparc is not set
-# CT_ARCH_x86 is not set
-# CT_ARCH_xtensa is not set
-CT_ARCH_alpha_AVAILABLE=y
-CT_ARCH_arm_AVAILABLE=y
-CT_ARCH_avr_AVAILABLE=y
-CT_ARCH_m68k_AVAILABLE=y
-CT_ARCH_microblaze_AVAILABLE=y
-CT_ARCH_mips_AVAILABLE=y
-CT_ARCH_nios2_AVAILABLE=y
-CT_ARCH_powerpc_AVAILABLE=y
-CT_ARCH_s390_AVAILABLE=y
-CT_ARCH_sh_AVAILABLE=y
-CT_ARCH_sparc_AVAILABLE=y
-CT_ARCH_x86_AVAILABLE=y
-CT_ARCH_xtensa_AVAILABLE=y
+CT_ARCH_ARM_SHOW=y
+
+#
+# Options for arm
+#
+CT_ARCH_ARM_PKG_KSYM=""
+# CT_ARCH_ARM_MODE_ARM is not set
+# CT_ARCH_ARM_MODE_THUMB is not set
+CT_ALL_ARCH_CHOICES="ALPHA ARC ARM AVR M68K MICROBLAZE MIPS MOXIE MSP430 NIOS2 POWERPC RISCV S390 SH SPARC X86 XTENSA"
 CT_ARCH_SUFFIX=""
+# CT_OMIT_TARGET_VENDOR is not set
 
 #
 # Generic target options
 #
 # CT_MULTILIB is not set
+CT_DEMULTILIB=y
+CT_ARCH_SUPPORTS_BOTH_MMU=y
+CT_ARCH_DEFAULT_HAS_MMU=y
 CT_ARCH_USE_MMU=y
+CT_ARCH_SUPPORTS_FLAT_FORMAT=y
+CT_ARCH_SUPPORTS_EITHER_ENDIAN=y
+CT_ARCH_DEFAULT_LE=y
+# CT_ARCH_BE is not set
+CT_ARCH_LE=y
 CT_ARCH_ENDIAN="little"
+CT_ARCH_SUPPORTS_32=y
+CT_ARCH_SUPPORTS_64=y
+CT_ARCH_DEFAULT_32=y
+CT_ARCH_BITNESS=64
+# CT_ARCH_32 is not set
+CT_ARCH_64=y
 
 #
 # Target optimisations
 #
+CT_ARCH_SUPPORTS_WITH_ARCH=y
+CT_ARCH_SUPPORTS_WITH_CPU=y
+CT_ARCH_SUPPORTS_WITH_TUNE=y
 CT_ARCH_EXCLUSIVE_WITH_CPU=y
-CT_ARCH_FLOAT=""
-
-#
-# arm other options
-#
-CT_ARCH_ARM_MODE="arm"
-CT_ARCH_ARM_MODE_ARM=y
-# CT_ARCH_ARM_MODE_THUMB is not set
-# CT_ARCH_ARM_INTERWORKING is not set
-CT_ARCH_ARM_EABI_FORCE=y
-CT_ARCH_ARM_EABI=y
+CT_ARCH_ARCH=""
+# CT_ARCH_FLOAT_AUTO is not set
+# CT_ARCH_FLOAT_HW is not set
+# CT_ARCH_FLOAT_SOFTFP is not set
+# CT_ARCH_FLOAT_SW is not set
+CT_TARGET_CFLAGS=""
+CT_TARGET_LDFLAGS=""
 
 #
 # Toolchain options
@@ -172,7 +203,9 @@ CT_USE_SYSROOT=y
 CT_SYSROOT_NAME="sysroot"
 CT_SYSROOT_DIR_PREFIX=""
 CT_WANTS_STATIC_LINK=y
+CT_WANTS_STATIC_LINK_CXX=y
 # CT_STATIC_TOOLCHAIN is not set
+CT_SHOW_CT_VERSION=y
 CT_TOOLCHAIN_PKGVERSION=""
 CT_TOOLCHAIN_BUGURL=""
 
@@ -206,127 +239,214 @@ CT_BUILD_SUFFIX=""
 # Operating System
 #
 CT_KERNEL_SUPPORTS_SHARED_LIBS=y
+# CT_KERNEL_BARE_METAL is not set
+CT_KERNEL_LINUX=y
 CT_KERNEL="linux"
-CT_KERNEL_VERSION="4.2.6"
-# CT_KERNEL_bare_metal is not set
-CT_KERNEL_linux=y
-CT_KERNEL_bare_metal_AVAILABLE=y
-CT_KERNEL_linux_AVAILABLE=y
-# CT_KERNEL_V_4_3 is not set
-CT_KERNEL_V_4_2=y
-# CT_KERNEL_V_4_1 is not set
-# CT_KERNEL_V_3_18 is not set
-# CT_KERNEL_V_3_14 is not set
-# CT_KERNEL_V_3_12 is not set
-# CT_KERNEL_V_3_10 is not set
-# CT_KERNEL_V_3_4 is not set
-# CT_KERNEL_V_3_2 is not set
-# CT_KERNEL_V_2_6_32 is not set
-# CT_KERNEL_LINUX_CUSTOM is not set
-CT_KERNEL_windows_AVAILABLE=y
-
-#
-# Common kernel options
-#
-CT_SHARED_LIBS=y
-
-#
-# linux other options
-#
+CT_KERNEL_CHOICE_KSYM="LINUX"
+CT_KERNEL_LINUX_SHOW=y
+
+#
+# Options for linux
+#
+CT_KERNEL_LINUX_PKG_KSYM="LINUX"
+CT_LINUX_DIR_NAME="linux"
+CT_LINUX_PKG_NAME="linux"
+CT_LINUX_SRC_RELEASE=y
+CT_LINUX_PATCH_ORDER="global"
+# CT_LINUX_V_4_20 is not set
+# CT_LINUX_V_4_19 is not set
+# CT_LINUX_V_4_18 is not set
+# CT_LINUX_V_4_17 is not set
+# CT_LINUX_V_4_16 is not set
+# CT_LINUX_V_4_15 is not set
+# CT_LINUX_V_4_14 is not set
+# CT_LINUX_V_4_13 is not set
+# CT_LINUX_V_4_12 is not set
+# CT_LINUX_V_4_11 is not set
+# CT_LINUX_V_4_10 is not set
+# CT_LINUX_V_4_9 is not set
+# CT_LINUX_V_4_4 is not set
+CT_LINUX_V_4_1=y
+# CT_LINUX_V_3_16 is not set
+# CT_LINUX_V_3_13 is not set
+# CT_LINUX_V_3_12 is not set
+# CT_LINUX_V_3_10 is not set
+# CT_LINUX_NO_VERSIONS is not set
+CT_LINUX_VERSION="4.1.49"
+CT_LINUX_MIRRORS="$(CT_Mirrors kernel.org linux ${CT_LINUX_VERSION})"
+CT_LINUX_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_LINUX_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_LINUX_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_LINUX_SIGNATURE_FORMAT="unpacked/.sign"
+CT_LINUX_4_8_or_older=y
+CT_LINUX_older_than_4_8=y
+CT_LINUX_later_than_3_7=y
+CT_LINUX_3_7_or_later=y
+CT_LINUX_REQUIRE_3_7_or_later=y
+CT_LINUX_later_than_3_2=y
+CT_LINUX_3_2_or_later=y
 CT_KERNEL_LINUX_VERBOSITY_0=y
 # CT_KERNEL_LINUX_VERBOSITY_1 is not set
 # CT_KERNEL_LINUX_VERBOSITY_2 is not set
 CT_KERNEL_LINUX_VERBOSE_LEVEL=0
 CT_KERNEL_LINUX_INSTALL_CHECK=y
+CT_ALL_KERNEL_CHOICES="BARE_METAL LINUX WINDOWS"
+
+#
+# Common kernel options
+#
+CT_SHARED_LIBS=y
 
 #
 # Binary utilities
 #
 CT_ARCH_BINFMT_ELF=y
+CT_BINUTILS_BINUTILS=y
 CT_BINUTILS="binutils"
-CT_BINUTILS_binutils=y
+CT_BINUTILS_CHOICE_KSYM="BINUTILS"
+CT_BINUTILS_BINUTILS_SHOW=y
+
+#
+# Options for binutils
+#
+CT_BINUTILS_BINUTILS_PKG_KSYM="BINUTILS"
+CT_BINUTILS_DIR_NAME="binutils"
+CT_BINUTILS_USE_GNU=y
+CT_BINUTILS_USE="BINUTILS"
+CT_BINUTILS_PKG_NAME="binutils"
+CT_BINUTILS_SRC_RELEASE=y
+CT_BINUTILS_PATCH_ORDER="global"
+# CT_BINUTILS_V_2_32 is not set
+# CT_BINUTILS_V_2_31 is not set
+# CT_BINUTILS_V_2_30 is not set
+CT_BINUTILS_V_2_29=y
+# CT_BINUTILS_V_2_28 is not set
+# CT_BINUTILS_V_2_27 is not set
+# CT_BINUTILS_V_2_26 is not set
+# CT_BINUTILS_NO_VERSIONS is not set
+CT_BINUTILS_VERSION="2.29.1"
+CT_BINUTILS_MIRRORS="$(CT_Mirrors GNU binutils) $(CT_Mirrors sourceware binutils/releases)"
+CT_BINUTILS_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_BINUTILS_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_BINUTILS_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_BINUTILS_SIGNATURE_FORMAT="packed/.sig"
+CT_BINUTILS_2_30_or_older=y
+CT_BINUTILS_older_than_2_30=y
+CT_BINUTILS_REQUIRE_older_than_2_30=y
+CT_BINUTILS_later_than_2_27=y
+CT_BINUTILS_2_27_or_later=y
+CT_BINUTILS_later_than_2_25=y
+CT_BINUTILS_2_25_or_later=y
+CT_BINUTILS_later_than_2_23=y
+CT_BINUTILS_2_23_or_later=y
 
 #
 # GNU binutils
 #
-# CT_CC_BINUTILS_SHOW_LINARO is not set
-CT_BINUTILS_V_2_25_1=y
-# CT_BINUTILS_V_2_25 is not set
-# CT_BINUTILS_V_2_24 is not set
-# CT_BINUTILS_V_2_23_2 is not set
-# CT_BINUTILS_V_2_23_1 is not set
-# CT_BINUTILS_V_2_22 is not set
-# CT_BINUTILS_V_2_21_53 is not set
-# CT_BINUTILS_V_2_21_1a is not set
-# CT_BINUTILS_V_2_20_1a is not set
-# CT_BINUTILS_V_2_19_1a is not set
-# CT_BINUTILS_V_2_18a is not set
-CT_BINUTILS_VERSION="2.25.1"
-CT_BINUTILS_2_25_1_or_later=y
-CT_BINUTILS_2_25_or_later=y
-CT_BINUTILS_2_24_or_later=y
-CT_BINUTILS_2_23_or_later=y
-CT_BINUTILS_2_22_or_later=y
-CT_BINUTILS_2_21_or_later=y
-CT_BINUTILS_2_20_or_later=y
-CT_BINUTILS_2_19_or_later=y
-CT_BINUTILS_2_18_or_later=y
 CT_BINUTILS_HAS_HASH_STYLE=y
 CT_BINUTILS_HAS_GOLD=y
-CT_BINUTILS_GOLD_SUPPORTS_ARCH=y
-CT_BINUTILS_GOLD_SUPPORT=y
 CT_BINUTILS_HAS_PLUGINS=y
 CT_BINUTILS_HAS_PKGVERSION_BUGURL=y
-CT_BINUTILS_FORCE_LD_BFD=y
+CT_BINUTILS_GOLD_SUPPORTS_ARCH=y
+CT_BINUTILS_GOLD_SUPPORT=y
+CT_BINUTILS_FORCE_LD_BFD_DEFAULT=y
 CT_BINUTILS_LINKER_LD=y
 # CT_BINUTILS_LINKER_LD_GOLD is not set
-# CT_BINUTILS_LINKER_GOLD_LD is not set
 CT_BINUTILS_LINKERS_LIST="ld"
 CT_BINUTILS_LINKER_DEFAULT="bfd"
 # CT_BINUTILS_PLUGINS is not set
+CT_BINUTILS_RELRO=m
 CT_BINUTILS_EXTRA_CONFIG_ARRAY=""
 # CT_BINUTILS_FOR_TARGET is not set
-
-#
-# binutils other options
-#
+CT_ALL_BINUTILS_CHOICES="BINUTILS"
 
 #
 # C-library
 #
+CT_LIBC_GLIBC=y
+# CT_LIBC_NEWLIB is not set
+# CT_LIBC_NONE is not set
+# CT_LIBC_UCLIBC is not set
 CT_LIBC="glibc"
-CT_LIBC_VERSION="2.17"
-CT_LIBC_glibc=y
-# CT_LIBC_musl is not set
-# CT_LIBC_uClibc is not set
-CT_LIBC_avr_libc_AVAILABLE=y
-CT_LIBC_glibc_AVAILABLE=y
+CT_LIBC_CHOICE_KSYM="GLIBC"
 CT_THREADS="nptl"
-# CT_CC_GLIBC_SHOW_LINARO is not set
-# CT_LIBC_GLIBC_V_2_22 is not set
-# CT_LIBC_GLIBC_V_2_21 is not set
-# CT_LIBC_GLIBC_V_2_20 is not set
-# CT_LIBC_GLIBC_V_2_19 is not set
-# CT_LIBC_GLIBC_V_2_18 is not set
-CT_LIBC_GLIBC_V_2_17=y
-# CT_LIBC_GLIBC_V_2_16_0 is not set
-# CT_LIBC_GLIBC_V_2_15 is not set
-# CT_LIBC_GLIBC_V_2_14_1 is not set
-# CT_LIBC_GLIBC_V_2_14 is not set
-# CT_LIBC_GLIBC_V_2_13 is not set
-# CT_LIBC_GLIBC_V_2_12_2 is not set
-# CT_LIBC_GLIBC_V_2_12_1 is not set
-# CT_LIBC_GLIBC_V_2_11_1 is not set
-# CT_LIBC_GLIBC_V_2_11 is not set
-# CT_LIBC_GLIBC_V_2_10_1 is not set
-# CT_LIBC_GLIBC_V_2_9 is not set
-# CT_LIBC_GLIBC_V_2_8 is not set
-CT_LIBC_GLIBC_2_17_or_later=y
-CT_LIBC_mingw_AVAILABLE=y
-CT_LIBC_musl_AVAILABLE=y
-CT_LIBC_newlib_AVAILABLE=y
-CT_LIBC_none_AVAILABLE=y
-CT_LIBC_uClibc_AVAILABLE=y
+CT_LIBC_GLIBC_SHOW=y
+
+#
+# Options for glibc
+#
+CT_LIBC_GLIBC_PKG_KSYM="GLIBC"
+CT_GLIBC_DIR_NAME="glibc"
+CT_GLIBC_USE_GNU=y
+CT_GLIBC_USE="GLIBC"
+CT_GLIBC_PKG_NAME="glibc"
+CT_GLIBC_SRC_RELEASE=y
+CT_GLIBC_PATCH_ORDER="global"
+# CT_GLIBC_V_2_29 is not set
+# CT_GLIBC_V_2_28 is not set
+# CT_GLIBC_V_2_27 is not set
+# CT_GLIBC_V_2_26 is not set
+# CT_GLIBC_V_2_25 is not set
+# CT_GLIBC_V_2_24 is not set
+# CT_GLIBC_V_2_23 is not set
+# CT_GLIBC_V_2_19 is not set
+CT_GLIBC_V_2_17=y
+# CT_GLIBC_V_2_12_1 is not set
+# CT_GLIBC_NO_VERSIONS is not set
+CT_GLIBC_VERSION="2.17"
+CT_GLIBC_MIRRORS="$(CT_Mirrors GNU glibc)"
+CT_GLIBC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GLIBC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GLIBC_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_GLIBC_SIGNATURE_FORMAT="packed/.sig"
+CT_GLIBC_2_29_or_older=y
+CT_GLIBC_older_than_2_29=y
+CT_GLIBC_2_27_or_older=y
+CT_GLIBC_older_than_2_27=y
+CT_GLIBC_2_26_or_older=y
+CT_GLIBC_older_than_2_26=y
+CT_GLIBC_2_25_or_older=y
+CT_GLIBC_older_than_2_25=y
+CT_GLIBC_2_24_or_older=y
+CT_GLIBC_older_than_2_24=y
+CT_GLIBC_2_23_or_older=y
+CT_GLIBC_older_than_2_23=y
+CT_GLIBC_2_20_or_older=y
+CT_GLIBC_older_than_2_20=y
+CT_GLIBC_2_17_or_later=y
+CT_GLIBC_2_17_or_older=y
+CT_GLIBC_later_than_2_14=y
+CT_GLIBC_2_14_or_later=y
+CT_GLIBC_DEP_KERNEL_HEADERS_VERSION=y
+CT_GLIBC_DEP_BINUTILS=y
+CT_GLIBC_DEP_GCC=y
+CT_GLIBC_DEP_PYTHON=y
+CT_GLIBC_HAS_NPTL_ADDON=y
+CT_GLIBC_HAS_PORTS_ADDON=y
+CT_GLIBC_HAS_LIBIDN_ADDON=y
+CT_GLIBC_USE_PORTS_ADDON=y
+CT_GLIBC_USE_NPTL_ADDON=y
+# CT_GLIBC_USE_LIBIDN_ADDON is not set
+CT_GLIBC_HAS_OBSOLETE_RPC=y
+CT_GLIBC_EXTRA_CONFIG_ARRAY=""
+CT_GLIBC_CONFIGPARMS=""
+CT_GLIBC_EXTRA_CFLAGS=""
+CT_GLIBC_ENABLE_OBSOLETE_RPC=y
+# CT_GLIBC_DISABLE_VERSIONING is not set
+CT_GLIBC_OLDEST_ABI=""
+CT_GLIBC_FORCE_UNWIND=y
+# CT_GLIBC_LOCALES is not set
+# CT_GLIBC_KERNEL_VERSION_NONE is not set
+CT_GLIBC_KERNEL_VERSION_AS_HEADERS=y
+# CT_GLIBC_KERNEL_VERSION_CHOSEN is not set
+CT_GLIBC_MIN_KERNEL="4.1.49"
+# CT_GLIBC_SSP_DEFAULT is not set
+# CT_GLIBC_SSP_NO is not set
+# CT_GLIBC_SSP_YES is not set
+# CT_GLIBC_SSP_ALL is not set
+# CT_GLIBC_SSP_STRONG is not set
+# CT_NEWLIB_USE_REDHAT is not set
+CT_ALL_LIBC_CHOICES="AVR_LIBC BIONIC GLIBC MINGW_W64 MOXIEBOX MUSL NEWLIB NONE UCLIBC"
 CT_LIBC_SUPPORT_THREADS_ANY=y
 CT_LIBC_SUPPORT_THREADS_NATIVE=y
 
@@ -334,100 +454,71 @@ CT_LIBC_SUPPORT_THREADS_NATIVE=y
 # Common C library options
 #
 CT_THREADS_NATIVE=y
+# CT_CREATE_LDSO_CONF is not set
 CT_LIBC_XLDD=y
 
-#
-# glibc other options
-#
-# CT_LIBC_GLIBC_PORTS_EXTERNAL is not set
-CT_LIBC_GLIBC_MAY_FORCE_PORTS=y
-CT_LIBC_glibc_familly=y
-CT_LIBC_GLIBC_EXTRA_CONFIG_ARRAY=""
-CT_LIBC_GLIBC_CONFIGPARMS=""
-CT_LIBC_GLIBC_EXTRA_CFLAGS=""
-CT_LIBC_EXTRA_CC_ARGS=""
-# CT_LIBC_DISABLE_VERSIONING is not set
-CT_LIBC_OLDEST_ABI=""
-CT_LIBC_GLIBC_FORCE_UNWIND=y
-CT_LIBC_GLIBC_USE_PORTS=y
-CT_LIBC_ADDONS_LIST=""
-
-#
-# WARNING !!!                                            
-#
-
-#
-#   For glibc >= 2.8, it can happen that the tarballs    
-#
-
-#
-#   for the addons are not available for download.       
-#
-
-#
-#   If that happens, bad luck... Try a previous version  
-#
-
-#
-#   or try again later... :-(                            
-#
-# CT_LIBC_LOCALES is not set
-# CT_LIBC_GLIBC_KERNEL_VERSION_NONE is not set
-CT_LIBC_GLIBC_KERNEL_VERSION_AS_HEADERS=y
-# CT_LIBC_GLIBC_KERNEL_VERSION_CHOSEN is not set
-CT_LIBC_GLIBC_MIN_KERNEL="4.2.6"
-
 #
 # C compiler
 #
-CT_CC="gcc"
 CT_CC_CORE_PASSES_NEEDED=y
 CT_CC_CORE_PASS_1_NEEDED=y
 CT_CC_CORE_PASS_2_NEEDED=y
-CT_CC_gcc=y
-# CT_CC_GCC_SHOW_LINARO is not set
-CT_CC_GCC_V_5_2_0=y
-# CT_CC_GCC_V_4_9_3 is not set
-# CT_CC_GCC_V_4_8_5 is not set
-# CT_CC_GCC_V_4_7_4 is not set
-# CT_CC_GCC_V_4_6_4 is not set
-# CT_CC_GCC_V_4_5_4 is not set
-# CT_CC_GCC_V_4_4_7 is not set
-# CT_CC_GCC_V_4_3_6 is not set
-# CT_CC_GCC_V_4_2_4 is not set
-CT_CC_GCC_4_2_or_later=y
-CT_CC_GCC_4_3_or_later=y
-CT_CC_GCC_4_4_or_later=y
-CT_CC_GCC_4_5_or_later=y
-CT_CC_GCC_4_6_or_later=y
-CT_CC_GCC_4_7_or_later=y
-CT_CC_GCC_4_8_or_later=y
-CT_CC_GCC_4_9_or_later=y
-CT_CC_GCC_5=y
-CT_CC_GCC_5_or_later=y
-CT_CC_GCC_HAS_GRAPHITE=y
-CT_CC_GCC_USE_GRAPHITE=y
-CT_CC_GCC_HAS_LTO=y
-CT_CC_GCC_USE_LTO=y
-CT_CC_GCC_HAS_PKGVERSION_BUGURL=y
-CT_CC_GCC_HAS_BUILD_ID=y
-CT_CC_GCC_HAS_LNK_HASH_STYLE=y
-CT_CC_GCC_USE_GMP_MPFR=y
-CT_CC_GCC_USE_MPC=y
-CT_CC_GCC_HAS_LIBQUADMATH=y
-CT_CC_GCC_HAS_LIBSANITIZER=y
-CT_CC_GCC_VERSION="5.2.0"
-# CT_CC_LANG_FORTRAN is not set
+CT_CC_SUPPORT_CXX=y
+CT_CC_SUPPORT_FORTRAN=y
+CT_CC_SUPPORT_ADA=y
+CT_CC_SUPPORT_OBJC=y
+CT_CC_SUPPORT_OBJCXX=y
+CT_CC_SUPPORT_GOLANG=y
+CT_CC_GCC=y
+CT_CC="gcc"
+CT_CC_CHOICE_KSYM="GCC"
+CT_CC_GCC_SHOW=y
+
+#
+# Options for gcc
+#
+CT_CC_GCC_PKG_KSYM="GCC"
+CT_GCC_DIR_NAME="gcc"
+CT_GCC_USE_GNU=y
+CT_GCC_USE="GCC"
+CT_GCC_PKG_NAME="gcc"
+CT_GCC_SRC_RELEASE=y
+CT_GCC_PATCH_ORDER="global"
+CT_GCC_V_8=y
+# CT_GCC_V_7 is not set
+# CT_GCC_V_6 is not set
+# CT_GCC_V_5 is not set
+# CT_GCC_V_4_9 is not set
+# CT_GCC_NO_VERSIONS is not set
+CT_GCC_VERSION="8.3.0"
+CT_GCC_MIRRORS="$(CT_Mirrors GNU gcc/gcc-${CT_GCC_VERSION}) $(CT_Mirrors sourceware gcc/releases/gcc-${CT_GCC_VERSION})"
+CT_GCC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GCC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GCC_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_GCC_SIGNATURE_FORMAT=""
+CT_GCC_later_than_7=y
+CT_GCC_7_or_later=y
+CT_GCC_later_than_6=y
+CT_GCC_6_or_later=y
+CT_GCC_later_than_5=y
+CT_GCC_5_or_later=y
+CT_GCC_later_than_4_9=y
+CT_GCC_4_9_or_later=y
+CT_GCC_later_than_4_8=y
+CT_GCC_4_8_or_later=y
+CT_CC_GCC_HAS_LIBMPX=y
 CT_CC_GCC_ENABLE_CXX_FLAGS=""
 CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY=""
 CT_CC_GCC_EXTRA_CONFIG_ARRAY=""
-CT_CC_GCC_EXTRA_ENV_ARRAY=""
 CT_CC_GCC_STATIC_LIBSTDCXX=y
 # CT_CC_GCC_SYSTEM_ZLIB is not set
+CT_CC_GCC_CONFIG_TLS=m
 
 #
 # Optimisation features
 #
+CT_CC_GCC_USE_GRAPHITE=y
+CT_CC_GCC_USE_LTO=y
 
 #
 # Settings for libraries running on target
@@ -456,97 +547,208 @@ CT_CC_GCC_DEC_FLOAT_AUTO=y
 # CT_CC_GCC_DEC_FLOAT_BID is not set
 # CT_CC_GCC_DEC_FLOAT_DPD is not set
 # CT_CC_GCC_DEC_FLOATS_NO is not set
-CT_CC_SUPPORT_CXX=y
-CT_CC_SUPPORT_FORTRAN=y
-CT_CC_SUPPORT_JAVA=y
-CT_CC_SUPPORT_ADA=y
-CT_CC_SUPPORT_OBJC=y
-CT_CC_SUPPORT_OBJCXX=y
-CT_CC_SUPPORT_GOLANG=y
+CT_ALL_CC_CHOICES="GCC"
 
 #
 # Additional supported languages:
 #
 CT_CC_LANG_CXX=y
-# CT_CC_LANG_JAVA is not set
+# CT_CC_LANG_FORTRAN is not set
 
 #
 # Debug facilities
 #
-# CT_DEBUG_dmalloc is not set
-# CT_DEBUG_duma is not set
-# CT_DEBUG_gdb is not set
-# CT_DEBUG_ltrace is not set
-# CT_DEBUG_strace is not set
+# CT_DEBUG_DUMA is not set
+# CT_DEBUG_GDB is not set
+# CT_DEBUG_LTRACE is not set
+# CT_DEBUG_STRACE is not set
+CT_ALL_DEBUG_CHOICES="DUMA GDB LTRACE STRACE"
 
 #
 # Companion libraries
 #
-CT_COMPLIBS_NEEDED=y
+# CT_COMPLIBS_CHECK is not set
+# CT_COMP_LIBS_CLOOG is not set
+# CT_COMP_LIBS_EXPAT is not set
+CT_COMP_LIBS_GETTEXT=y
+CT_COMP_LIBS_GETTEXT_PKG_KSYM="GETTEXT"
+CT_GETTEXT_DIR_NAME="gettext"
+CT_GETTEXT_PKG_NAME="gettext"
+CT_GETTEXT_SRC_RELEASE=y
+CT_GETTEXT_PATCH_ORDER="global"
+CT_GETTEXT_V_0_19_8_1=y
+# CT_GETTEXT_NO_VERSIONS is not set
+CT_GETTEXT_VERSION="0.19.8.1"
+CT_GETTEXT_MIRRORS="$(CT_Mirrors GNU gettext)"
+CT_GETTEXT_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GETTEXT_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GETTEXT_ARCHIVE_FORMATS=".tar.xz .tar.lz .tar.gz"
+CT_GETTEXT_SIGNATURE_FORMAT="packed/.sig"
+CT_COMP_LIBS_GMP=y
+CT_COMP_LIBS_GMP_PKG_KSYM="GMP"
+CT_GMP_DIR_NAME="gmp"
+CT_GMP_PKG_NAME="gmp"
+CT_GMP_SRC_RELEASE=y
+CT_GMP_PATCH_ORDER="global"
+CT_GMP_V_6_1=y
+# CT_GMP_NO_VERSIONS is not set
+CT_GMP_VERSION="6.1.2"
+CT_GMP_MIRRORS="https://gmplib.org/download/gmp https://gmplib.org/download/gmp/archive $(CT_Mirrors GNU gmp)"
+CT_GMP_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GMP_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GMP_ARCHIVE_FORMATS=".tar.xz .tar.lz .tar.bz2"
+CT_GMP_SIGNATURE_FORMAT="packed/.sig"
+CT_GMP_later_than_5_1_0=y
+CT_GMP_5_1_0_or_later=y
+CT_GMP_later_than_5_0_0=y
+CT_GMP_5_0_0_or_later=y
+CT_GMP_REQUIRE_5_0_0_or_later=y
+CT_COMP_LIBS_ISL=y
+CT_COMP_LIBS_ISL_PKG_KSYM="ISL"
+CT_ISL_DIR_NAME="isl"
+CT_ISL_PKG_NAME="isl"
+CT_ISL_SRC_RELEASE=y
+CT_ISL_PATCH_ORDER="global"
+CT_ISL_V_0_20=y
+# CT_ISL_V_0_19 is not set
+# CT_ISL_V_0_18 is not set
+# CT_ISL_V_0_17 is not set
+# CT_ISL_V_0_16 is not set
+# CT_ISL_V_0_15 is not set
+# CT_ISL_NO_VERSIONS is not set
+CT_ISL_VERSION="0.20"
+CT_ISL_MIRRORS="http://isl.gforge.inria.fr"
+CT_ISL_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_ISL_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_ISL_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_ISL_SIGNATURE_FORMAT=""
+CT_ISL_later_than_0_18=y
+CT_ISL_0_18_or_later=y
+CT_ISL_later_than_0_15=y
+CT_ISL_0_15_or_later=y
+CT_ISL_REQUIRE_0_15_or_later=y
+CT_ISL_later_than_0_14=y
+CT_ISL_0_14_or_later=y
+CT_ISL_REQUIRE_0_14_or_later=y
+CT_ISL_later_than_0_13=y
+CT_ISL_0_13_or_later=y
+CT_ISL_later_than_0_12=y
+CT_ISL_0_12_or_later=y
+CT_ISL_REQUIRE_0_12_or_later=y
+# CT_COMP_LIBS_LIBELF is not set
+CT_COMP_LIBS_LIBICONV=y
+CT_COMP_LIBS_LIBICONV_PKG_KSYM="LIBICONV"
+CT_LIBICONV_DIR_NAME="libiconv"
+CT_LIBICONV_PKG_NAME="libiconv"
+CT_LIBICONV_SRC_RELEASE=y
+CT_LIBICONV_PATCH_ORDER="global"
+CT_LIBICONV_V_1_15=y
+# CT_LIBICONV_NO_VERSIONS is not set
+CT_LIBICONV_VERSION="1.15"
+CT_LIBICONV_MIRRORS="$(CT_Mirrors GNU libiconv)"
+CT_LIBICONV_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_LIBICONV_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_LIBICONV_ARCHIVE_FORMATS=".tar.gz"
+CT_LIBICONV_SIGNATURE_FORMAT="packed/.sig"
+CT_COMP_LIBS_MPC=y
+CT_COMP_LIBS_MPC_PKG_KSYM="MPC"
+CT_MPC_DIR_NAME="mpc"
+CT_MPC_PKG_NAME="mpc"
+CT_MPC_SRC_RELEASE=y
+CT_MPC_PATCH_ORDER="global"
+CT_MPC_V_1_1=y
+# CT_MPC_V_1_0 is not set
+# CT_MPC_NO_VERSIONS is not set
+CT_MPC_VERSION="1.1.0"
+CT_MPC_MIRRORS="http://www.multiprecision.org/downloads $(CT_Mirrors GNU mpc)"
+CT_MPC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_MPC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_MPC_ARCHIVE_FORMATS=".tar.gz"
+CT_MPC_SIGNATURE_FORMAT="packed/.sig"
+CT_MPC_1_1_0_or_later=y
+CT_MPC_1_1_0_or_older=y
+CT_COMP_LIBS_MPFR=y
+CT_COMP_LIBS_MPFR_PKG_KSYM="MPFR"
+CT_MPFR_DIR_NAME="mpfr"
+CT_MPFR_PKG_NAME="mpfr"
+CT_MPFR_SRC_RELEASE=y
+CT_MPFR_PATCH_ORDER="global"
+CT_MPFR_V_4_0=y
+# CT_MPFR_V_3_1 is not set
+# CT_MPFR_NO_VERSIONS is not set
+CT_MPFR_VERSION="4.0.2"
+CT_MPFR_MIRRORS="http://www.mpfr.org/mpfr-${CT_MPFR_VERSION} $(CT_Mirrors GNU mpfr)"
+CT_MPFR_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_MPFR_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_MPFR_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz .zip"
+CT_MPFR_SIGNATURE_FORMAT="packed/.asc"
+CT_MPFR_later_than_4_0_0=y
+CT_MPFR_4_0_0_or_later=y
+CT_MPFR_later_than_3_0_0=y
+CT_MPFR_3_0_0_or_later=y
+CT_MPFR_REQUIRE_3_0_0_or_later=y
+CT_COMP_LIBS_NCURSES=y
+CT_COMP_LIBS_NCURSES_PKG_KSYM="NCURSES"
+CT_NCURSES_DIR_NAME="ncurses"
+CT_NCURSES_PKG_NAME="ncurses"
+CT_NCURSES_SRC_RELEASE=y
+CT_NCURSES_PATCH_ORDER="global"
+CT_NCURSES_V_6_1=y
+# CT_NCURSES_V_6_0 is not set
+# CT_NCURSES_NO_VERSIONS is not set
+CT_NCURSES_VERSION="6.1"
+CT_NCURSES_MIRRORS="ftp://invisible-island.net/ncurses $(CT_Mirrors GNU ncurses)"
+CT_NCURSES_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_NCURSES_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_NCURSES_ARCHIVE_FORMATS=".tar.gz"
+CT_NCURSES_SIGNATURE_FORMAT="packed/.sig"
+CT_NCURSES_HOST_CONFIG_ARGS=""
+CT_NCURSES_HOST_DISABLE_DB=y
+CT_NCURSES_HOST_FALLBACKS="linux,xterm,xterm-color,xterm-256color,vt100"
+CT_NCURSES_TARGET_CONFIG_ARGS=""
+# CT_NCURSES_TARGET_DISABLE_DB is not set
+CT_NCURSES_TARGET_FALLBACKS=""
+CT_COMP_LIBS_ZLIB=y
+CT_COMP_LIBS_ZLIB_PKG_KSYM="ZLIB"
+CT_ZLIB_DIR_NAME="zlib"
+CT_ZLIB_PKG_NAME="zlib"
+CT_ZLIB_SRC_RELEASE=y
+CT_ZLIB_PATCH_ORDER="global"
+CT_ZLIB_V_1_2_11=y
+# CT_ZLIB_NO_VERSIONS is not set
+CT_ZLIB_VERSION="1.2.11"
+CT_ZLIB_MIRRORS="http://downloads.sourceforge.net/project/libpng/zlib/${CT_ZLIB_VERSION}"
+CT_ZLIB_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_ZLIB_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_ZLIB_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_ZLIB_SIGNATURE_FORMAT="packed/.asc"
+CT_ALL_COMP_LIBS_CHOICES="CLOOG EXPAT GETTEXT GMP ISL LIBELF LIBICONV MPC MPFR NCURSES ZLIB"
 CT_LIBICONV_NEEDED=y
 CT_GETTEXT_NEEDED=y
 CT_GMP_NEEDED=y
 CT_MPFR_NEEDED=y
 CT_ISL_NEEDED=y
 CT_MPC_NEEDED=y
-CT_COMPLIBS=y
+CT_NCURSES_NEEDED=y
+CT_ZLIB_NEEDED=y
 CT_LIBICONV=y
 CT_GETTEXT=y
 CT_GMP=y
 CT_MPFR=y
 CT_ISL=y
 CT_MPC=y
-CT_LIBICONV_V_1_14=y
-CT_LIBICONV_VERSION="1.14"
-CT_GETTEXT_V_0_19_6=y
-CT_GETTEXT_VERSION="0.19.6"
-CT_GMP_V_6_0_0=y
-# CT_GMP_V_5_1_3 is not set
-# CT_GMP_V_5_1_1 is not set
-# CT_GMP_V_5_0_2 is not set
-# CT_GMP_V_5_0_1 is not set
-# CT_GMP_V_4_3_2 is not set
-# CT_GMP_V_4_3_1 is not set
-# CT_GMP_V_4_3_0 is not set
-CT_GMP_5_0_2_or_later=y
-CT_GMP_VERSION="6.0.0a"
-CT_MPFR_V_3_1_3=y
-# CT_MPFR_V_3_1_2 is not set
-# CT_MPFR_V_3_1_0 is not set
-# CT_MPFR_V_3_0_1 is not set
-# CT_MPFR_V_3_0_0 is not set
-# CT_MPFR_V_2_4_2 is not set
-# CT_MPFR_V_2_4_1 is not set
-# CT_MPFR_V_2_4_0 is not set
-CT_MPFR_VERSION="3.1.3"
-CT_ISL_V_0_14=y
-# CT_ISL_V_0_12_2 is not set
-CT_ISL_V_0_14_or_later=y
-CT_ISL_V_0_12_or_later=y
-CT_ISL_VERSION="0.14"
-# CT_CLOOG_V_0_18_4 is not set
-# CT_CLOOG_V_0_18_1 is not set
-# CT_CLOOG_V_0_18_0 is not set
-CT_MPC_V_1_0_3=y
-# CT_MPC_V_1_0_2 is not set
-# CT_MPC_V_1_0_1 is not set
-# CT_MPC_V_1_0 is not set
-# CT_MPC_V_0_9 is not set
-# CT_MPC_V_0_8_2 is not set
-# CT_MPC_V_0_8_1 is not set
-# CT_MPC_V_0_7 is not set
-CT_MPC_VERSION="1.0.3"
-
-#
-# Companion libraries common options
-#
-# CT_COMPLIBS_CHECK is not set
+CT_NCURSES=y
+CT_ZLIB=y
 
 #
 # Companion tools
 #
-
-#
-# READ HELP before you say 'Y' below !!!
-#
-# CT_COMP_TOOLS is not set
+# CT_COMP_TOOLS_FOR_HOST is not set
+# CT_COMP_TOOLS_AUTOCONF is not set
+# CT_COMP_TOOLS_AUTOMAKE is not set
+# CT_COMP_TOOLS_BISON is not set
+# CT_COMP_TOOLS_DTC is not set
+# CT_COMP_TOOLS_LIBTOOL is not set
+# CT_COMP_TOOLS_M4 is not set
+# CT_COMP_TOOLS_MAKE is not set
+CT_ALL_COMP_TOOLS_CHOICES="AUTOCONF AUTOMAKE BISON DTC LIBTOOL M4 MAKE"
index 2f0496d7dd4ba06ab3a7f8e79bb9a26950c829a0..c98fa496d4861d22c274e17d3f38c2ca12fc7ccf 100644 (file)
@@ -32,7 +32,8 @@ ENV RUST_CONFIGURE_ARGS \
       --i686-linux-android-ndk=/android/ndk/x86-14 \
       --aarch64-linux-android-ndk=/android/ndk/arm64-21 \
       --x86_64-linux-android-ndk=/android/ndk/x86_64-21 \
-      --disable-docs
+      --disable-docs \
+      --set llvm.allow-old-toolchain
 
 ENV SCRIPT python3 ../x.py dist --host='' --target $TARGETS
 
index 79c2c1d93d7187bd9f5e1c9b7c32ce09ed856276..0c3b9ebdc331621a0edd104d98e91a83c794dfb7 100644 (file)
@@ -28,9 +28,6 @@ USER root
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
-
 ENV PATH=$PATH:/x-tools/arm-unknown-linux-gnueabi/bin
 
 ENV CC_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-gcc \
index dd1c83b41325209a537c06f4358b432192b9a373..753d6450502f3d31570a6fe099d1d5b6fb2ddcee 100644 (file)
@@ -19,9 +19,6 @@ USER root
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
-
 ENV PATH=$PATH:/x-tools/arm-unknown-linux-gnueabihf/bin
 
 ENV CC_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-gcc \
index 32e3bc22ad795cf5619ed75f5771b9fdf933d16f..7eb5097aae88ac63c7d9a977e2a38bed68374e91 100644 (file)
@@ -19,9 +19,6 @@ USER root
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
-
 ENV PATH=$PATH:/x-tools/armv7-unknown-linux-gnueabihf/bin
 
 ENV CC_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-gcc \
index c98fc7dcfff3e803d3edc9407db469c1e3664f95..b0d65428ec6c488a7166e9f05108439cd95e2478 100644 (file)
@@ -36,7 +36,8 @@ RUN /scripts/cmake.sh
 ENV RUST_CONFIGURE_ARGS \
       --musl-root-i586=/musl-i586 \
       --musl-root-i686=/musl-i686 \
-      --disable-docs
+      --disable-docs \
+      --set llvm.allow-old-toolchain
 
 # Newer binutils broke things on some vms/distros (i.e., linking against
 # unknown relocs disabled by the following flag), so we need to go out of our
index 2b4b78e81350d5dd396e62e038781a837b3c308c..cd86d9fb584fb116eaeb6345f841fe7718846754 100644 (file)
@@ -1,48 +1,40 @@
-# We need recent curl, OpenSSL and CA certificates, so we can download further
-# dependencies in the debian:6 image. We use an ubuntu 20.04 image download
-# those.
-FROM ubuntu:20.04
-RUN apt-get update && \
-    apt-get install -y --no-install-recommends \
-        curl \
-        ca-certificates
-WORKDIR /tmp
-COPY host-x86_64/dist-x86_64-linux/download-openssl-curl.sh /tmp/
-RUN ./download-openssl-curl.sh
-
-# We use Debian 6 (glibc 2.11, kernel 2.6.32) as a common base for other
-# distros that still need Rust support: RHEL 6 (glibc 2.12, kernel 2.6.32) and
-# SLES 11 SP4 (glibc 2.11, kernel 3.0).
-FROM debian:6
+# We document platform support for minimum glibc 2.17 and kernel 3.2.
+# CentOS 7 has headers for kernel 3.10, but that's fine as long as we don't
+# actually use newer APIs in rustc or std without a fallback. It's more
+# important that we match glibc for ELF symbol versioning.
+FROM centos:7
 
 WORKDIR /build
 
-# Debian 6 is EOL and no longer available from the usual mirrors,
-# so we'll need to switch to http://archive.debian.org/
-RUN sed -i '/updates/d' /etc/apt/sources.list && \
-    sed -i 's/httpredir/archive/' /etc/apt/sources.list
-
-RUN apt-get update && \
-    apt-get install --allow-unauthenticated -y --no-install-recommends \
+RUN yum upgrade -y && \
+    yum install -y epel-release && \
+    yum install -y \
       automake \
       bzip2 \
       file \
-      g++ \
-      g++-multilib \
+      cmake3 \
       gcc \
-      gcc-multilib \
+      gcc-c++ \
       git \
-      lib32z1-dev \
-      libedit-dev \
-      libncurses-dev \
+      glibc-devel.i686 \
+      glibc-devel.x86_64 \
+      libedit-devel \
+      libstdc++-devel.i686 \
+      libstdc++-devel.x86_64 \
       make \
+      ncurses-devel \
+      openssl-devel \
       patch \
       perl \
-      pkg-config \
+      pkgconfig \
+      python3 \
       unzip \
       wget \
-      xz-utils \
-      zlib1g-dev
+      xz \
+      zlib-devel.i686 \
+      zlib-devel.x86_64
+
+RUN mkdir -p /rustroot/bin && ln -s /usr/bin/cmake3 /rustroot/bin/cmake
 
 ENV PATH=/rustroot/bin:$PATH
 ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib32:/rustroot/lib
@@ -51,46 +43,9 @@ WORKDIR /tmp
 RUN mkdir /home/user
 COPY host-x86_64/dist-x86_64-linux/shared.sh /tmp/
 
-# We need a build of openssl which supports SNI to download artifacts from
-# static.rust-lang.org. This'll be used to link into libcurl below (and used
-# later as well), so build a copy of OpenSSL with dynamic libraries into our
-# generic root.
-COPY --from=0 /tmp/openssl.tar.gz /tmp/openssl.tar.gz
-COPY host-x86_64/dist-x86_64-linux/build-openssl.sh /tmp/
-RUN ./build-openssl.sh
-
-# The `curl` binary on Debian 6 doesn't support SNI which is needed for fetching
-# some https urls we have, so install a new version of libcurl + curl which is
-# using the openssl we just built previously.
-#
-# Note that we also disable a bunch of optional features of curl that we don't
-# really need.
-COPY --from=0 /tmp/curl.tar.xz /tmp/curl.tar.xz
-COPY host-x86_64/dist-x86_64-linux/build-curl.sh /tmp/
-RUN ./build-curl.sh
-
-# Use up-to-date curl CA bundle
-COPY --from=0 /tmp/cacert.pem /tmp/cacert.pem
-ENV CURL_CA_BUNDLE /tmp/cacert.pem
-
-# binutils < 2.22 has a bug where the 32-bit executables it generates
-# immediately segfault in Rust, so we need to install our own binutils.
-#
-# See https://github.com/rust-lang/rust/issues/20440 for more info
-COPY host-x86_64/dist-x86_64-linux/build-binutils.sh /tmp/
-RUN ./build-binutils.sh
-
 # Need at least GCC 5.1 to compile LLVM nowadays
 COPY host-x86_64/dist-x86_64-linux/build-gcc.sh /tmp/
-RUN ./build-gcc.sh && apt-get remove -y gcc g++
-
-COPY host-x86_64/dist-x86_64-linux/build-python.sh /tmp/
-# Build Python 3 needed for LLVM 12.
-RUN ./build-python.sh 3.9.1
-
-# LLVM needs cmake 3.13.4 or higher.
-COPY host-x86_64/dist-x86_64-linux/build-cmake.sh /tmp/
-RUN ./build-cmake.sh
+RUN ./build-gcc.sh && yum remove -y gcc gcc-c++
 
 # Now build LLVM+Clang, afterwards configuring further compilations to use the
 # clang/clang++ compilers.
index b0f06569a9c21f20192cd72525e2ce63f4f7b1a9..948fa40dd4b13c0161c41637570f8a31c19d182b 100644 (file)
@@ -26,5 +26,6 @@ RUN /scripts/cmake.sh
 
 ENV HOSTS=mips-unknown-linux-gnu
 
-ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
+ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs \
+    --set llvm.allow-old-toolchain
 ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS
index 245c28e1fa341efa1b0775ad18658fc9b7367dde..fd15dbd22c6c279b807556067174458961a387fc 100644 (file)
@@ -25,5 +25,6 @@ RUN /scripts/cmake.sh
 
 ENV HOSTS=mips64-unknown-linux-gnuabi64
 
-ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
+ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs \
+    --set llvm.allow-old-toolchain
 ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS
index 03998c8880aea3cdefc056163c8074bcc68e6c74..376bdfb4a2f4b6e1d80375e806a7cc510a418c5d 100644 (file)
@@ -26,5 +26,6 @@ RUN /scripts/cmake.sh
 
 ENV HOSTS=mips64el-unknown-linux-gnuabi64
 
-ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
+ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs \
+    --set llvm.allow-old-toolchain
 ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS
index 586172706210104606a9cfe441565cf7ffc1e569..70c8b2a96c8c1e458582e32ce01bbf3c1d1596aa 100644 (file)
@@ -25,5 +25,6 @@ RUN /scripts/cmake.sh
 
 ENV HOSTS=mipsel-unknown-linux-gnu
 
-ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
+ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs \
+    --set llvm.allow-old-toolchain
 ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS
index ecaa495e97aee8859f63a17e0f0951146f944d8c..94a837151c62301fe5a693d8e7195ea061826df7 100644 (file)
@@ -1,22 +1,16 @@
-FROM ubuntu:16.04
+FROM ubuntu:20.04
 
 COPY scripts/cross-apt-packages.sh /scripts/
 RUN sh /scripts/cross-apt-packages.sh
 
-# Ubuntu 16.04 (this container) ships with make 4, but something in the
-# toolchains we build below chokes on that, so go back to make 3
-COPY scripts/make3.sh /scripts/
-RUN sh /scripts/make3.sh
-
-COPY scripts/crosstool-ng.sh /scripts/
-RUN sh /scripts/crosstool-ng.sh
+COPY scripts/crosstool-ng-1.24.sh /scripts/
+RUN sh /scripts/crosstool-ng-1.24.sh
 
 COPY scripts/rustbuild-setup.sh /scripts/
 RUN sh /scripts/rustbuild-setup.sh
 USER rustbuild
 WORKDIR /tmp
 
-COPY host-x86_64/dist-powerpc-linux/patches/ /tmp/patches/
 COPY host-x86_64/dist-powerpc-linux/powerpc-linux-gnu.config host-x86_64/dist-powerpc-linux/build-powerpc-toolchain.sh /tmp/
 RUN ./build-powerpc-toolchain.sh
 
@@ -25,9 +19,6 @@ USER root
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
-
 ENV PATH=$PATH:/x-tools/powerpc-unknown-linux-gnu/bin
 
 ENV \
diff --git a/src/ci/docker/host-x86_64/dist-powerpc-linux/patches/glibc/2.11.1/001-PowerPC-Remove-unnecessary-mnew-mnemonics.patch b/src/ci/docker/host-x86_64/dist-powerpc-linux/patches/glibc/2.11.1/001-PowerPC-Remove-unnecessary-mnew-mnemonics.patch
deleted file mode 100644 (file)
index 744eb18..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-From b3563932f85d60bb0d38b0a5f3b8f4abc133f890 Mon Sep 17 00:00:00 2001
-From: Tulio Magno Quites Machado Filho <tuliom@linux.vnet.ibm.com>
-Date: Thu, 1 Nov 2012 18:00:06 -0500
-Subject: [PATCH] PowerPC: Remove unnecessary -mnew-mnemonics.
-
----
- sysdeps/powerpc/Makefile | 4 ----
- 1 file changed, 4 deletions(-)
-
-diff --git a/sysdeps/powerpc/Makefile b/sysdeps/powerpc/Makefile
-index 79dd6fa976d5..7442b6709ad1 100644
---- a/sysdeps/powerpc/Makefile
-+++ b/sysdeps/powerpc/Makefile
-@@ -1,7 +1,3 @@
--# We always want to use the new mnemonic syntax even if we are on a RS6000
--# machine.
--+cflags += -mnew-mnemonics
--
- ifeq ($(subdir),gmon)
- sysdep_routines += ppc-mcount
- endif
--- 
-2.9.3
-
diff --git a/src/ci/docker/host-x86_64/dist-powerpc-linux/patches/glibc/2.11.1/002-newer-gcc.patch b/src/ci/docker/host-x86_64/dist-powerpc-linux/patches/glibc/2.11.1/002-newer-gcc.patch
deleted file mode 100644 (file)
index a96b488..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-diff --git a/configure b/configure
-index b6752d147c6b..6089a3403410 100755
---- a/configure
-+++ b/configure
-@@ -5079,7 +5079,7 @@ $as_echo_n "checking version of $CC... " >&6; }
-   ac_prog_version=`$CC -v 2>&1 | sed -n 's/^.*version \([egcygnustpi-]*[0-9.]*\).*$/\1/p'`
-   case $ac_prog_version in
-     '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
--    3.4* | 4.[0-9]* )
-+    3.4* | [4-9].* )
-        ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;;
-     *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;;
-diff --git a/configure.in b/configure.in
-index 56849dfc489a..09677eb3d0c1 100644
---- a/configure.in
-+++ b/configure.in
-@@ -960,7 +960,7 @@ fi
- # These programs are version sensitive.
- AC_CHECK_TOOL_PREFIX
- AC_CHECK_PROG_VER(CC, ${ac_tool_prefix}gcc ${ac_tool_prefix}cc, -v,
--  [version \([egcygnustpi-]*[0-9.]*\)], [3.4* | 4.[0-9]* ],
-+  [version \([egcygnustpi-]*[0-9.]*\)], [3.4* | [4-9].* ],
-   critic_missing="$critic_missing gcc")
- AC_CHECK_PROG_VER(MAKE, gnumake gmake make, --version,
-   [GNU Make[^0-9]*\([0-9][0-9.]*\)],
index 814e1fa16f87d87333501796d7f3f7febc7469a5..0df859ad944884ed03c970bc6608007e749ead1a 100644 (file)
@@ -1,9 +1,30 @@
 #
 # Automatically generated file; DO NOT EDIT.
-# Crosstool-NG Configuration
-#
-CT_CONFIGURE_has_make381=y
-CT_CONFIGURE_has_xz=y
+# crosstool-NG  Configuration
+#
+CT_CONFIGURE_has_static_link=y
+CT_CONFIGURE_has_cxx11=y
+CT_CONFIGURE_has_wget=y
+CT_CONFIGURE_has_curl=y
+CT_CONFIGURE_has_make_3_81_or_newer=y
+CT_CONFIGURE_has_make_4_0_or_newer=y
+CT_CONFIGURE_has_libtool_2_4_or_newer=y
+CT_CONFIGURE_has_libtoolize_2_4_or_newer=y
+CT_CONFIGURE_has_autoconf_2_65_or_newer=y
+CT_CONFIGURE_has_autoreconf_2_65_or_newer=y
+CT_CONFIGURE_has_automake_1_15_or_newer=y
+CT_CONFIGURE_has_gnu_m4_1_4_12_or_newer=y
+CT_CONFIGURE_has_python_3_4_or_newer=y
+CT_CONFIGURE_has_bison_2_7_or_newer=y
+CT_CONFIGURE_has_python=y
+CT_CONFIGURE_has_git=y
+CT_CONFIGURE_has_md5sum=y
+CT_CONFIGURE_has_sha1sum=y
+CT_CONFIGURE_has_sha256sum=y
+CT_CONFIGURE_has_sha512sum=y
+CT_CONFIGURE_has_install_with_strip_program=y
+CT_CONFIG_VERSION_CURRENT="3"
+CT_CONFIG_VERSION="3"
 CT_MODULES=y
 
 #
@@ -20,42 +41,50 @@ CT_MODULES=y
 #
 # Paths
 #
-CT_LOCAL_TARBALLS_DIR=""
+CT_LOCAL_TARBALLS_DIR="${HOME}/src"
+CT_SAVE_TARBALLS=y
+# CT_TARBALLS_BUILDROOT_LAYOUT is not set
 CT_WORK_DIR="${CT_TOP_DIR}/.build"
+CT_BUILD_TOP_DIR="${CT_WORK_DIR:-${CT_TOP_DIR}/.build}/${CT_HOST:+HOST-${CT_HOST}/}${CT_TARGET}"
 CT_PREFIX_DIR="/x-tools/${CT_TARGET}"
-CT_INSTALL_DIR="${CT_PREFIX_DIR}"
 CT_RM_RF_PREFIX_DIR=y
 CT_REMOVE_DOCS=y
-CT_INSTALL_DIR_RO=y
+CT_INSTALL_LICENSES=y
+CT_PREFIX_DIR_RO=y
 CT_STRIP_HOST_TOOLCHAIN_EXECUTABLES=y
 # CT_STRIP_TARGET_TOOLCHAIN_EXECUTABLES is not set
 
 #
 # Downloading
 #
+CT_DOWNLOAD_AGENT_WGET=y
+# CT_DOWNLOAD_AGENT_CURL is not set
+# CT_DOWNLOAD_AGENT_NONE is not set
 # CT_FORBID_DOWNLOAD is not set
 # CT_FORCE_DOWNLOAD is not set
 CT_CONNECT_TIMEOUT=10
+CT_DOWNLOAD_WGET_OPTIONS="--passive-ftp --tries=3 -nc --progress=dot:binary"
 # CT_ONLY_DOWNLOAD is not set
 CT_USE_MIRROR=y
+# CT_FORCE_MIRROR is not set
 CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc"
+CT_VERIFY_DOWNLOAD_DIGEST=y
+CT_VERIFY_DOWNLOAD_DIGEST_SHA512=y
+# CT_VERIFY_DOWNLOAD_DIGEST_SHA256 is not set
+# CT_VERIFY_DOWNLOAD_DIGEST_SHA1 is not set
+# CT_VERIFY_DOWNLOAD_DIGEST_MD5 is not set
+CT_VERIFY_DOWNLOAD_DIGEST_ALG="sha512"
+# CT_VERIFY_DOWNLOAD_SIGNATURE is not set
 
 #
 # Extracting
 #
 # CT_FORCE_EXTRACT is not set
-CT_OVERIDE_CONFIG_GUESS_SUB=y
+CT_OVERRIDE_CONFIG_GUESS_SUB=y
 # CT_ONLY_EXTRACT is not set
-# CT_PATCH_BUNDLED is not set
-# CT_PATCH_LOCAL is not set
-CT_PATCH_BUNDLED_LOCAL=y
-# CT_PATCH_LOCAL_BUNDLED is not set
-# CT_PATCH_BUNDLED_FALLBACK_LOCAL is not set
-# CT_PATCH_LOCAL_FALLBACK_BUNDLED is not set
-# CT_PATCH_NONE is not set
-CT_PATCH_ORDER="bundled,local"
-CT_PATCH_USE_LOCAL=y
-CT_LOCAL_PATCH_DIR="/tmp/patches"
+CT_PATCH_BUNDLED=y
+# CT_PATCH_BUNDLED_LOCAL is not set
+CT_PATCH_ORDER="bundled"
 
 #
 # Build behavior
@@ -78,11 +107,11 @@ CT_CONFIG_SHELL="${bash}"
 #
 # CT_LOG_ERROR is not set
 # CT_LOG_WARN is not set
-CT_LOG_INFO=y
-# CT_LOG_EXTRA is not set
+# CT_LOG_INFO is not set
+CT_LOG_EXTRA=y
 # CT_LOG_ALL is not set
 # CT_LOG_DEBUG is not set
-CT_LOG_LEVEL_MAX="INFO"
+CT_LOG_LEVEL_MAX="EXTRA"
 # CT_LOG_SEE_TOOLS_WARN is not set
 CT_LOG_PROGRESS_BAR=y
 CT_LOG_TO_FILE=y
@@ -91,75 +120,69 @@ CT_LOG_FILE_COMPRESS=y
 #
 # Target options
 #
+# CT_ARCH_ALPHA is not set
+# CT_ARCH_ARC is not set
+# CT_ARCH_ARM is not set
+# CT_ARCH_AVR is not set
+# CT_ARCH_M68K is not set
+# CT_ARCH_MIPS is not set
+# CT_ARCH_NIOS2 is not set
+CT_ARCH_POWERPC=y
+# CT_ARCH_S390 is not set
+# CT_ARCH_SH is not set
+# CT_ARCH_SPARC is not set
+# CT_ARCH_X86 is not set
+# CT_ARCH_XTENSA is not set
 CT_ARCH="powerpc"
-CT_ARCH_SUPPORTS_BOTH_ENDIAN=y
-CT_ARCH_SUPPORTS_32=y
-CT_ARCH_SUPPORTS_64=y
-CT_ARCH_SUPPORTS_WITH_ABI=y
-CT_ARCH_SUPPORTS_WITH_CPU=y
-CT_ARCH_SUPPORTS_WITH_TUNE=y
-CT_ARCH_SUPPORTS_WITH_FLOAT=y
-CT_ARCH_DEFAULT_BE=y
-CT_ARCH_DEFAULT_32=y
-CT_ARCH_ABI=""
+CT_ARCH_CHOICE_KSYM="POWERPC"
 CT_ARCH_CPU="powerpc"
 CT_ARCH_TUNE=""
-CT_ARCH_BE=y
-# CT_ARCH_LE is not set
-CT_ARCH_32=y
-# CT_ARCH_64 is not set
-CT_ARCH_BITNESS=32
-# CT_ARCH_FLOAT_HW is not set
-# CT_ARCH_FLOAT_SW is not set
-CT_TARGET_CFLAGS=""
-CT_TARGET_LDFLAGS=""
-# CT_ARCH_alpha is not set
-# CT_ARCH_arm is not set
-# CT_ARCH_avr is not set
-# CT_ARCH_m68k is not set
-# CT_ARCH_mips is not set
-# CT_ARCH_nios2 is not set
-CT_ARCH_powerpc=y
-# CT_ARCH_s390 is not set
-# CT_ARCH_sh is not set
-# CT_ARCH_sparc is not set
-# CT_ARCH_x86 is not set
-# CT_ARCH_xtensa is not set
-CT_ARCH_alpha_AVAILABLE=y
-CT_ARCH_arm_AVAILABLE=y
-CT_ARCH_avr_AVAILABLE=y
-CT_ARCH_m68k_AVAILABLE=y
-CT_ARCH_microblaze_AVAILABLE=y
-CT_ARCH_mips_AVAILABLE=y
-CT_ARCH_nios2_AVAILABLE=y
-CT_ARCH_powerpc_AVAILABLE=y
-CT_ARCH_s390_AVAILABLE=y
-CT_ARCH_sh_AVAILABLE=y
-CT_ARCH_sparc_AVAILABLE=y
-CT_ARCH_x86_AVAILABLE=y
-CT_ARCH_xtensa_AVAILABLE=y
+CT_ARCH_POWERPC_SHOW=y
+
+#
+# Options for powerpc
+#
+CT_ARCH_POWERPC_PKG_KSYM=""
+CT_ARCH_powerpc_ABI=""
+CT_ARCH_powerpc_ABI_DEFAULT=y
+# CT_ARCH_powerpc_ABI_SPE is not set
+CT_ALL_ARCH_CHOICES="ALPHA ARC ARM AVR M68K MICROBLAZE MIPS MOXIE MSP430 NIOS2 POWERPC RISCV S390 SH SPARC X86 XTENSA"
 CT_ARCH_SUFFIX=""
+# CT_OMIT_TARGET_VENDOR is not set
 
 #
 # Generic target options
 #
 # CT_MULTILIB is not set
+CT_DEMULTILIB=y
 CT_ARCH_USE_MMU=y
+CT_ARCH_SUPPORTS_EITHER_ENDIAN=y
+CT_ARCH_DEFAULT_BE=y
+CT_ARCH_BE=y
+# CT_ARCH_LE is not set
 CT_ARCH_ENDIAN="big"
+CT_ARCH_SUPPORTS_32=y
+CT_ARCH_SUPPORTS_64=y
+CT_ARCH_DEFAULT_32=y
+CT_ARCH_BITNESS=32
+CT_ARCH_32=y
+# CT_ARCH_64 is not set
 
 #
 # Target optimisations
 #
+CT_ARCH_SUPPORTS_WITH_ABI=y
+CT_ARCH_SUPPORTS_WITH_CPU=y
+CT_ARCH_SUPPORTS_WITH_TUNE=y
+CT_ARCH_SUPPORTS_WITH_FLOAT=y
+CT_ARCH_ABI=""
 CT_ARCH_FLOAT_AUTO=y
+# CT_ARCH_FLOAT_HW is not set
+# CT_ARCH_FLOAT_SW is not set
+CT_TARGET_CFLAGS=""
+CT_TARGET_LDFLAGS=""
 CT_ARCH_FLOAT="auto"
 
-#
-# powerpc other options
-#
-CT_ARCH_powerpc_ABI=""
-CT_ARCH_powerpc_ABI_DEFAULT=y
-# CT_ARCH_powerpc_ABI_SPE is not set
-
 #
 # Toolchain options
 #
@@ -172,7 +195,9 @@ CT_USE_SYSROOT=y
 CT_SYSROOT_NAME="sysroot"
 CT_SYSROOT_DIR_PREFIX=""
 CT_WANTS_STATIC_LINK=y
+CT_WANTS_STATIC_LINK_CXX=y
 # CT_STATIC_TOOLCHAIN is not set
+CT_SHOW_CT_VERSION=y
 CT_TOOLCHAIN_PKGVERSION=""
 CT_TOOLCHAIN_BUGURL=""
 
@@ -206,122 +231,204 @@ CT_BUILD_SUFFIX=""
 # Operating System
 #
 CT_KERNEL_SUPPORTS_SHARED_LIBS=y
+# CT_KERNEL_BARE_METAL is not set
+CT_KERNEL_LINUX=y
 CT_KERNEL="linux"
-CT_KERNEL_VERSION="2.6.32.68"
-# CT_KERNEL_bare_metal is not set
-CT_KERNEL_linux=y
-CT_KERNEL_bare_metal_AVAILABLE=y
-CT_KERNEL_linux_AVAILABLE=y
-# CT_KERNEL_V_4_3 is not set
-# CT_KERNEL_V_4_2 is not set
-# CT_KERNEL_V_4_1 is not set
-# CT_KERNEL_V_3_18 is not set
-# CT_KERNEL_V_3_14 is not set
-# CT_KERNEL_V_3_12 is not set
-# CT_KERNEL_V_3_10 is not set
-# CT_KERNEL_V_3_4 is not set
-# CT_KERNEL_V_3_2 is not set
-CT_KERNEL_V_2_6_32=y
-# CT_KERNEL_LINUX_CUSTOM is not set
-CT_KERNEL_windows_AVAILABLE=y
-
-#
-# Common kernel options
-#
-CT_SHARED_LIBS=y
-
-#
-# linux other options
-#
+CT_KERNEL_CHOICE_KSYM="LINUX"
+CT_KERNEL_LINUX_SHOW=y
+
+#
+# Options for linux
+#
+CT_KERNEL_LINUX_PKG_KSYM="LINUX"
+CT_LINUX_DIR_NAME="linux"
+CT_LINUX_PKG_NAME="linux"
+CT_LINUX_SRC_RELEASE=y
+CT_LINUX_PATCH_ORDER="global"
+# CT_LINUX_V_4_20 is not set
+# CT_LINUX_V_4_19 is not set
+# CT_LINUX_V_4_18 is not set
+# CT_LINUX_V_4_17 is not set
+# CT_LINUX_V_4_16 is not set
+# CT_LINUX_V_4_15 is not set
+# CT_LINUX_V_4_14 is not set
+# CT_LINUX_V_4_13 is not set
+# CT_LINUX_V_4_12 is not set
+# CT_LINUX_V_4_11 is not set
+# CT_LINUX_V_4_10 is not set
+# CT_LINUX_V_4_9 is not set
+# CT_LINUX_V_4_4 is not set
+# CT_LINUX_V_4_1 is not set
+# CT_LINUX_V_3_16 is not set
+# CT_LINUX_V_3_13 is not set
+# CT_LINUX_V_3_12 is not set
+# CT_LINUX_V_3_10 is not set
+# CT_LINUX_V_3_4 is not set
+CT_LINUX_V_3_2=y
+# CT_LINUX_V_2_6_32 is not set
+# CT_LINUX_NO_VERSIONS is not set
+CT_LINUX_VERSION="3.2.101"
+CT_LINUX_MIRRORS="$(CT_Mirrors kernel.org linux ${CT_LINUX_VERSION})"
+CT_LINUX_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_LINUX_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_LINUX_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_LINUX_SIGNATURE_FORMAT="unpacked/.sign"
+CT_LINUX_4_8_or_older=y
+CT_LINUX_older_than_4_8=y
+CT_LINUX_3_7_or_older=y
+CT_LINUX_older_than_3_7=y
+CT_LINUX_later_than_3_2=y
+CT_LINUX_3_2_or_later=y
 CT_KERNEL_LINUX_VERBOSITY_0=y
 # CT_KERNEL_LINUX_VERBOSITY_1 is not set
 # CT_KERNEL_LINUX_VERBOSITY_2 is not set
 CT_KERNEL_LINUX_VERBOSE_LEVEL=0
 CT_KERNEL_LINUX_INSTALL_CHECK=y
+CT_ALL_KERNEL_CHOICES="BARE_METAL LINUX WINDOWS"
+
+#
+# Common kernel options
+#
+CT_SHARED_LIBS=y
 
 #
 # Binary utilities
 #
 CT_ARCH_BINFMT_ELF=y
+CT_BINUTILS_BINUTILS=y
 CT_BINUTILS="binutils"
-CT_BINUTILS_binutils=y
+CT_BINUTILS_CHOICE_KSYM="BINUTILS"
+CT_BINUTILS_BINUTILS_SHOW=y
+
+#
+# Options for binutils
+#
+CT_BINUTILS_BINUTILS_PKG_KSYM="BINUTILS"
+CT_BINUTILS_DIR_NAME="binutils"
+CT_BINUTILS_USE_GNU=y
+CT_BINUTILS_USE="BINUTILS"
+CT_BINUTILS_PKG_NAME="binutils"
+CT_BINUTILS_SRC_RELEASE=y
+CT_BINUTILS_PATCH_ORDER="global"
+# CT_BINUTILS_V_2_32 is not set
+# CT_BINUTILS_V_2_31 is not set
+CT_BINUTILS_V_2_30=y
+# CT_BINUTILS_V_2_29 is not set
+# CT_BINUTILS_V_2_28 is not set
+# CT_BINUTILS_V_2_27 is not set
+# CT_BINUTILS_V_2_26 is not set
+# CT_BINUTILS_NO_VERSIONS is not set
+CT_BINUTILS_VERSION="2.30"
+CT_BINUTILS_MIRRORS="$(CT_Mirrors GNU binutils) $(CT_Mirrors sourceware binutils/releases)"
+CT_BINUTILS_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_BINUTILS_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_BINUTILS_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_BINUTILS_SIGNATURE_FORMAT="packed/.sig"
+CT_BINUTILS_2_30_or_later=y
+CT_BINUTILS_2_30_or_older=y
+CT_BINUTILS_later_than_2_27=y
+CT_BINUTILS_2_27_or_later=y
+CT_BINUTILS_later_than_2_25=y
+CT_BINUTILS_2_25_or_later=y
+CT_BINUTILS_later_than_2_23=y
+CT_BINUTILS_2_23_or_later=y
 
 #
 # GNU binutils
 #
-# CT_CC_BINUTILS_SHOW_LINARO is not set
-CT_BINUTILS_V_2_25_1=y
-# CT_BINUTILS_V_2_25 is not set
-# CT_BINUTILS_V_2_24 is not set
-# CT_BINUTILS_V_2_23_2 is not set
-# CT_BINUTILS_V_2_23_1 is not set
-# CT_BINUTILS_V_2_22 is not set
-# CT_BINUTILS_V_2_21_53 is not set
-# CT_BINUTILS_V_2_21_1a is not set
-# CT_BINUTILS_V_2_20_1a is not set
-# CT_BINUTILS_V_2_19_1a is not set
-# CT_BINUTILS_V_2_18a is not set
-CT_BINUTILS_VERSION="2.25.1"
-CT_BINUTILS_2_25_1_or_later=y
-CT_BINUTILS_2_25_or_later=y
-CT_BINUTILS_2_24_or_later=y
-CT_BINUTILS_2_23_or_later=y
-CT_BINUTILS_2_22_or_later=y
-CT_BINUTILS_2_21_or_later=y
-CT_BINUTILS_2_20_or_later=y
-CT_BINUTILS_2_19_or_later=y
-CT_BINUTILS_2_18_or_later=y
 CT_BINUTILS_HAS_HASH_STYLE=y
 CT_BINUTILS_HAS_GOLD=y
 CT_BINUTILS_HAS_PLUGINS=y
 CT_BINUTILS_HAS_PKGVERSION_BUGURL=y
-CT_BINUTILS_FORCE_LD_BFD=y
+CT_BINUTILS_FORCE_LD_BFD_DEFAULT=y
 CT_BINUTILS_LINKER_LD=y
 CT_BINUTILS_LINKERS_LIST="ld"
 CT_BINUTILS_LINKER_DEFAULT="bfd"
 # CT_BINUTILS_PLUGINS is not set
+CT_BINUTILS_RELRO=m
 CT_BINUTILS_EXTRA_CONFIG_ARRAY=""
 # CT_BINUTILS_FOR_TARGET is not set
-
-#
-# binutils other options
-#
+CT_ALL_BINUTILS_CHOICES="BINUTILS"
 
 #
 # C-library
 #
+CT_LIBC_GLIBC=y
+# CT_LIBC_UCLIBC is not set
 CT_LIBC="glibc"
-CT_LIBC_VERSION="2.11.1"
-CT_LIBC_glibc=y
-# CT_LIBC_musl is not set
-# CT_LIBC_uClibc is not set
-CT_LIBC_avr_libc_AVAILABLE=y
-CT_LIBC_glibc_AVAILABLE=y
+CT_LIBC_CHOICE_KSYM="GLIBC"
 CT_THREADS="nptl"
-# CT_CC_GLIBC_SHOW_LINARO is not set
-# CT_LIBC_GLIBC_V_2_22 is not set
-# CT_LIBC_GLIBC_V_2_21 is not set
-# CT_LIBC_GLIBC_V_2_20 is not set
-# CT_LIBC_GLIBC_V_2_19 is not set
-# CT_LIBC_GLIBC_V_2_18 is not set
-# CT_LIBC_GLIBC_V_2_17 is not set
-# CT_LIBC_GLIBC_V_2_16_0 is not set
-# CT_LIBC_GLIBC_V_2_15 is not set
-# CT_LIBC_GLIBC_V_2_14_1 is not set
-# CT_LIBC_GLIBC_V_2_14 is not set
-# CT_LIBC_GLIBC_V_2_13 is not set
-# CT_LIBC_GLIBC_V_2_12_2 is not set
-# CT_LIBC_GLIBC_V_2_12_1 is not set
-CT_LIBC_GLIBC_V_2_11_1=y
-# CT_LIBC_GLIBC_V_2_11 is not set
-# CT_LIBC_GLIBC_V_2_10_1 is not set
-# CT_LIBC_GLIBC_V_2_9 is not set
-# CT_LIBC_GLIBC_V_2_8 is not set
-CT_LIBC_mingw_AVAILABLE=y
-CT_LIBC_musl_AVAILABLE=y
-CT_LIBC_newlib_AVAILABLE=y
-CT_LIBC_none_AVAILABLE=y
-CT_LIBC_uClibc_AVAILABLE=y
+CT_LIBC_GLIBC_SHOW=y
+
+#
+# Options for glibc
+#
+CT_LIBC_GLIBC_PKG_KSYM="GLIBC"
+CT_GLIBC_DIR_NAME="glibc"
+CT_GLIBC_USE_GNU=y
+CT_GLIBC_USE="GLIBC"
+CT_GLIBC_PKG_NAME="glibc"
+CT_GLIBC_SRC_RELEASE=y
+CT_GLIBC_PATCH_ORDER="global"
+# CT_GLIBC_V_2_29 is not set
+# CT_GLIBC_V_2_28 is not set
+# CT_GLIBC_V_2_27 is not set
+# CT_GLIBC_V_2_26 is not set
+# CT_GLIBC_V_2_25 is not set
+# CT_GLIBC_V_2_24 is not set
+# CT_GLIBC_V_2_23 is not set
+# CT_GLIBC_V_2_19 is not set
+CT_GLIBC_V_2_17=y
+# CT_GLIBC_V_2_12_1 is not set
+# CT_GLIBC_NO_VERSIONS is not set
+CT_GLIBC_VERSION="2.17"
+CT_GLIBC_MIRRORS="$(CT_Mirrors GNU glibc)"
+CT_GLIBC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GLIBC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GLIBC_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_GLIBC_SIGNATURE_FORMAT="packed/.sig"
+CT_GLIBC_2_29_or_older=y
+CT_GLIBC_older_than_2_29=y
+CT_GLIBC_2_27_or_older=y
+CT_GLIBC_older_than_2_27=y
+CT_GLIBC_2_26_or_older=y
+CT_GLIBC_older_than_2_26=y
+CT_GLIBC_2_25_or_older=y
+CT_GLIBC_older_than_2_25=y
+CT_GLIBC_2_24_or_older=y
+CT_GLIBC_older_than_2_24=y
+CT_GLIBC_2_23_or_older=y
+CT_GLIBC_older_than_2_23=y
+CT_GLIBC_2_20_or_older=y
+CT_GLIBC_older_than_2_20=y
+CT_GLIBC_2_17_or_later=y
+CT_GLIBC_2_17_or_older=y
+CT_GLIBC_later_than_2_14=y
+CT_GLIBC_2_14_or_later=y
+CT_GLIBC_DEP_KERNEL_HEADERS_VERSION=y
+CT_GLIBC_DEP_BINUTILS=y
+CT_GLIBC_DEP_GCC=y
+CT_GLIBC_DEP_PYTHON=y
+CT_GLIBC_HAS_NPTL_ADDON=y
+CT_GLIBC_HAS_PORTS_ADDON=y
+CT_GLIBC_HAS_LIBIDN_ADDON=y
+CT_GLIBC_USE_PORTS_ADDON=y
+CT_GLIBC_USE_NPTL_ADDON=y
+# CT_GLIBC_USE_LIBIDN_ADDON is not set
+CT_GLIBC_HAS_OBSOLETE_RPC=y
+CT_GLIBC_EXTRA_CONFIG_ARRAY=""
+CT_GLIBC_CONFIGPARMS=""
+CT_GLIBC_EXTRA_CFLAGS=""
+CT_GLIBC_ENABLE_OBSOLETE_RPC=y
+# CT_GLIBC_DISABLE_VERSIONING is not set
+CT_GLIBC_OLDEST_ABI=""
+CT_GLIBC_FORCE_UNWIND=y
+# CT_GLIBC_LOCALES is not set
+# CT_GLIBC_KERNEL_VERSION_NONE is not set
+CT_GLIBC_KERNEL_VERSION_AS_HEADERS=y
+# CT_GLIBC_KERNEL_VERSION_CHOSEN is not set
+CT_GLIBC_MIN_KERNEL="3.2.101"
+CT_ALL_LIBC_CHOICES="AVR_LIBC BIONIC GLIBC MINGW_W64 MOXIEBOX MUSL NEWLIB NONE UCLIBC"
 CT_LIBC_SUPPORT_THREADS_ANY=y
 CT_LIBC_SUPPORT_THREADS_NATIVE=y
 
@@ -329,79 +436,71 @@ CT_LIBC_SUPPORT_THREADS_NATIVE=y
 # Common C library options
 #
 CT_THREADS_NATIVE=y
+# CT_CREATE_LDSO_CONF is not set
 CT_LIBC_XLDD=y
 
-#
-# glibc other options
-#
-CT_LIBC_GLIBC_PORTS_EXTERNAL=y
-CT_LIBC_glibc_familly=y
-CT_LIBC_GLIBC_EXTRA_CONFIG_ARRAY=""
-CT_LIBC_GLIBC_CONFIGPARMS=""
-CT_LIBC_GLIBC_EXTRA_CFLAGS=""
-CT_LIBC_EXTRA_CC_ARGS=""
-# CT_LIBC_DISABLE_VERSIONING is not set
-CT_LIBC_OLDEST_ABI=""
-CT_LIBC_GLIBC_FORCE_UNWIND=y
-# CT_LIBC_GLIBC_USE_PORTS is not set
-CT_LIBC_ADDONS_LIST=""
-# CT_LIBC_LOCALES is not set
-# CT_LIBC_GLIBC_KERNEL_VERSION_NONE is not set
-CT_LIBC_GLIBC_KERNEL_VERSION_AS_HEADERS=y
-# CT_LIBC_GLIBC_KERNEL_VERSION_CHOSEN is not set
-CT_LIBC_GLIBC_MIN_KERNEL="2.6.32.68"
-
 #
 # C compiler
 #
-CT_CC="gcc"
 CT_CC_CORE_PASSES_NEEDED=y
 CT_CC_CORE_PASS_1_NEEDED=y
 CT_CC_CORE_PASS_2_NEEDED=y
-CT_CC_gcc=y
-# CT_CC_GCC_SHOW_LINARO is not set
-CT_CC_GCC_V_5_2_0=y
-# CT_CC_GCC_V_4_9_3 is not set
-# CT_CC_GCC_V_4_8_5 is not set
-# CT_CC_GCC_V_4_7_4 is not set
-# CT_CC_GCC_V_4_6_4 is not set
-# CT_CC_GCC_V_4_5_4 is not set
-# CT_CC_GCC_V_4_4_7 is not set
-# CT_CC_GCC_V_4_3_6 is not set
-# CT_CC_GCC_V_4_2_4 is not set
-CT_CC_GCC_4_2_or_later=y
-CT_CC_GCC_4_3_or_later=y
-CT_CC_GCC_4_4_or_later=y
-CT_CC_GCC_4_5_or_later=y
-CT_CC_GCC_4_6_or_later=y
-CT_CC_GCC_4_7_or_later=y
-CT_CC_GCC_4_8_or_later=y
-CT_CC_GCC_4_9_or_later=y
-CT_CC_GCC_5=y
-CT_CC_GCC_5_or_later=y
-CT_CC_GCC_HAS_GRAPHITE=y
-CT_CC_GCC_USE_GRAPHITE=y
-CT_CC_GCC_HAS_LTO=y
-CT_CC_GCC_USE_LTO=y
-CT_CC_GCC_HAS_PKGVERSION_BUGURL=y
-CT_CC_GCC_HAS_BUILD_ID=y
-CT_CC_GCC_HAS_LNK_HASH_STYLE=y
-CT_CC_GCC_USE_GMP_MPFR=y
-CT_CC_GCC_USE_MPC=y
-CT_CC_GCC_HAS_LIBQUADMATH=y
-CT_CC_GCC_HAS_LIBSANITIZER=y
-CT_CC_GCC_VERSION="5.2.0"
-# CT_CC_LANG_FORTRAN is not set
+CT_CC_SUPPORT_CXX=y
+CT_CC_SUPPORT_FORTRAN=y
+CT_CC_SUPPORT_ADA=y
+CT_CC_SUPPORT_OBJC=y
+CT_CC_SUPPORT_OBJCXX=y
+CT_CC_SUPPORT_GOLANG=y
+CT_CC_GCC=y
+CT_CC="gcc"
+CT_CC_CHOICE_KSYM="GCC"
+CT_CC_GCC_SHOW=y
+
+#
+# Options for gcc
+#
+CT_CC_GCC_PKG_KSYM="GCC"
+CT_GCC_DIR_NAME="gcc"
+CT_GCC_USE_GNU=y
+CT_GCC_USE="GCC"
+CT_GCC_PKG_NAME="gcc"
+CT_GCC_SRC_RELEASE=y
+CT_GCC_PATCH_ORDER="global"
+CT_GCC_V_8=y
+# CT_GCC_V_7 is not set
+# CT_GCC_V_6 is not set
+# CT_GCC_V_5 is not set
+# CT_GCC_V_4_9 is not set
+# CT_GCC_NO_VERSIONS is not set
+CT_GCC_VERSION="8.3.0"
+CT_GCC_MIRRORS="$(CT_Mirrors GNU gcc/gcc-${CT_GCC_VERSION}) $(CT_Mirrors sourceware gcc/releases/gcc-${CT_GCC_VERSION})"
+CT_GCC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GCC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GCC_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_GCC_SIGNATURE_FORMAT=""
+CT_GCC_later_than_7=y
+CT_GCC_7_or_later=y
+CT_GCC_later_than_6=y
+CT_GCC_6_or_later=y
+CT_GCC_later_than_5=y
+CT_GCC_5_or_later=y
+CT_GCC_later_than_4_9=y
+CT_GCC_4_9_or_later=y
+CT_GCC_later_than_4_8=y
+CT_GCC_4_8_or_later=y
+CT_CC_GCC_HAS_LIBMPX=y
 CT_CC_GCC_ENABLE_CXX_FLAGS=""
 CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY=""
 CT_CC_GCC_EXTRA_CONFIG_ARRAY=""
-CT_CC_GCC_EXTRA_ENV_ARRAY=""
 CT_CC_GCC_STATIC_LIBSTDCXX=y
 # CT_CC_GCC_SYSTEM_ZLIB is not set
+CT_CC_GCC_CONFIG_TLS=m
 
 #
 # Optimisation features
 #
+CT_CC_GCC_USE_GRAPHITE=y
+CT_CC_GCC_USE_LTO=y
 
 #
 # Settings for libraries running on target
@@ -430,97 +529,208 @@ CT_CC_GCC_DEC_FLOAT_AUTO=y
 # CT_CC_GCC_DEC_FLOAT_BID is not set
 # CT_CC_GCC_DEC_FLOAT_DPD is not set
 # CT_CC_GCC_DEC_FLOATS_NO is not set
-CT_CC_SUPPORT_CXX=y
-CT_CC_SUPPORT_FORTRAN=y
-CT_CC_SUPPORT_JAVA=y
-CT_CC_SUPPORT_ADA=y
-CT_CC_SUPPORT_OBJC=y
-CT_CC_SUPPORT_OBJCXX=y
-CT_CC_SUPPORT_GOLANG=y
+CT_ALL_CC_CHOICES="GCC"
 
 #
 # Additional supported languages:
 #
 CT_CC_LANG_CXX=y
-# CT_CC_LANG_JAVA is not set
+# CT_CC_LANG_FORTRAN is not set
 
 #
 # Debug facilities
 #
-# CT_DEBUG_dmalloc is not set
-# CT_DEBUG_duma is not set
-# CT_DEBUG_gdb is not set
-# CT_DEBUG_ltrace is not set
-# CT_DEBUG_strace is not set
+# CT_DEBUG_DUMA is not set
+# CT_DEBUG_GDB is not set
+# CT_DEBUG_LTRACE is not set
+# CT_DEBUG_STRACE is not set
+CT_ALL_DEBUG_CHOICES="DUMA GDB LTRACE STRACE"
 
 #
 # Companion libraries
 #
-CT_COMPLIBS_NEEDED=y
+# CT_COMPLIBS_CHECK is not set
+# CT_COMP_LIBS_CLOOG is not set
+# CT_COMP_LIBS_EXPAT is not set
+CT_COMP_LIBS_GETTEXT=y
+CT_COMP_LIBS_GETTEXT_PKG_KSYM="GETTEXT"
+CT_GETTEXT_DIR_NAME="gettext"
+CT_GETTEXT_PKG_NAME="gettext"
+CT_GETTEXT_SRC_RELEASE=y
+CT_GETTEXT_PATCH_ORDER="global"
+CT_GETTEXT_V_0_19_8_1=y
+# CT_GETTEXT_NO_VERSIONS is not set
+CT_GETTEXT_VERSION="0.19.8.1"
+CT_GETTEXT_MIRRORS="$(CT_Mirrors GNU gettext)"
+CT_GETTEXT_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GETTEXT_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GETTEXT_ARCHIVE_FORMATS=".tar.xz .tar.lz .tar.gz"
+CT_GETTEXT_SIGNATURE_FORMAT="packed/.sig"
+CT_COMP_LIBS_GMP=y
+CT_COMP_LIBS_GMP_PKG_KSYM="GMP"
+CT_GMP_DIR_NAME="gmp"
+CT_GMP_PKG_NAME="gmp"
+CT_GMP_SRC_RELEASE=y
+CT_GMP_PATCH_ORDER="global"
+CT_GMP_V_6_1=y
+# CT_GMP_NO_VERSIONS is not set
+CT_GMP_VERSION="6.1.2"
+CT_GMP_MIRRORS="https://gmplib.org/download/gmp https://gmplib.org/download/gmp/archive $(CT_Mirrors GNU gmp)"
+CT_GMP_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GMP_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GMP_ARCHIVE_FORMATS=".tar.xz .tar.lz .tar.bz2"
+CT_GMP_SIGNATURE_FORMAT="packed/.sig"
+CT_GMP_later_than_5_1_0=y
+CT_GMP_5_1_0_or_later=y
+CT_GMP_later_than_5_0_0=y
+CT_GMP_5_0_0_or_later=y
+CT_GMP_REQUIRE_5_0_0_or_later=y
+CT_COMP_LIBS_ISL=y
+CT_COMP_LIBS_ISL_PKG_KSYM="ISL"
+CT_ISL_DIR_NAME="isl"
+CT_ISL_PKG_NAME="isl"
+CT_ISL_SRC_RELEASE=y
+CT_ISL_PATCH_ORDER="global"
+CT_ISL_V_0_20=y
+# CT_ISL_V_0_19 is not set
+# CT_ISL_V_0_18 is not set
+# CT_ISL_V_0_17 is not set
+# CT_ISL_V_0_16 is not set
+# CT_ISL_V_0_15 is not set
+# CT_ISL_NO_VERSIONS is not set
+CT_ISL_VERSION="0.20"
+CT_ISL_MIRRORS="http://isl.gforge.inria.fr"
+CT_ISL_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_ISL_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_ISL_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_ISL_SIGNATURE_FORMAT=""
+CT_ISL_later_than_0_18=y
+CT_ISL_0_18_or_later=y
+CT_ISL_later_than_0_15=y
+CT_ISL_0_15_or_later=y
+CT_ISL_REQUIRE_0_15_or_later=y
+CT_ISL_later_than_0_14=y
+CT_ISL_0_14_or_later=y
+CT_ISL_REQUIRE_0_14_or_later=y
+CT_ISL_later_than_0_13=y
+CT_ISL_0_13_or_later=y
+CT_ISL_later_than_0_12=y
+CT_ISL_0_12_or_later=y
+CT_ISL_REQUIRE_0_12_or_later=y
+# CT_COMP_LIBS_LIBELF is not set
+CT_COMP_LIBS_LIBICONV=y
+CT_COMP_LIBS_LIBICONV_PKG_KSYM="LIBICONV"
+CT_LIBICONV_DIR_NAME="libiconv"
+CT_LIBICONV_PKG_NAME="libiconv"
+CT_LIBICONV_SRC_RELEASE=y
+CT_LIBICONV_PATCH_ORDER="global"
+CT_LIBICONV_V_1_15=y
+# CT_LIBICONV_NO_VERSIONS is not set
+CT_LIBICONV_VERSION="1.15"
+CT_LIBICONV_MIRRORS="$(CT_Mirrors GNU libiconv)"
+CT_LIBICONV_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_LIBICONV_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_LIBICONV_ARCHIVE_FORMATS=".tar.gz"
+CT_LIBICONV_SIGNATURE_FORMAT="packed/.sig"
+CT_COMP_LIBS_MPC=y
+CT_COMP_LIBS_MPC_PKG_KSYM="MPC"
+CT_MPC_DIR_NAME="mpc"
+CT_MPC_PKG_NAME="mpc"
+CT_MPC_SRC_RELEASE=y
+CT_MPC_PATCH_ORDER="global"
+CT_MPC_V_1_1=y
+# CT_MPC_V_1_0 is not set
+# CT_MPC_NO_VERSIONS is not set
+CT_MPC_VERSION="1.1.0"
+CT_MPC_MIRRORS="http://www.multiprecision.org/downloads $(CT_Mirrors GNU mpc)"
+CT_MPC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_MPC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_MPC_ARCHIVE_FORMATS=".tar.gz"
+CT_MPC_SIGNATURE_FORMAT="packed/.sig"
+CT_MPC_1_1_0_or_later=y
+CT_MPC_1_1_0_or_older=y
+CT_COMP_LIBS_MPFR=y
+CT_COMP_LIBS_MPFR_PKG_KSYM="MPFR"
+CT_MPFR_DIR_NAME="mpfr"
+CT_MPFR_PKG_NAME="mpfr"
+CT_MPFR_SRC_RELEASE=y
+CT_MPFR_PATCH_ORDER="global"
+CT_MPFR_V_4_0=y
+# CT_MPFR_V_3_1 is not set
+# CT_MPFR_NO_VERSIONS is not set
+CT_MPFR_VERSION="4.0.2"
+CT_MPFR_MIRRORS="http://www.mpfr.org/mpfr-${CT_MPFR_VERSION} $(CT_Mirrors GNU mpfr)"
+CT_MPFR_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_MPFR_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_MPFR_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz .zip"
+CT_MPFR_SIGNATURE_FORMAT="packed/.asc"
+CT_MPFR_later_than_4_0_0=y
+CT_MPFR_4_0_0_or_later=y
+CT_MPFR_later_than_3_0_0=y
+CT_MPFR_3_0_0_or_later=y
+CT_MPFR_REQUIRE_3_0_0_or_later=y
+CT_COMP_LIBS_NCURSES=y
+CT_COMP_LIBS_NCURSES_PKG_KSYM="NCURSES"
+CT_NCURSES_DIR_NAME="ncurses"
+CT_NCURSES_PKG_NAME="ncurses"
+CT_NCURSES_SRC_RELEASE=y
+CT_NCURSES_PATCH_ORDER="global"
+CT_NCURSES_V_6_1=y
+# CT_NCURSES_V_6_0 is not set
+# CT_NCURSES_NO_VERSIONS is not set
+CT_NCURSES_VERSION="6.1"
+CT_NCURSES_MIRRORS="ftp://invisible-island.net/ncurses $(CT_Mirrors GNU ncurses)"
+CT_NCURSES_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_NCURSES_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_NCURSES_ARCHIVE_FORMATS=".tar.gz"
+CT_NCURSES_SIGNATURE_FORMAT="packed/.sig"
+CT_NCURSES_HOST_CONFIG_ARGS=""
+CT_NCURSES_HOST_DISABLE_DB=y
+CT_NCURSES_HOST_FALLBACKS="linux,xterm,xterm-color,xterm-256color,vt100"
+CT_NCURSES_TARGET_CONFIG_ARGS=""
+# CT_NCURSES_TARGET_DISABLE_DB is not set
+CT_NCURSES_TARGET_FALLBACKS=""
+CT_COMP_LIBS_ZLIB=y
+CT_COMP_LIBS_ZLIB_PKG_KSYM="ZLIB"
+CT_ZLIB_DIR_NAME="zlib"
+CT_ZLIB_PKG_NAME="zlib"
+CT_ZLIB_SRC_RELEASE=y
+CT_ZLIB_PATCH_ORDER="global"
+CT_ZLIB_V_1_2_11=y
+# CT_ZLIB_NO_VERSIONS is not set
+CT_ZLIB_VERSION="1.2.11"
+CT_ZLIB_MIRRORS="http://downloads.sourceforge.net/project/libpng/zlib/${CT_ZLIB_VERSION}"
+CT_ZLIB_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_ZLIB_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_ZLIB_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_ZLIB_SIGNATURE_FORMAT="packed/.asc"
+CT_ALL_COMP_LIBS_CHOICES="CLOOG EXPAT GETTEXT GMP ISL LIBELF LIBICONV MPC MPFR NCURSES ZLIB"
 CT_LIBICONV_NEEDED=y
 CT_GETTEXT_NEEDED=y
 CT_GMP_NEEDED=y
 CT_MPFR_NEEDED=y
 CT_ISL_NEEDED=y
 CT_MPC_NEEDED=y
-CT_COMPLIBS=y
+CT_NCURSES_NEEDED=y
+CT_ZLIB_NEEDED=y
 CT_LIBICONV=y
 CT_GETTEXT=y
 CT_GMP=y
 CT_MPFR=y
 CT_ISL=y
 CT_MPC=y
-CT_LIBICONV_V_1_14=y
-CT_LIBICONV_VERSION="1.14"
-CT_GETTEXT_V_0_19_6=y
-CT_GETTEXT_VERSION="0.19.6"
-CT_GMP_V_6_0_0=y
-# CT_GMP_V_5_1_3 is not set
-# CT_GMP_V_5_1_1 is not set
-# CT_GMP_V_5_0_2 is not set
-# CT_GMP_V_5_0_1 is not set
-# CT_GMP_V_4_3_2 is not set
-# CT_GMP_V_4_3_1 is not set
-# CT_GMP_V_4_3_0 is not set
-CT_GMP_5_0_2_or_later=y
-CT_GMP_VERSION="6.0.0a"
-CT_MPFR_V_3_1_3=y
-# CT_MPFR_V_3_1_2 is not set
-# CT_MPFR_V_3_1_0 is not set
-# CT_MPFR_V_3_0_1 is not set
-# CT_MPFR_V_3_0_0 is not set
-# CT_MPFR_V_2_4_2 is not set
-# CT_MPFR_V_2_4_1 is not set
-# CT_MPFR_V_2_4_0 is not set
-CT_MPFR_VERSION="3.1.3"
-CT_ISL_V_0_14=y
-# CT_ISL_V_0_12_2 is not set
-CT_ISL_V_0_14_or_later=y
-CT_ISL_V_0_12_or_later=y
-CT_ISL_VERSION="0.14"
-# CT_CLOOG_V_0_18_4 is not set
-# CT_CLOOG_V_0_18_1 is not set
-# CT_CLOOG_V_0_18_0 is not set
-CT_MPC_V_1_0_3=y
-# CT_MPC_V_1_0_2 is not set
-# CT_MPC_V_1_0_1 is not set
-# CT_MPC_V_1_0 is not set
-# CT_MPC_V_0_9 is not set
-# CT_MPC_V_0_8_2 is not set
-# CT_MPC_V_0_8_1 is not set
-# CT_MPC_V_0_7 is not set
-CT_MPC_VERSION="1.0.3"
-
-#
-# Companion libraries common options
-#
-# CT_COMPLIBS_CHECK is not set
+CT_NCURSES=y
+CT_ZLIB=y
 
 #
 # Companion tools
 #
-
-#
-# READ HELP before you say 'Y' below !!!
-#
-# CT_COMP_TOOLS is not set
+# CT_COMP_TOOLS_FOR_HOST is not set
+# CT_COMP_TOOLS_AUTOCONF is not set
+# CT_COMP_TOOLS_AUTOMAKE is not set
+# CT_COMP_TOOLS_BISON is not set
+# CT_COMP_TOOLS_DTC is not set
+# CT_COMP_TOOLS_LIBTOOL is not set
+# CT_COMP_TOOLS_M4 is not set
+# CT_COMP_TOOLS_MAKE is not set
+CT_ALL_COMP_TOOLS_CHOICES="AUTOCONF AUTOMAKE BISON DTC LIBTOOL M4 MAKE"
index a22d9a7553ecfbf87b92ce8a313bbcbe94bafb22..c976536cb7c5db4a324f4314ef3240a815e1ac73 100644 (file)
@@ -1,23 +1,16 @@
-FROM ubuntu:16.04
+FROM ubuntu:20.04
 
 COPY scripts/cross-apt-packages.sh /scripts/
 RUN sh /scripts/cross-apt-packages.sh
 
-
-# Ubuntu 16.04 (this container) ships with make 4, but something in the
-# toolchains we build below chokes on that, so go back to make 3
-COPY scripts/make3.sh /scripts/
-RUN sh /scripts/make3.sh
-
-COPY scripts/crosstool-ng.sh /scripts/
-RUN sh /scripts/crosstool-ng.sh
+COPY scripts/crosstool-ng-1.24.sh /scripts/
+RUN sh /scripts/crosstool-ng-1.24.sh
 
 COPY scripts/rustbuild-setup.sh /scripts/
 RUN sh /scripts/rustbuild-setup.sh
 USER rustbuild
 WORKDIR /tmp
 
-COPY host-x86_64/dist-powerpc64-linux/patches/ /tmp/patches/
 COPY host-x86_64/dist-powerpc64-linux/shared.sh host-x86_64/dist-powerpc64-linux/powerpc64-linux-gnu.config host-x86_64/dist-powerpc64-linux/build-powerpc64-toolchain.sh /tmp/
 RUN ./build-powerpc64-toolchain.sh
 
@@ -26,9 +19,6 @@ USER root
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
-
 ENV PATH=$PATH:/x-tools/powerpc64-unknown-linux-gnu/bin
 
 ENV \
index fc53849a2ada41f6094b3793e96b093d8ffc606a..f7aa2cd326832b52495d5ea40d3e9891b828251e 100755 (executable)
@@ -3,29 +3,9 @@ set -ex
 
 source shared.sh
 
-BINUTILS=2.32
-TARGET=powerpc64-unknown-linux-gnu
-PREFIX=/x-tools/$TARGET
-SYSROOT=$PREFIX/$TARGET/sysroot
-
 mkdir build
 cd build
 cp ../powerpc64-linux-gnu.config .config
 hide_output ct-ng build
 cd ..
 rm -rf build
-
-chmod -R u+w $PREFIX
-
-# Next, download and build newer binutils.
-mkdir binutils-$TARGET
-pushd binutils-$TARGET
-curl https://ftp.gnu.org/gnu/binutils/binutils-$BINUTILS.tar.bz2 | tar xjf -
-mkdir binutils-build
-cd binutils-build
-hide_output ../binutils-$BINUTILS/configure --target=$TARGET \
-  --prefix=$PREFIX --with-sysroot=$SYSROOT
-hide_output make -j10
-hide_output make install
-popd
-rm -rf binutils-$TARGET
diff --git a/src/ci/docker/host-x86_64/dist-powerpc64-linux/patches/glibc/2.11.1/001-PowerPC-Remove-unnecessary-mnew-mnemonics.patch b/src/ci/docker/host-x86_64/dist-powerpc64-linux/patches/glibc/2.11.1/001-PowerPC-Remove-unnecessary-mnew-mnemonics.patch
deleted file mode 100644 (file)
index 744eb18..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-From b3563932f85d60bb0d38b0a5f3b8f4abc133f890 Mon Sep 17 00:00:00 2001
-From: Tulio Magno Quites Machado Filho <tuliom@linux.vnet.ibm.com>
-Date: Thu, 1 Nov 2012 18:00:06 -0500
-Subject: [PATCH] PowerPC: Remove unnecessary -mnew-mnemonics.
-
----
- sysdeps/powerpc/Makefile | 4 ----
- 1 file changed, 4 deletions(-)
-
-diff --git a/sysdeps/powerpc/Makefile b/sysdeps/powerpc/Makefile
-index 79dd6fa976d5..7442b6709ad1 100644
---- a/sysdeps/powerpc/Makefile
-+++ b/sysdeps/powerpc/Makefile
-@@ -1,7 +1,3 @@
--# We always want to use the new mnemonic syntax even if we are on a RS6000
--# machine.
--+cflags += -mnew-mnemonics
--
- ifeq ($(subdir),gmon)
- sysdep_routines += ppc-mcount
- endif
--- 
-2.9.3
-
diff --git a/src/ci/docker/host-x86_64/dist-powerpc64-linux/patches/glibc/2.11.1/002-Prevent-inlining-in-PPC64-initfini.s.patch b/src/ci/docker/host-x86_64/dist-powerpc64-linux/patches/glibc/2.11.1/002-Prevent-inlining-in-PPC64-initfini.s.patch
deleted file mode 100644 (file)
index 47cc8b2..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-From a4f388e111ce05e2ab7912cff3c9070334bb74ae Mon Sep 17 00:00:00 2001
-From: Josh Stone <jistone@redhat.com>
-Date: Fri, 20 Jan 2017 15:41:56 -0800
-Subject: [PATCH] Prevent inlining in PPC64 initfini.s
-
-Ref: https://sourceware.org/ml/libc-alpha/2012-01/msg00195.html
----
- sysdeps/powerpc/powerpc64/Makefile | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/sysdeps/powerpc/powerpc64/Makefile b/sysdeps/powerpc/powerpc64/Makefile
-index 78d4f07e575f..fe96aae4d43e 100644
---- a/sysdeps/powerpc/powerpc64/Makefile
-+++ b/sysdeps/powerpc/powerpc64/Makefile
-@@ -28,7 +28,7 @@ elide-routines.os += hp-timing
- ifneq ($(elf),no)
- # The initfini generation code doesn't work in the presence of -fPIC, so
- # we use -fpic instead which is much better.
--CFLAGS-initfini.s += -fpic -O1
-+CFLAGS-initfini.s += -fpic -O1 -fno-inline
- endif
- endif
--- 
-2.9.3
-
diff --git a/src/ci/docker/host-x86_64/dist-powerpc64-linux/patches/glibc/2.11.1/003-newer-gcc.patch b/src/ci/docker/host-x86_64/dist-powerpc64-linux/patches/glibc/2.11.1/003-newer-gcc.patch
deleted file mode 100644 (file)
index a96b488..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-diff --git a/configure b/configure
-index b6752d147c6b..6089a3403410 100755
---- a/configure
-+++ b/configure
-@@ -5079,7 +5079,7 @@ $as_echo_n "checking version of $CC... " >&6; }
-   ac_prog_version=`$CC -v 2>&1 | sed -n 's/^.*version \([egcygnustpi-]*[0-9.]*\).*$/\1/p'`
-   case $ac_prog_version in
-     '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
--    3.4* | 4.[0-9]* )
-+    3.4* | [4-9].* )
-        ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;;
-     *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;;
-diff --git a/configure.in b/configure.in
-index 56849dfc489a..09677eb3d0c1 100644
---- a/configure.in
-+++ b/configure.in
-@@ -960,7 +960,7 @@ fi
- # These programs are version sensitive.
- AC_CHECK_TOOL_PREFIX
- AC_CHECK_PROG_VER(CC, ${ac_tool_prefix}gcc ${ac_tool_prefix}cc, -v,
--  [version \([egcygnustpi-]*[0-9.]*\)], [3.4* | 4.[0-9]* ],
-+  [version \([egcygnustpi-]*[0-9.]*\)], [3.4* | [4-9].* ],
-   critic_missing="$critic_missing gcc")
- AC_CHECK_PROG_VER(MAKE, gnumake gmake make, --version,
-   [GNU Make[^0-9]*\([0-9][0-9.]*\)],
index 83439bb81e23d084dcf1c2b17cc1c2a59b270096..d3293eab2bed69d829c11e4a43e794b5c2b3087f 100644 (file)
@@ -1,9 +1,30 @@
 #
 # Automatically generated file; DO NOT EDIT.
-# Crosstool-NG Configuration
-#
-CT_CONFIGURE_has_make381=y
-CT_CONFIGURE_has_xz=y
+# crosstool-NG  Configuration
+#
+CT_CONFIGURE_has_static_link=y
+CT_CONFIGURE_has_cxx11=y
+CT_CONFIGURE_has_wget=y
+CT_CONFIGURE_has_curl=y
+CT_CONFIGURE_has_make_3_81_or_newer=y
+CT_CONFIGURE_has_make_4_0_or_newer=y
+CT_CONFIGURE_has_libtool_2_4_or_newer=y
+CT_CONFIGURE_has_libtoolize_2_4_or_newer=y
+CT_CONFIGURE_has_autoconf_2_65_or_newer=y
+CT_CONFIGURE_has_autoreconf_2_65_or_newer=y
+CT_CONFIGURE_has_automake_1_15_or_newer=y
+CT_CONFIGURE_has_gnu_m4_1_4_12_or_newer=y
+CT_CONFIGURE_has_python_3_4_or_newer=y
+CT_CONFIGURE_has_bison_2_7_or_newer=y
+CT_CONFIGURE_has_python=y
+CT_CONFIGURE_has_git=y
+CT_CONFIGURE_has_md5sum=y
+CT_CONFIGURE_has_sha1sum=y
+CT_CONFIGURE_has_sha256sum=y
+CT_CONFIGURE_has_sha512sum=y
+CT_CONFIGURE_has_install_with_strip_program=y
+CT_CONFIG_VERSION_CURRENT="3"
+CT_CONFIG_VERSION="3"
 CT_MODULES=y
 
 #
@@ -20,42 +41,50 @@ CT_MODULES=y
 #
 # Paths
 #
-CT_LOCAL_TARBALLS_DIR=""
+CT_LOCAL_TARBALLS_DIR="${HOME}/src"
+CT_SAVE_TARBALLS=y
+# CT_TARBALLS_BUILDROOT_LAYOUT is not set
 CT_WORK_DIR="${CT_TOP_DIR}/.build"
+CT_BUILD_TOP_DIR="${CT_WORK_DIR:-${CT_TOP_DIR}/.build}/${CT_HOST:+HOST-${CT_HOST}/}${CT_TARGET}"
 CT_PREFIX_DIR="/x-tools/${CT_TARGET}"
-CT_INSTALL_DIR="${CT_PREFIX_DIR}"
 CT_RM_RF_PREFIX_DIR=y
 CT_REMOVE_DOCS=y
-CT_INSTALL_DIR_RO=y
+CT_INSTALL_LICENSES=y
+CT_PREFIX_DIR_RO=y
 CT_STRIP_HOST_TOOLCHAIN_EXECUTABLES=y
 # CT_STRIP_TARGET_TOOLCHAIN_EXECUTABLES is not set
 
 #
 # Downloading
 #
+CT_DOWNLOAD_AGENT_WGET=y
+# CT_DOWNLOAD_AGENT_CURL is not set
+# CT_DOWNLOAD_AGENT_NONE is not set
 # CT_FORBID_DOWNLOAD is not set
 # CT_FORCE_DOWNLOAD is not set
 CT_CONNECT_TIMEOUT=10
+CT_DOWNLOAD_WGET_OPTIONS="--passive-ftp --tries=3 -nc --progress=dot:binary"
 # CT_ONLY_DOWNLOAD is not set
 CT_USE_MIRROR=y
+# CT_FORCE_MIRROR is not set
 CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc"
+CT_VERIFY_DOWNLOAD_DIGEST=y
+CT_VERIFY_DOWNLOAD_DIGEST_SHA512=y
+# CT_VERIFY_DOWNLOAD_DIGEST_SHA256 is not set
+# CT_VERIFY_DOWNLOAD_DIGEST_SHA1 is not set
+# CT_VERIFY_DOWNLOAD_DIGEST_MD5 is not set
+CT_VERIFY_DOWNLOAD_DIGEST_ALG="sha512"
+# CT_VERIFY_DOWNLOAD_SIGNATURE is not set
 
 #
 # Extracting
 #
 # CT_FORCE_EXTRACT is not set
-CT_OVERIDE_CONFIG_GUESS_SUB=y
+CT_OVERRIDE_CONFIG_GUESS_SUB=y
 # CT_ONLY_EXTRACT is not set
-# CT_PATCH_BUNDLED is not set
-# CT_PATCH_LOCAL is not set
-CT_PATCH_BUNDLED_LOCAL=y
-# CT_PATCH_LOCAL_BUNDLED is not set
-# CT_PATCH_BUNDLED_FALLBACK_LOCAL is not set
-# CT_PATCH_LOCAL_FALLBACK_BUNDLED is not set
-# CT_PATCH_NONE is not set
-CT_PATCH_ORDER="bundled,local"
-CT_PATCH_USE_LOCAL=y
-CT_LOCAL_PATCH_DIR="/tmp/patches"
+CT_PATCH_BUNDLED=y
+# CT_PATCH_BUNDLED_LOCAL is not set
+CT_PATCH_ORDER="bundled"
 
 #
 # Build behavior
@@ -78,11 +107,11 @@ CT_CONFIG_SHELL="${bash}"
 #
 # CT_LOG_ERROR is not set
 # CT_LOG_WARN is not set
-CT_LOG_INFO=y
-# CT_LOG_EXTRA is not set
+# CT_LOG_INFO is not set
+CT_LOG_EXTRA=y
 # CT_LOG_ALL is not set
 # CT_LOG_DEBUG is not set
-CT_LOG_LEVEL_MAX="INFO"
+CT_LOG_LEVEL_MAX="EXTRA"
 # CT_LOG_SEE_TOOLS_WARN is not set
 CT_LOG_PROGRESS_BAR=y
 CT_LOG_TO_FILE=y
@@ -91,75 +120,69 @@ CT_LOG_FILE_COMPRESS=y
 #
 # Target options
 #
+# CT_ARCH_ALPHA is not set
+# CT_ARCH_ARC is not set
+# CT_ARCH_ARM is not set
+# CT_ARCH_AVR is not set
+# CT_ARCH_M68K is not set
+# CT_ARCH_MIPS is not set
+# CT_ARCH_NIOS2 is not set
+CT_ARCH_POWERPC=y
+# CT_ARCH_S390 is not set
+# CT_ARCH_SH is not set
+# CT_ARCH_SPARC is not set
+# CT_ARCH_X86 is not set
+# CT_ARCH_XTENSA is not set
 CT_ARCH="powerpc"
-CT_ARCH_SUPPORTS_BOTH_ENDIAN=y
-CT_ARCH_SUPPORTS_32=y
-CT_ARCH_SUPPORTS_64=y
-CT_ARCH_SUPPORTS_WITH_ABI=y
-CT_ARCH_SUPPORTS_WITH_CPU=y
-CT_ARCH_SUPPORTS_WITH_TUNE=y
-CT_ARCH_SUPPORTS_WITH_FLOAT=y
-CT_ARCH_DEFAULT_BE=y
-CT_ARCH_DEFAULT_32=y
-CT_ARCH_ABI=""
+CT_ARCH_CHOICE_KSYM="POWERPC"
 CT_ARCH_CPU="power4"
 CT_ARCH_TUNE="power6"
-CT_ARCH_BE=y
-# CT_ARCH_LE is not set
-# CT_ARCH_32 is not set
-CT_ARCH_64=y
-CT_ARCH_BITNESS=64
-# CT_ARCH_FLOAT_HW is not set
-# CT_ARCH_FLOAT_SW is not set
-CT_TARGET_CFLAGS=""
-CT_TARGET_LDFLAGS=""
-# CT_ARCH_alpha is not set
-# CT_ARCH_arm is not set
-# CT_ARCH_avr is not set
-# CT_ARCH_m68k is not set
-# CT_ARCH_mips is not set
-# CT_ARCH_nios2 is not set
-CT_ARCH_powerpc=y
-# CT_ARCH_s390 is not set
-# CT_ARCH_sh is not set
-# CT_ARCH_sparc is not set
-# CT_ARCH_x86 is not set
-# CT_ARCH_xtensa is not set
-CT_ARCH_alpha_AVAILABLE=y
-CT_ARCH_arm_AVAILABLE=y
-CT_ARCH_avr_AVAILABLE=y
-CT_ARCH_m68k_AVAILABLE=y
-CT_ARCH_microblaze_AVAILABLE=y
-CT_ARCH_mips_AVAILABLE=y
-CT_ARCH_nios2_AVAILABLE=y
-CT_ARCH_powerpc_AVAILABLE=y
-CT_ARCH_s390_AVAILABLE=y
-CT_ARCH_sh_AVAILABLE=y
-CT_ARCH_sparc_AVAILABLE=y
-CT_ARCH_x86_AVAILABLE=y
-CT_ARCH_xtensa_AVAILABLE=y
+CT_ARCH_POWERPC_SHOW=y
+
+#
+# Options for powerpc
+#
+CT_ARCH_POWERPC_PKG_KSYM=""
+CT_ARCH_powerpc_ABI=""
+CT_ARCH_powerpc_ABI_DEFAULT=y
+# CT_ARCH_powerpc_ABI_SPE is not set
+CT_ALL_ARCH_CHOICES="ALPHA ARC ARM AVR M68K MICROBLAZE MIPS MOXIE MSP430 NIOS2 POWERPC RISCV S390 SH SPARC X86 XTENSA"
 CT_ARCH_SUFFIX=""
+# CT_OMIT_TARGET_VENDOR is not set
 
 #
 # Generic target options
 #
 # CT_MULTILIB is not set
+CT_DEMULTILIB=y
 CT_ARCH_USE_MMU=y
+CT_ARCH_SUPPORTS_EITHER_ENDIAN=y
+CT_ARCH_DEFAULT_BE=y
+CT_ARCH_BE=y
+# CT_ARCH_LE is not set
 CT_ARCH_ENDIAN="big"
+CT_ARCH_SUPPORTS_32=y
+CT_ARCH_SUPPORTS_64=y
+CT_ARCH_DEFAULT_32=y
+CT_ARCH_BITNESS=64
+# CT_ARCH_32 is not set
+CT_ARCH_64=y
 
 #
 # Target optimisations
 #
+CT_ARCH_SUPPORTS_WITH_ABI=y
+CT_ARCH_SUPPORTS_WITH_CPU=y
+CT_ARCH_SUPPORTS_WITH_TUNE=y
+CT_ARCH_SUPPORTS_WITH_FLOAT=y
+CT_ARCH_ABI=""
 CT_ARCH_FLOAT_AUTO=y
+# CT_ARCH_FLOAT_HW is not set
+# CT_ARCH_FLOAT_SW is not set
+CT_TARGET_CFLAGS=""
+CT_TARGET_LDFLAGS=""
 CT_ARCH_FLOAT="auto"
 
-#
-# powerpc other options
-#
-CT_ARCH_powerpc_ABI=""
-CT_ARCH_powerpc_ABI_DEFAULT=y
-# CT_ARCH_powerpc_ABI_SPE is not set
-
 #
 # Toolchain options
 #
@@ -172,7 +195,9 @@ CT_USE_SYSROOT=y
 CT_SYSROOT_NAME="sysroot"
 CT_SYSROOT_DIR_PREFIX=""
 CT_WANTS_STATIC_LINK=y
+CT_WANTS_STATIC_LINK_CXX=y
 # CT_STATIC_TOOLCHAIN is not set
+CT_SHOW_CT_VERSION=y
 CT_TOOLCHAIN_PKGVERSION=""
 CT_TOOLCHAIN_BUGURL=""
 
@@ -206,122 +231,204 @@ CT_BUILD_SUFFIX=""
 # Operating System
 #
 CT_KERNEL_SUPPORTS_SHARED_LIBS=y
+# CT_KERNEL_BARE_METAL is not set
+CT_KERNEL_LINUX=y
 CT_KERNEL="linux"
-CT_KERNEL_VERSION="2.6.32.68"
-# CT_KERNEL_bare_metal is not set
-CT_KERNEL_linux=y
-CT_KERNEL_bare_metal_AVAILABLE=y
-CT_KERNEL_linux_AVAILABLE=y
-# CT_KERNEL_V_4_3 is not set
-# CT_KERNEL_V_4_2 is not set
-# CT_KERNEL_V_4_1 is not set
-# CT_KERNEL_V_3_18 is not set
-# CT_KERNEL_V_3_14 is not set
-# CT_KERNEL_V_3_12 is not set
-# CT_KERNEL_V_3_10 is not set
-# CT_KERNEL_V_3_4 is not set
-# CT_KERNEL_V_3_2 is not set
-CT_KERNEL_V_2_6_32=y
-# CT_KERNEL_LINUX_CUSTOM is not set
-CT_KERNEL_windows_AVAILABLE=y
-
-#
-# Common kernel options
-#
-CT_SHARED_LIBS=y
-
-#
-# linux other options
-#
+CT_KERNEL_CHOICE_KSYM="LINUX"
+CT_KERNEL_LINUX_SHOW=y
+
+#
+# Options for linux
+#
+CT_KERNEL_LINUX_PKG_KSYM="LINUX"
+CT_LINUX_DIR_NAME="linux"
+CT_LINUX_PKG_NAME="linux"
+CT_LINUX_SRC_RELEASE=y
+CT_LINUX_PATCH_ORDER="global"
+# CT_LINUX_V_4_20 is not set
+# CT_LINUX_V_4_19 is not set
+# CT_LINUX_V_4_18 is not set
+# CT_LINUX_V_4_17 is not set
+# CT_LINUX_V_4_16 is not set
+# CT_LINUX_V_4_15 is not set
+# CT_LINUX_V_4_14 is not set
+# CT_LINUX_V_4_13 is not set
+# CT_LINUX_V_4_12 is not set
+# CT_LINUX_V_4_11 is not set
+# CT_LINUX_V_4_10 is not set
+# CT_LINUX_V_4_9 is not set
+# CT_LINUX_V_4_4 is not set
+# CT_LINUX_V_4_1 is not set
+# CT_LINUX_V_3_16 is not set
+# CT_LINUX_V_3_13 is not set
+# CT_LINUX_V_3_12 is not set
+# CT_LINUX_V_3_10 is not set
+# CT_LINUX_V_3_4 is not set
+CT_LINUX_V_3_2=y
+# CT_LINUX_V_2_6_32 is not set
+# CT_LINUX_NO_VERSIONS is not set
+CT_LINUX_VERSION="3.2.101"
+CT_LINUX_MIRRORS="$(CT_Mirrors kernel.org linux ${CT_LINUX_VERSION})"
+CT_LINUX_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_LINUX_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_LINUX_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_LINUX_SIGNATURE_FORMAT="unpacked/.sign"
+CT_LINUX_4_8_or_older=y
+CT_LINUX_older_than_4_8=y
+CT_LINUX_3_7_or_older=y
+CT_LINUX_older_than_3_7=y
+CT_LINUX_later_than_3_2=y
+CT_LINUX_3_2_or_later=y
 CT_KERNEL_LINUX_VERBOSITY_0=y
 # CT_KERNEL_LINUX_VERBOSITY_1 is not set
 # CT_KERNEL_LINUX_VERBOSITY_2 is not set
 CT_KERNEL_LINUX_VERBOSE_LEVEL=0
 CT_KERNEL_LINUX_INSTALL_CHECK=y
+CT_ALL_KERNEL_CHOICES="BARE_METAL LINUX WINDOWS"
+
+#
+# Common kernel options
+#
+CT_SHARED_LIBS=y
 
 #
 # Binary utilities
 #
 CT_ARCH_BINFMT_ELF=y
+CT_BINUTILS_BINUTILS=y
 CT_BINUTILS="binutils"
-CT_BINUTILS_binutils=y
+CT_BINUTILS_CHOICE_KSYM="BINUTILS"
+CT_BINUTILS_BINUTILS_SHOW=y
+
+#
+# Options for binutils
+#
+CT_BINUTILS_BINUTILS_PKG_KSYM="BINUTILS"
+CT_BINUTILS_DIR_NAME="binutils"
+CT_BINUTILS_USE_GNU=y
+CT_BINUTILS_USE="BINUTILS"
+CT_BINUTILS_PKG_NAME="binutils"
+CT_BINUTILS_SRC_RELEASE=y
+CT_BINUTILS_PATCH_ORDER="global"
+CT_BINUTILS_V_2_32=y
+# CT_BINUTILS_V_2_31 is not set
+# CT_BINUTILS_V_2_30 is not set
+# CT_BINUTILS_V_2_29 is not set
+# CT_BINUTILS_V_2_28 is not set
+# CT_BINUTILS_V_2_27 is not set
+# CT_BINUTILS_V_2_26 is not set
+# CT_BINUTILS_NO_VERSIONS is not set
+CT_BINUTILS_VERSION="2.32"
+CT_BINUTILS_MIRRORS="$(CT_Mirrors GNU binutils) $(CT_Mirrors sourceware binutils/releases)"
+CT_BINUTILS_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_BINUTILS_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_BINUTILS_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_BINUTILS_SIGNATURE_FORMAT="packed/.sig"
+CT_BINUTILS_later_than_2_30=y
+CT_BINUTILS_2_30_or_later=y
+CT_BINUTILS_later_than_2_27=y
+CT_BINUTILS_2_27_or_later=y
+CT_BINUTILS_later_than_2_25=y
+CT_BINUTILS_2_25_or_later=y
+CT_BINUTILS_later_than_2_23=y
+CT_BINUTILS_2_23_or_later=y
 
 #
 # GNU binutils
 #
-# CT_CC_BINUTILS_SHOW_LINARO is not set
-CT_BINUTILS_V_2_25_1=y
-# CT_BINUTILS_V_2_25 is not set
-# CT_BINUTILS_V_2_24 is not set
-# CT_BINUTILS_V_2_23_2 is not set
-# CT_BINUTILS_V_2_23_1 is not set
-# CT_BINUTILS_V_2_22 is not set
-# CT_BINUTILS_V_2_21_53 is not set
-# CT_BINUTILS_V_2_21_1a is not set
-# CT_BINUTILS_V_2_20_1a is not set
-# CT_BINUTILS_V_2_19_1a is not set
-# CT_BINUTILS_V_2_18a is not set
-CT_BINUTILS_VERSION="2.25.1"
-CT_BINUTILS_2_25_1_or_later=y
-CT_BINUTILS_2_25_or_later=y
-CT_BINUTILS_2_24_or_later=y
-CT_BINUTILS_2_23_or_later=y
-CT_BINUTILS_2_22_or_later=y
-CT_BINUTILS_2_21_or_later=y
-CT_BINUTILS_2_20_or_later=y
-CT_BINUTILS_2_19_or_later=y
-CT_BINUTILS_2_18_or_later=y
 CT_BINUTILS_HAS_HASH_STYLE=y
 CT_BINUTILS_HAS_GOLD=y
 CT_BINUTILS_HAS_PLUGINS=y
 CT_BINUTILS_HAS_PKGVERSION_BUGURL=y
-CT_BINUTILS_FORCE_LD_BFD=y
+CT_BINUTILS_FORCE_LD_BFD_DEFAULT=y
 CT_BINUTILS_LINKER_LD=y
 CT_BINUTILS_LINKERS_LIST="ld"
 CT_BINUTILS_LINKER_DEFAULT="bfd"
 # CT_BINUTILS_PLUGINS is not set
+CT_BINUTILS_RELRO=m
 CT_BINUTILS_EXTRA_CONFIG_ARRAY=""
 # CT_BINUTILS_FOR_TARGET is not set
-
-#
-# binutils other options
-#
+CT_ALL_BINUTILS_CHOICES="BINUTILS"
 
 #
 # C-library
 #
+CT_LIBC_GLIBC=y
+# CT_LIBC_UCLIBC is not set
 CT_LIBC="glibc"
-CT_LIBC_VERSION="2.11.1"
-CT_LIBC_glibc=y
-# CT_LIBC_musl is not set
-# CT_LIBC_uClibc is not set
-CT_LIBC_avr_libc_AVAILABLE=y
-CT_LIBC_glibc_AVAILABLE=y
+CT_LIBC_CHOICE_KSYM="GLIBC"
 CT_THREADS="nptl"
-# CT_CC_GLIBC_SHOW_LINARO is not set
-# CT_LIBC_GLIBC_V_2_22 is not set
-# CT_LIBC_GLIBC_V_2_21 is not set
-# CT_LIBC_GLIBC_V_2_20 is not set
-# CT_LIBC_GLIBC_V_2_19 is not set
-# CT_LIBC_GLIBC_V_2_18 is not set
-# CT_LIBC_GLIBC_V_2_17 is not set
-# CT_LIBC_GLIBC_V_2_16_0 is not set
-# CT_LIBC_GLIBC_V_2_15 is not set
-# CT_LIBC_GLIBC_V_2_14_1 is not set
-# CT_LIBC_GLIBC_V_2_14 is not set
-# CT_LIBC_GLIBC_V_2_13 is not set
-# CT_LIBC_GLIBC_V_2_12_2 is not set
-# CT_LIBC_GLIBC_V_2_12_1 is not set
-CT_LIBC_GLIBC_V_2_11_1=y
-# CT_LIBC_GLIBC_V_2_11 is not set
-# CT_LIBC_GLIBC_V_2_10_1 is not set
-# CT_LIBC_GLIBC_V_2_9 is not set
-# CT_LIBC_GLIBC_V_2_8 is not set
-CT_LIBC_mingw_AVAILABLE=y
-CT_LIBC_musl_AVAILABLE=y
-CT_LIBC_newlib_AVAILABLE=y
-CT_LIBC_none_AVAILABLE=y
-CT_LIBC_uClibc_AVAILABLE=y
+CT_LIBC_GLIBC_SHOW=y
+
+#
+# Options for glibc
+#
+CT_LIBC_GLIBC_PKG_KSYM="GLIBC"
+CT_GLIBC_DIR_NAME="glibc"
+CT_GLIBC_USE_GNU=y
+CT_GLIBC_USE="GLIBC"
+CT_GLIBC_PKG_NAME="glibc"
+CT_GLIBC_SRC_RELEASE=y
+CT_GLIBC_PATCH_ORDER="global"
+# CT_GLIBC_V_2_29 is not set
+# CT_GLIBC_V_2_28 is not set
+# CT_GLIBC_V_2_27 is not set
+# CT_GLIBC_V_2_26 is not set
+# CT_GLIBC_V_2_25 is not set
+# CT_GLIBC_V_2_24 is not set
+# CT_GLIBC_V_2_23 is not set
+# CT_GLIBC_V_2_19 is not set
+CT_GLIBC_V_2_17=y
+# CT_GLIBC_V_2_12_1 is not set
+# CT_GLIBC_NO_VERSIONS is not set
+CT_GLIBC_VERSION="2.17"
+CT_GLIBC_MIRRORS="$(CT_Mirrors GNU glibc)"
+CT_GLIBC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GLIBC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GLIBC_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_GLIBC_SIGNATURE_FORMAT="packed/.sig"
+CT_GLIBC_2_29_or_older=y
+CT_GLIBC_older_than_2_29=y
+CT_GLIBC_2_27_or_older=y
+CT_GLIBC_older_than_2_27=y
+CT_GLIBC_2_26_or_older=y
+CT_GLIBC_older_than_2_26=y
+CT_GLIBC_2_25_or_older=y
+CT_GLIBC_older_than_2_25=y
+CT_GLIBC_2_24_or_older=y
+CT_GLIBC_older_than_2_24=y
+CT_GLIBC_2_23_or_older=y
+CT_GLIBC_older_than_2_23=y
+CT_GLIBC_2_20_or_older=y
+CT_GLIBC_older_than_2_20=y
+CT_GLIBC_2_17_or_later=y
+CT_GLIBC_2_17_or_older=y
+CT_GLIBC_later_than_2_14=y
+CT_GLIBC_2_14_or_later=y
+CT_GLIBC_DEP_KERNEL_HEADERS_VERSION=y
+CT_GLIBC_DEP_BINUTILS=y
+CT_GLIBC_DEP_GCC=y
+CT_GLIBC_DEP_PYTHON=y
+CT_GLIBC_HAS_NPTL_ADDON=y
+CT_GLIBC_HAS_PORTS_ADDON=y
+CT_GLIBC_HAS_LIBIDN_ADDON=y
+CT_GLIBC_USE_PORTS_ADDON=y
+CT_GLIBC_USE_NPTL_ADDON=y
+# CT_GLIBC_USE_LIBIDN_ADDON is not set
+CT_GLIBC_HAS_OBSOLETE_RPC=y
+CT_GLIBC_EXTRA_CONFIG_ARRAY=""
+CT_GLIBC_CONFIGPARMS=""
+CT_GLIBC_EXTRA_CFLAGS=""
+CT_GLIBC_ENABLE_OBSOLETE_RPC=y
+# CT_GLIBC_DISABLE_VERSIONING is not set
+CT_GLIBC_OLDEST_ABI=""
+CT_GLIBC_FORCE_UNWIND=y
+# CT_GLIBC_LOCALES is not set
+# CT_GLIBC_KERNEL_VERSION_NONE is not set
+CT_GLIBC_KERNEL_VERSION_AS_HEADERS=y
+# CT_GLIBC_KERNEL_VERSION_CHOSEN is not set
+CT_GLIBC_MIN_KERNEL="3.2.101"
+CT_ALL_LIBC_CHOICES="AVR_LIBC BIONIC GLIBC MINGW_W64 MOXIEBOX MUSL NEWLIB NONE UCLIBC"
 CT_LIBC_SUPPORT_THREADS_ANY=y
 CT_LIBC_SUPPORT_THREADS_NATIVE=y
 
@@ -329,79 +436,71 @@ CT_LIBC_SUPPORT_THREADS_NATIVE=y
 # Common C library options
 #
 CT_THREADS_NATIVE=y
+# CT_CREATE_LDSO_CONF is not set
 CT_LIBC_XLDD=y
 
-#
-# glibc other options
-#
-CT_LIBC_GLIBC_PORTS_EXTERNAL=y
-CT_LIBC_glibc_familly=y
-CT_LIBC_GLIBC_EXTRA_CONFIG_ARRAY=""
-CT_LIBC_GLIBC_CONFIGPARMS=""
-CT_LIBC_GLIBC_EXTRA_CFLAGS=""
-CT_LIBC_EXTRA_CC_ARGS=""
-# CT_LIBC_DISABLE_VERSIONING is not set
-CT_LIBC_OLDEST_ABI=""
-CT_LIBC_GLIBC_FORCE_UNWIND=y
-# CT_LIBC_GLIBC_USE_PORTS is not set
-CT_LIBC_ADDONS_LIST=""
-# CT_LIBC_LOCALES is not set
-# CT_LIBC_GLIBC_KERNEL_VERSION_NONE is not set
-CT_LIBC_GLIBC_KERNEL_VERSION_AS_HEADERS=y
-# CT_LIBC_GLIBC_KERNEL_VERSION_CHOSEN is not set
-CT_LIBC_GLIBC_MIN_KERNEL="2.6.32.68"
-
 #
 # C compiler
 #
-CT_CC="gcc"
 CT_CC_CORE_PASSES_NEEDED=y
 CT_CC_CORE_PASS_1_NEEDED=y
 CT_CC_CORE_PASS_2_NEEDED=y
-CT_CC_gcc=y
-# CT_CC_GCC_SHOW_LINARO is not set
-CT_CC_GCC_V_5_2_0=y
-# CT_CC_GCC_V_4_9_3 is not set
-# CT_CC_GCC_V_4_8_5 is not set
-# CT_CC_GCC_V_4_7_4 is not set
-# CT_CC_GCC_V_4_6_4 is not set
-# CT_CC_GCC_V_4_5_4 is not set
-# CT_CC_GCC_V_4_4_7 is not set
-# CT_CC_GCC_V_4_3_6 is not set
-# CT_CC_GCC_V_4_2_4 is not set
-CT_CC_GCC_4_2_or_later=y
-CT_CC_GCC_4_3_or_later=y
-CT_CC_GCC_4_4_or_later=y
-CT_CC_GCC_4_5_or_later=y
-CT_CC_GCC_4_6_or_later=y
-CT_CC_GCC_4_7_or_later=y
-CT_CC_GCC_4_8_or_later=y
-CT_CC_GCC_4_9_or_later=y
-CT_CC_GCC_5=y
-CT_CC_GCC_5_or_later=y
-CT_CC_GCC_HAS_GRAPHITE=y
-CT_CC_GCC_USE_GRAPHITE=y
-CT_CC_GCC_HAS_LTO=y
-CT_CC_GCC_USE_LTO=y
-CT_CC_GCC_HAS_PKGVERSION_BUGURL=y
-CT_CC_GCC_HAS_BUILD_ID=y
-CT_CC_GCC_HAS_LNK_HASH_STYLE=y
-CT_CC_GCC_USE_GMP_MPFR=y
-CT_CC_GCC_USE_MPC=y
-CT_CC_GCC_HAS_LIBQUADMATH=y
-CT_CC_GCC_HAS_LIBSANITIZER=y
-CT_CC_GCC_VERSION="5.2.0"
-# CT_CC_LANG_FORTRAN is not set
+CT_CC_SUPPORT_CXX=y
+CT_CC_SUPPORT_FORTRAN=y
+CT_CC_SUPPORT_ADA=y
+CT_CC_SUPPORT_OBJC=y
+CT_CC_SUPPORT_OBJCXX=y
+CT_CC_SUPPORT_GOLANG=y
+CT_CC_GCC=y
+CT_CC="gcc"
+CT_CC_CHOICE_KSYM="GCC"
+CT_CC_GCC_SHOW=y
+
+#
+# Options for gcc
+#
+CT_CC_GCC_PKG_KSYM="GCC"
+CT_GCC_DIR_NAME="gcc"
+CT_GCC_USE_GNU=y
+CT_GCC_USE="GCC"
+CT_GCC_PKG_NAME="gcc"
+CT_GCC_SRC_RELEASE=y
+CT_GCC_PATCH_ORDER="global"
+CT_GCC_V_8=y
+# CT_GCC_V_7 is not set
+# CT_GCC_V_6 is not set
+# CT_GCC_V_5 is not set
+# CT_GCC_V_4_9 is not set
+# CT_GCC_NO_VERSIONS is not set
+CT_GCC_VERSION="8.3.0"
+CT_GCC_MIRRORS="$(CT_Mirrors GNU gcc/gcc-${CT_GCC_VERSION}) $(CT_Mirrors sourceware gcc/releases/gcc-${CT_GCC_VERSION})"
+CT_GCC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GCC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GCC_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_GCC_SIGNATURE_FORMAT=""
+CT_GCC_later_than_7=y
+CT_GCC_7_or_later=y
+CT_GCC_later_than_6=y
+CT_GCC_6_or_later=y
+CT_GCC_later_than_5=y
+CT_GCC_5_or_later=y
+CT_GCC_later_than_4_9=y
+CT_GCC_4_9_or_later=y
+CT_GCC_later_than_4_8=y
+CT_GCC_4_8_or_later=y
+CT_CC_GCC_HAS_LIBMPX=y
 CT_CC_GCC_ENABLE_CXX_FLAGS=""
 CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY=""
 CT_CC_GCC_EXTRA_CONFIG_ARRAY=""
-CT_CC_GCC_EXTRA_ENV_ARRAY=""
 CT_CC_GCC_STATIC_LIBSTDCXX=y
 # CT_CC_GCC_SYSTEM_ZLIB is not set
+CT_CC_GCC_CONFIG_TLS=m
 
 #
 # Optimisation features
 #
+CT_CC_GCC_USE_GRAPHITE=y
+CT_CC_GCC_USE_LTO=y
 
 #
 # Settings for libraries running on target
@@ -430,94 +529,208 @@ CT_CC_GCC_DEC_FLOAT_AUTO=y
 # CT_CC_GCC_DEC_FLOAT_BID is not set
 # CT_CC_GCC_DEC_FLOAT_DPD is not set
 # CT_CC_GCC_DEC_FLOATS_NO is not set
-CT_CC_SUPPORT_CXX=y
-CT_CC_SUPPORT_FORTRAN=y
-CT_CC_SUPPORT_JAVA=y
-CT_CC_SUPPORT_ADA=y
-CT_CC_SUPPORT_OBJC=y
-CT_CC_SUPPORT_OBJCXX=y
-CT_CC_SUPPORT_GOLANG=y
+CT_ALL_CC_CHOICES="GCC"
 
 #
 # Additional supported languages:
 #
 CT_CC_LANG_CXX=y
-# CT_CC_LANG_JAVA is not set
+# CT_CC_LANG_FORTRAN is not set
 
 #
 # Debug facilities
 #
-# CT_DEBUG_dmalloc is not set
-# CT_DEBUG_duma is not set
-# CT_DEBUG_gdb is not set
-# CT_DEBUG_ltrace is not set
-# CT_DEBUG_strace is not set
+# CT_DEBUG_DUMA is not set
+# CT_DEBUG_GDB is not set
+# CT_DEBUG_LTRACE is not set
+# CT_DEBUG_STRACE is not set
+CT_ALL_DEBUG_CHOICES="DUMA GDB LTRACE STRACE"
 
 #
 # Companion libraries
 #
-CT_COMPLIBS_NEEDED=y
+# CT_COMPLIBS_CHECK is not set
+# CT_COMP_LIBS_CLOOG is not set
+# CT_COMP_LIBS_EXPAT is not set
+CT_COMP_LIBS_GETTEXT=y
+CT_COMP_LIBS_GETTEXT_PKG_KSYM="GETTEXT"
+CT_GETTEXT_DIR_NAME="gettext"
+CT_GETTEXT_PKG_NAME="gettext"
+CT_GETTEXT_SRC_RELEASE=y
+CT_GETTEXT_PATCH_ORDER="global"
+CT_GETTEXT_V_0_19_8_1=y
+# CT_GETTEXT_NO_VERSIONS is not set
+CT_GETTEXT_VERSION="0.19.8.1"
+CT_GETTEXT_MIRRORS="$(CT_Mirrors GNU gettext)"
+CT_GETTEXT_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GETTEXT_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GETTEXT_ARCHIVE_FORMATS=".tar.xz .tar.lz .tar.gz"
+CT_GETTEXT_SIGNATURE_FORMAT="packed/.sig"
+CT_COMP_LIBS_GMP=y
+CT_COMP_LIBS_GMP_PKG_KSYM="GMP"
+CT_GMP_DIR_NAME="gmp"
+CT_GMP_PKG_NAME="gmp"
+CT_GMP_SRC_RELEASE=y
+CT_GMP_PATCH_ORDER="global"
+CT_GMP_V_6_1=y
+# CT_GMP_NO_VERSIONS is not set
+CT_GMP_VERSION="6.1.2"
+CT_GMP_MIRRORS="https://gmplib.org/download/gmp https://gmplib.org/download/gmp/archive $(CT_Mirrors GNU gmp)"
+CT_GMP_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GMP_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GMP_ARCHIVE_FORMATS=".tar.xz .tar.lz .tar.bz2"
+CT_GMP_SIGNATURE_FORMAT="packed/.sig"
+CT_GMP_later_than_5_1_0=y
+CT_GMP_5_1_0_or_later=y
+CT_GMP_later_than_5_0_0=y
+CT_GMP_5_0_0_or_later=y
+CT_GMP_REQUIRE_5_0_0_or_later=y
+CT_COMP_LIBS_ISL=y
+CT_COMP_LIBS_ISL_PKG_KSYM="ISL"
+CT_ISL_DIR_NAME="isl"
+CT_ISL_PKG_NAME="isl"
+CT_ISL_SRC_RELEASE=y
+CT_ISL_PATCH_ORDER="global"
+CT_ISL_V_0_20=y
+# CT_ISL_V_0_19 is not set
+# CT_ISL_V_0_18 is not set
+# CT_ISL_V_0_17 is not set
+# CT_ISL_V_0_16 is not set
+# CT_ISL_V_0_15 is not set
+# CT_ISL_NO_VERSIONS is not set
+CT_ISL_VERSION="0.20"
+CT_ISL_MIRRORS="http://isl.gforge.inria.fr"
+CT_ISL_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_ISL_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_ISL_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_ISL_SIGNATURE_FORMAT=""
+CT_ISL_later_than_0_18=y
+CT_ISL_0_18_or_later=y
+CT_ISL_later_than_0_15=y
+CT_ISL_0_15_or_later=y
+CT_ISL_REQUIRE_0_15_or_later=y
+CT_ISL_later_than_0_14=y
+CT_ISL_0_14_or_later=y
+CT_ISL_REQUIRE_0_14_or_later=y
+CT_ISL_later_than_0_13=y
+CT_ISL_0_13_or_later=y
+CT_ISL_later_than_0_12=y
+CT_ISL_0_12_or_later=y
+CT_ISL_REQUIRE_0_12_or_later=y
+# CT_COMP_LIBS_LIBELF is not set
+CT_COMP_LIBS_LIBICONV=y
+CT_COMP_LIBS_LIBICONV_PKG_KSYM="LIBICONV"
+CT_LIBICONV_DIR_NAME="libiconv"
+CT_LIBICONV_PKG_NAME="libiconv"
+CT_LIBICONV_SRC_RELEASE=y
+CT_LIBICONV_PATCH_ORDER="global"
+CT_LIBICONV_V_1_15=y
+# CT_LIBICONV_NO_VERSIONS is not set
+CT_LIBICONV_VERSION="1.15"
+CT_LIBICONV_MIRRORS="$(CT_Mirrors GNU libiconv)"
+CT_LIBICONV_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_LIBICONV_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_LIBICONV_ARCHIVE_FORMATS=".tar.gz"
+CT_LIBICONV_SIGNATURE_FORMAT="packed/.sig"
+CT_COMP_LIBS_MPC=y
+CT_COMP_LIBS_MPC_PKG_KSYM="MPC"
+CT_MPC_DIR_NAME="mpc"
+CT_MPC_PKG_NAME="mpc"
+CT_MPC_SRC_RELEASE=y
+CT_MPC_PATCH_ORDER="global"
+CT_MPC_V_1_1=y
+# CT_MPC_V_1_0 is not set
+# CT_MPC_NO_VERSIONS is not set
+CT_MPC_VERSION="1.1.0"
+CT_MPC_MIRRORS="http://www.multiprecision.org/downloads $(CT_Mirrors GNU mpc)"
+CT_MPC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_MPC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_MPC_ARCHIVE_FORMATS=".tar.gz"
+CT_MPC_SIGNATURE_FORMAT="packed/.sig"
+CT_MPC_1_1_0_or_later=y
+CT_MPC_1_1_0_or_older=y
+CT_COMP_LIBS_MPFR=y
+CT_COMP_LIBS_MPFR_PKG_KSYM="MPFR"
+CT_MPFR_DIR_NAME="mpfr"
+CT_MPFR_PKG_NAME="mpfr"
+CT_MPFR_SRC_RELEASE=y
+CT_MPFR_PATCH_ORDER="global"
+CT_MPFR_V_4_0=y
+# CT_MPFR_V_3_1 is not set
+# CT_MPFR_NO_VERSIONS is not set
+CT_MPFR_VERSION="4.0.2"
+CT_MPFR_MIRRORS="http://www.mpfr.org/mpfr-${CT_MPFR_VERSION} $(CT_Mirrors GNU mpfr)"
+CT_MPFR_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_MPFR_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_MPFR_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz .zip"
+CT_MPFR_SIGNATURE_FORMAT="packed/.asc"
+CT_MPFR_later_than_4_0_0=y
+CT_MPFR_4_0_0_or_later=y
+CT_MPFR_later_than_3_0_0=y
+CT_MPFR_3_0_0_or_later=y
+CT_MPFR_REQUIRE_3_0_0_or_later=y
+CT_COMP_LIBS_NCURSES=y
+CT_COMP_LIBS_NCURSES_PKG_KSYM="NCURSES"
+CT_NCURSES_DIR_NAME="ncurses"
+CT_NCURSES_PKG_NAME="ncurses"
+CT_NCURSES_SRC_RELEASE=y
+CT_NCURSES_PATCH_ORDER="global"
+CT_NCURSES_V_6_1=y
+# CT_NCURSES_V_6_0 is not set
+# CT_NCURSES_NO_VERSIONS is not set
+CT_NCURSES_VERSION="6.1"
+CT_NCURSES_MIRRORS="ftp://invisible-island.net/ncurses $(CT_Mirrors GNU ncurses)"
+CT_NCURSES_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_NCURSES_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_NCURSES_ARCHIVE_FORMATS=".tar.gz"
+CT_NCURSES_SIGNATURE_FORMAT="packed/.sig"
+CT_NCURSES_HOST_CONFIG_ARGS=""
+CT_NCURSES_HOST_DISABLE_DB=y
+CT_NCURSES_HOST_FALLBACKS="linux,xterm,xterm-color,xterm-256color,vt100"
+CT_NCURSES_TARGET_CONFIG_ARGS=""
+# CT_NCURSES_TARGET_DISABLE_DB is not set
+CT_NCURSES_TARGET_FALLBACKS=""
+CT_COMP_LIBS_ZLIB=y
+CT_COMP_LIBS_ZLIB_PKG_KSYM="ZLIB"
+CT_ZLIB_DIR_NAME="zlib"
+CT_ZLIB_PKG_NAME="zlib"
+CT_ZLIB_SRC_RELEASE=y
+CT_ZLIB_PATCH_ORDER="global"
+CT_ZLIB_V_1_2_11=y
+# CT_ZLIB_NO_VERSIONS is not set
+CT_ZLIB_VERSION="1.2.11"
+CT_ZLIB_MIRRORS="http://downloads.sourceforge.net/project/libpng/zlib/${CT_ZLIB_VERSION}"
+CT_ZLIB_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_ZLIB_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_ZLIB_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_ZLIB_SIGNATURE_FORMAT="packed/.asc"
+CT_ALL_COMP_LIBS_CHOICES="CLOOG EXPAT GETTEXT GMP ISL LIBELF LIBICONV MPC MPFR NCURSES ZLIB"
 CT_LIBICONV_NEEDED=y
 CT_GETTEXT_NEEDED=y
 CT_GMP_NEEDED=y
 CT_MPFR_NEEDED=y
 CT_ISL_NEEDED=y
 CT_MPC_NEEDED=y
-CT_COMPLIBS=y
+CT_NCURSES_NEEDED=y
+CT_ZLIB_NEEDED=y
 CT_LIBICONV=y
 CT_GETTEXT=y
 CT_GMP=y
 CT_MPFR=y
 CT_ISL=y
 CT_MPC=y
-CT_LIBICONV_V_1_14=y
-CT_LIBICONV_VERSION="1.14"
-CT_GETTEXT_V_0_19_6=y
-CT_GETTEXT_VERSION="0.19.6"
-CT_GMP_V_6_0_0=y
-# CT_GMP_V_5_1_3 is not set
-# CT_GMP_V_5_1_1 is not set
-# CT_GMP_V_5_0_2 is not set
-# CT_GMP_V_5_0_1 is not set
-# CT_GMP_V_4_3_2 is not set
-# CT_GMP_V_4_3_1 is not set
-# CT_GMP_V_4_3_0 is not set
-CT_GMP_5_0_2_or_later=y
-CT_GMP_VERSION="6.0.0a"
-CT_MPFR_V_3_1_3=y
-# CT_MPFR_V_3_1_2 is not set
-# CT_MPFR_V_3_1_0 is not set
-# CT_MPFR_V_3_0_1 is not set
-# CT_MPFR_V_3_0_0 is not set
-# CT_MPFR_V_2_4_2 is not set
-# CT_MPFR_V_2_4_1 is not set
-# CT_MPFR_V_2_4_0 is not set
-CT_MPFR_VERSION="3.1.3"
-CT_ISL_V_0_14=y
-# CT_ISL_V_0_12_2 is not set
-CT_ISL_V_0_14_or_later=y
-CT_ISL_V_0_12_or_later=y
-CT_ISL_VERSION="0.14"
-CT_MPC_V_1_0_3=y
-# CT_MPC_V_1_0_2 is not set
-# CT_MPC_V_1_0_1 is not set
-# CT_MPC_V_1_0 is not set
-# CT_MPC_V_0_9 is not set
-# CT_MPC_V_0_8_2 is not set
-# CT_MPC_V_0_8_1 is not set
-# CT_MPC_V_0_7 is not set
-CT_MPC_VERSION="1.0.3"
-
-#
-# Companion libraries common options
-#
-# CT_COMPLIBS_CHECK is not set
+CT_NCURSES=y
+CT_ZLIB=y
 
 #
 # Companion tools
 #
-
-#
-# READ HELP before you say 'Y' below !!!
-#
-# CT_COMP_TOOLS is not set
+# CT_COMP_TOOLS_FOR_HOST is not set
+# CT_COMP_TOOLS_AUTOCONF is not set
+# CT_COMP_TOOLS_AUTOMAKE is not set
+# CT_COMP_TOOLS_BISON is not set
+# CT_COMP_TOOLS_DTC is not set
+# CT_COMP_TOOLS_LIBTOOL is not set
+# CT_COMP_TOOLS_M4 is not set
+# CT_COMP_TOOLS_MAKE is not set
+CT_ALL_COMP_TOOLS_CHOICES="AUTOCONF AUTOMAKE BISON DTC LIBTOOL M4 MAKE"
index 5157dd4c79b4c841c173418a6fea025c034b0029..9a290edd561cc7a6eccb1dd7fd01cb77f67a4f52 100644 (file)
@@ -1,16 +1,8 @@
-FROM ubuntu:16.04
+FROM ubuntu:20.04
 
 COPY scripts/cross-apt-packages.sh /scripts/
 RUN sh /scripts/cross-apt-packages.sh
 
-# Ubuntu 16.04 (this container) ships with make 4, but something in the
-# toolchains we build below chokes on that, so go back to make 3
-COPY scripts/make3.sh /scripts/
-RUN sh /scripts/make3.sh
-
-COPY scripts/crosstool-ng.sh /scripts/
-RUN sh /scripts/crosstool-ng.sh
-
 COPY scripts/rustbuild-setup.sh /scripts/
 RUN sh /scripts/rustbuild-setup.sh
 USER rustbuild
@@ -25,9 +17,6 @@ RUN ./build-powerpc64le-toolchain.sh
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
-
 ENV \
     AR_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-ar \
     CC_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-gcc \
index f78d2b7d1e843272e6c0d2832736acaf436e2931..56ea28b6ca5f1c9f50d4512f7b347797a7747b0f 100755 (executable)
@@ -5,7 +5,7 @@ set -ex
 source shared.sh
 
 BINUTILS=2.32
-GCC=5.3.0
+GCC=8.3.0
 TARGET=powerpc64le-linux-gnu
 SYSROOT=/usr/local/$TARGET/sysroot
 
@@ -32,7 +32,7 @@ popd
 # Next, download and build binutils.
 mkdir binutils-$TARGET
 pushd binutils-$TARGET
-curl https://ftp.gnu.org/gnu/binutils/binutils-$BINUTILS.tar.bz2 | tar xjf -
+curl https://ftp.gnu.org/gnu/binutils/binutils-$BINUTILS.tar.xz | tar xJf -
 mkdir binutils-build
 cd binutils-build
 hide_output ../binutils-$BINUTILS/configure --target=$TARGET --with-sysroot=$SYSROOT
@@ -44,7 +44,7 @@ rm -rf binutils-$TARGET
 # Finally, download and build gcc.
 mkdir gcc-$TARGET
 pushd gcc-$TARGET
-curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.bz2 | tar xjf -
+curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.xz | tar xJf -
 cd gcc-$GCC
 hide_output ./contrib/download_prerequisites
 
index 80b7793cb7e3caa88a4db03d2ec9df15351c8ebb..88b8c7ea3c7e403a7fe365d7ed2dd3c950e6f3cc 100644 (file)
@@ -1,10 +1,10 @@
-FROM ubuntu:18.04
+FROM ubuntu:20.04
 
 COPY scripts/cross-apt-packages.sh /scripts/
 RUN sh /scripts/cross-apt-packages.sh
 
-COPY host-x86_64/dist-riscv64-linux/crosstool-ng.sh /scripts/
-RUN sh /scripts/crosstool-ng.sh
+COPY scripts/crosstool-ng-1.24.sh /scripts/
+RUN sh /scripts/crosstool-ng-1.24.sh
 
 COPY scripts/rustbuild-setup.sh /scripts/
 RUN sh /scripts/rustbuild-setup.sh
@@ -19,9 +19,6 @@ USER root
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
-
 ENV PATH=$PATH:/x-tools/riscv64-unknown-linux-gnu/bin
 
 ENV CC_riscv64gc_unknown_linux_gnu=riscv64-unknown-linux-gnu-gcc \
diff --git a/src/ci/docker/host-x86_64/dist-riscv64-linux/crosstool-ng.sh b/src/ci/docker/host-x86_64/dist-riscv64-linux/crosstool-ng.sh
deleted file mode 100644 (file)
index 3a40f6c..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/sh
-set -ex
-
-# Mirrored from https://github.com/crosstool-ng/crosstool-ng/archive/crosstool-ng-1.24.0.tar.gz
-url="https://ci-mirrors.rust-lang.org/rustc/crosstool-ng-1.24.0.tar.gz"
-curl -Lf $url | tar xzf -
-cd crosstool-ng-crosstool-ng-1.24.0
-./bootstrap
-./configure --prefix=/usr/local
-make -j$(nproc)
-make install
-cd ..
-rm -rf crosstool-ng-crosstool-ng-1.24.0
index fda0f0e2f7fb84844d7f590675e5dc65ec5eb8cc..7d77fdd30d1d8ca6c340801c836053540544a696 100644 (file)
@@ -11,7 +11,6 @@ RUN sh /scripts/rustbuild-setup.sh
 USER rustbuild
 WORKDIR /tmp
 
-COPY host-x86_64/dist-s390x-linux/patches/ /tmp/patches/
 COPY host-x86_64/dist-s390x-linux/s390x-linux-gnu.config host-x86_64/dist-s390x-linux/build-s390x-toolchain.sh /tmp/
 RUN ./build-s390x-toolchain.sh
 
@@ -20,9 +19,6 @@ USER root
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
-
 ENV PATH=$PATH:/x-tools/s390x-ibm-linux-gnu/bin
 
 ENV \
diff --git a/src/ci/docker/host-x86_64/dist-s390x-linux/patches/glibc/2.12.1/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch b/src/ci/docker/host-x86_64/dist-s390x-linux/patches/glibc/2.12.1/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch
deleted file mode 100644 (file)
index cba416e..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-From 2739047682590b1df473401b4febf424f857fccf Mon Sep 17 00:00:00 2001
-From: Andreas Krebbel <Andreas.Krebbel@de.ibm.com>
-Date: Sun, 17 Apr 2011 20:43:59 -0400
-Subject: [PATCH] Use .machine to prevent AS from complaining about z9-109
- instructions in iconv modules
-
----
- sysdeps/s390/s390-64/utf16-utf32-z9.c | 5 ++++-
- sysdeps/s390/s390-64/utf8-utf16-z9.c  | 5 ++++-
- sysdeps/s390/s390-64/utf8-utf32-z9.c  | 5 ++++-
- 3 files changed, 12 insertions(+), 3 deletions(-)
-
-diff --git a/sysdeps/s390/s390-64/utf16-utf32-z9.c b/sysdeps/s390/s390-64/utf16-utf32-z9.c
-index 14daf2118fe5..5bcaaaedec9c 100644
---- a/sysdeps/s390/s390-64/utf16-utf32-z9.c
-+++ b/sysdeps/s390/s390-64/utf16-utf32-z9.c
-@@ -169,7 +169,10 @@ gconv_end (struct __gconv_step *data)
-     register unsigned long long outlen asm("11") = outend - outptr;   \
-     uint64_t cc = 0;                                                  \
-                                                                       \
--    asm volatile ("0: " INSTRUCTION "  \n\t"                          \
-+    asm volatile (".machine push       \n\t"                          \
-+                  ".machine \"z9-109\" \n\t"                          \
-+                "0: " INSTRUCTION "  \n\t"                            \
-+                  ".machine pop        \n\t"                          \
-                   "   jo     0b        \n\t"                          \
-                 "   ipm    %2        \n"                              \
-                 : "+a" (pOutput), "+a" (pInput), "+d" (cc),           \
-diff --git a/sysdeps/s390/s390-64/utf8-utf16-z9.c b/sysdeps/s390/s390-64/utf8-utf16-z9.c
-index 5f73f3c59e21..812a42fae44c 100644
---- a/sysdeps/s390/s390-64/utf8-utf16-z9.c
-+++ b/sysdeps/s390/s390-64/utf8-utf16-z9.c
-@@ -151,7 +151,10 @@ gconv_end (struct __gconv_step *data)
-     register unsigned long long outlen asm("11") = outend - outptr;   \
-     uint64_t cc = 0;                                                  \
-                                                                       \
--    asm volatile ("0: " INSTRUCTION "  \n\t"                          \
-+    asm volatile (".machine push       \n\t"                          \
-+                  ".machine \"z9-109\" \n\t"                          \
-+                "0: " INSTRUCTION "  \n\t"                            \
-+                  ".machine pop        \n\t"                          \
-                   "   jo     0b        \n\t"                          \
-                 "   ipm    %2        \n"                              \
-                 : "+a" (pOutput), "+a" (pInput), "+d" (cc),           \
-diff --git a/sysdeps/s390/s390-64/utf8-utf32-z9.c b/sysdeps/s390/s390-64/utf8-utf32-z9.c
-index 17ef8bc890c3..0ffd848c8124 100644
---- a/sysdeps/s390/s390-64/utf8-utf32-z9.c
-+++ b/sysdeps/s390/s390-64/utf8-utf32-z9.c
-@@ -155,7 +155,10 @@ gconv_end (struct __gconv_step *data)
-     register unsigned long long outlen asm("11") = outend - outptr;   \
-     uint64_t cc = 0;                                                  \
-                                                                       \
--    asm volatile ("0: " INSTRUCTION "  \n\t"                          \
-+    asm volatile (".machine push       \n\t"                          \
-+                  ".machine \"z9-109\" \n\t"                          \
-+                "0: " INSTRUCTION "  \n\t"                            \
-+                  ".machine pop        \n\t"                          \
-                   "   jo     0b        \n\t"                          \
-                 "   ipm    %2        \n"                              \
-                 : "+a" (pOutput), "+a" (pInput), "+d" (cc),           \
--- 
-2.9.3
-
index d766e6e838e577a335c767cd44861a6190713635..51ef36b03ac09494e3419f93d9cbfe34b248c2a8 100644 (file)
@@ -41,7 +41,8 @@ CT_MODULES=y
 #
 # Paths
 #
-CT_LOCAL_TARBALLS_DIR=""
+CT_LOCAL_TARBALLS_DIR="${HOME}/src"
+CT_SAVE_TARBALLS=y
 # CT_TARBALLS_BUILDROOT_LAYOUT is not set
 CT_WORK_DIR="${CT_TOP_DIR}/.build"
 CT_BUILD_TOP_DIR="${CT_WORK_DIR:-${CT_TOP_DIR}/.build}/${CT_HOST:+HOST-${CT_HOST}/}${CT_TARGET}"
@@ -81,11 +82,9 @@ CT_VERIFY_DOWNLOAD_DIGEST_ALG="sha512"
 # CT_FORCE_EXTRACT is not set
 CT_OVERRIDE_CONFIG_GUESS_SUB=y
 # CT_ONLY_EXTRACT is not set
-# CT_PATCH_BUNDLED is not set
-CT_PATCH_BUNDLED_LOCAL=y
-CT_PATCH_ORDER="bundled,local"
-CT_PATCH_USE_LOCAL=y
-CT_LOCAL_PATCH_DIR="/tmp/patches"
+CT_PATCH_BUNDLED=y
+# CT_PATCH_BUNDLED_LOCAL is not set
+CT_PATCH_ORDER="bundled"
 
 #
 # Build behavior
@@ -136,6 +135,12 @@ CT_ARCH_S390=y
 # CT_ARCH_XTENSA is not set
 CT_ARCH="s390"
 CT_ARCH_CHOICE_KSYM="S390"
+# CT_ARCH_ALPHA_EV4 is not set
+# CT_ARCH_ALPHA_EV45 is not set
+# CT_ARCH_ALPHA_EV5 is not set
+# CT_ARCH_ALPHA_EV56 is not set
+# CT_ARCH_ALPHA_EV6 is not set
+# CT_ARCH_ALPHA_EV67 is not set
 CT_ARCH_S390_SHOW=y
 
 #
@@ -248,10 +253,10 @@ CT_LINUX_PATCH_ORDER="global"
 # CT_LINUX_V_3_12 is not set
 # CT_LINUX_V_3_10 is not set
 # CT_LINUX_V_3_4 is not set
-# CT_LINUX_V_3_2 is not set
-CT_LINUX_V_2_6_32=y
+CT_LINUX_V_3_2=y
+# CT_LINUX_V_2_6_32 is not set
 # CT_LINUX_NO_VERSIONS is not set
-CT_LINUX_VERSION="2.6.32.71"
+CT_LINUX_VERSION="3.2.101"
 CT_LINUX_MIRRORS="$(CT_Mirrors kernel.org linux ${CT_LINUX_VERSION})"
 CT_LINUX_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
 CT_LINUX_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
@@ -261,8 +266,8 @@ CT_LINUX_4_8_or_older=y
 CT_LINUX_older_than_4_8=y
 CT_LINUX_3_7_or_older=y
 CT_LINUX_older_than_3_7=y
-CT_LINUX_3_2_or_older=y
-CT_LINUX_older_than_3_2=y
+CT_LINUX_later_than_3_2=y
+CT_LINUX_3_2_or_later=y
 CT_KERNEL_LINUX_VERBOSITY_0=y
 # CT_KERNEL_LINUX_VERBOSITY_1 is not set
 # CT_KERNEL_LINUX_VERBOSITY_2 is not set
@@ -294,24 +299,24 @@ CT_BINUTILS_USE="BINUTILS"
 CT_BINUTILS_PKG_NAME="binutils"
 CT_BINUTILS_SRC_RELEASE=y
 CT_BINUTILS_PATCH_ORDER="global"
-# CT_BINUTILS_V_2_32 is not set
+CT_BINUTILS_V_2_32=y
 # CT_BINUTILS_V_2_31 is not set
 # CT_BINUTILS_V_2_30 is not set
 # CT_BINUTILS_V_2_29 is not set
 # CT_BINUTILS_V_2_28 is not set
 # CT_BINUTILS_V_2_27 is not set
-CT_BINUTILS_V_2_26=y
+# CT_BINUTILS_V_2_26 is not set
 # CT_BINUTILS_NO_VERSIONS is not set
-CT_BINUTILS_VERSION="2.26.1"
+CT_BINUTILS_VERSION="2.32"
 CT_BINUTILS_MIRRORS="$(CT_Mirrors GNU binutils) $(CT_Mirrors sourceware binutils/releases)"
 CT_BINUTILS_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
 CT_BINUTILS_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
-CT_BINUTILS_ARCHIVE_FORMATS=".tar.bz2 .tar.gz"
+CT_BINUTILS_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
 CT_BINUTILS_SIGNATURE_FORMAT="packed/.sig"
-CT_BINUTILS_2_30_or_older=y
-CT_BINUTILS_older_than_2_30=y
-CT_BINUTILS_2_27_or_older=y
-CT_BINUTILS_older_than_2_27=y
+CT_BINUTILS_later_than_2_30=y
+CT_BINUTILS_2_30_or_later=y
+CT_BINUTILS_later_than_2_27=y
+CT_BINUTILS_2_27_or_later=y
 CT_BINUTILS_later_than_2_25=y
 CT_BINUTILS_2_25_or_later=y
 CT_BINUTILS_later_than_2_23=y
@@ -338,6 +343,8 @@ CT_ALL_BINUTILS_CHOICES="BINUTILS"
 # C-library
 #
 CT_LIBC_GLIBC=y
+# CT_LIBC_NEWLIB is not set
+# CT_LIBC_NONE is not set
 # CT_LIBC_UCLIBC is not set
 CT_LIBC="glibc"
 CT_LIBC_CHOICE_KSYM="GLIBC"
@@ -362,10 +369,10 @@ CT_GLIBC_PATCH_ORDER="global"
 # CT_GLIBC_V_2_24 is not set
 # CT_GLIBC_V_2_23 is not set
 # CT_GLIBC_V_2_19 is not set
-# CT_GLIBC_V_2_17 is not set
-CT_GLIBC_V_2_12_1=y
+CT_GLIBC_V_2_17=y
+# CT_GLIBC_V_2_12_1 is not set
 # CT_GLIBC_NO_VERSIONS is not set
-CT_GLIBC_VERSION="2.12.1"
+CT_GLIBC_VERSION="2.17"
 CT_GLIBC_MIRRORS="$(CT_Mirrors GNU glibc)"
 CT_GLIBC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
 CT_GLIBC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
@@ -385,23 +392,24 @@ CT_GLIBC_2_23_or_older=y
 CT_GLIBC_older_than_2_23=y
 CT_GLIBC_2_20_or_older=y
 CT_GLIBC_older_than_2_20=y
+CT_GLIBC_2_17_or_later=y
 CT_GLIBC_2_17_or_older=y
-CT_GLIBC_older_than_2_17=y
-CT_GLIBC_2_14_or_older=y
-CT_GLIBC_older_than_2_14=y
+CT_GLIBC_later_than_2_14=y
+CT_GLIBC_2_14_or_later=y
 CT_GLIBC_DEP_KERNEL_HEADERS_VERSION=y
 CT_GLIBC_DEP_BINUTILS=y
 CT_GLIBC_DEP_GCC=y
 CT_GLIBC_DEP_PYTHON=y
 CT_GLIBC_HAS_NPTL_ADDON=y
 CT_GLIBC_HAS_PORTS_ADDON=y
-CT_GLIBC_HAS_PORTS_ADDON_EXTERNAL=y
 CT_GLIBC_HAS_LIBIDN_ADDON=y
 CT_GLIBC_USE_NPTL_ADDON=y
 # CT_GLIBC_USE_LIBIDN_ADDON is not set
+CT_GLIBC_HAS_OBSOLETE_RPC=y
 CT_GLIBC_EXTRA_CONFIG_ARRAY=""
 CT_GLIBC_CONFIGPARMS=""
 CT_GLIBC_EXTRA_CFLAGS=""
+CT_GLIBC_ENABLE_OBSOLETE_RPC=y
 # CT_GLIBC_DISABLE_VERSIONING is not set
 CT_GLIBC_OLDEST_ABI=""
 CT_GLIBC_FORCE_UNWIND=y
@@ -409,7 +417,13 @@ CT_GLIBC_FORCE_UNWIND=y
 # CT_GLIBC_KERNEL_VERSION_NONE is not set
 CT_GLIBC_KERNEL_VERSION_AS_HEADERS=y
 # CT_GLIBC_KERNEL_VERSION_CHOSEN is not set
-CT_GLIBC_MIN_KERNEL="2.6.32.71"
+CT_GLIBC_MIN_KERNEL="3.2.101"
+# CT_GLIBC_SSP_DEFAULT is not set
+# CT_GLIBC_SSP_NO is not set
+# CT_GLIBC_SSP_YES is not set
+# CT_GLIBC_SSP_ALL is not set
+# CT_GLIBC_SSP_STRONG is not set
+# CT_NEWLIB_USE_REDHAT is not set
 CT_ALL_LIBC_CHOICES="AVR_LIBC BIONIC GLIBC MINGW_W64 MOXIEBOX MUSL NEWLIB NONE UCLIBC"
 CT_LIBC_SUPPORT_THREADS_ANY=y
 CT_LIBC_SUPPORT_THREADS_NATIVE=y
index 6f9980dbc865b48a41038cb25e89b8f6d84d4a81..126c292b38ea1f7a179b5ddaea5762ddc648a715 100644 (file)
@@ -32,10 +32,16 @@ RUN add-apt-repository -y 'deb https://apt.dilos.org/dilos dilos2 main'
 ENV \
     AR_x86_64_fuchsia=x86_64-fuchsia-ar \
     CC_x86_64_fuchsia=x86_64-fuchsia-clang \
+    CFLAGS_x86_64_fuchsia="--target=x86_64-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot -I/usr/local/core-linux-amd64-fuchsia-sdk/pkg/fdio/include" \
     CXX_x86_64_fuchsia=x86_64-fuchsia-clang++ \
+    CXXFLAGS_x86_64_fuchsia="--target=x86_64-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot -I/usr/local/core-linux-amd64-fuchsia-sdk/pkg/fdio/include" \
+    LDFLAGS_x86_64_fuchsia="--target=x86_64-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot -L/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/lib" \
     AR_aarch64_fuchsia=aarch64-fuchsia-ar \
     CC_aarch64_fuchsia=aarch64-fuchsia-clang \
+    CFLAGS_aarch64_fuchsia="--target=aarch64-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/sysroot -I/usr/local/core-linux-amd64-fuchsia-sdk/pkg/fdio/include" \
     CXX_aarch64_fuchsia=aarch64-fuchsia-clang++ \
+    CXXFLAGS_aarch64_fuchsia="--target=aarch64-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/sysroot -I/usr/local/core-linux-amd64-fuchsia-sdk/pkg/fdio/include" \
+    LDFLAGS_aarch64_fuchsia="--target=aarch64-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/sysroot -L/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/lib" \
     AR_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-ar \
     CC_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-gcc \
     CXX_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-g++ \
@@ -89,14 +95,14 @@ RUN sh /scripts/sccache.sh
 
 ENV CARGO_TARGET_X86_64_FUCHSIA_AR /usr/local/bin/llvm-ar
 ENV CARGO_TARGET_X86_64_FUCHSIA_RUSTFLAGS \
--C link-arg=--sysroot=/usr/local/x86_64-fuchsia \
--C link-arg=-L/usr/local/x86_64-fuchsia/lib \
--C link-arg=-L/usr/local/lib/x86_64-fuchsia/lib
+-C link-arg=--sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot \
+-Lnative=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot/lib \
+-Lnative=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/lib
 ENV CARGO_TARGET_AARCH64_FUCHSIA_AR /usr/local/bin/llvm-ar
 ENV CARGO_TARGET_AARCH64_FUCHSIA_RUSTFLAGS \
--C link-arg=--sysroot=/usr/local/aarch64-fuchsia \
--C link-arg=-L/usr/local/aarch64-fuchsia/lib \
--C link-arg=-L/usr/local/lib/aarch64-fuchsia/lib
+-C link-arg=--sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/sysroot \
+-Lnative=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/sysroot/lib \
+-Lnative=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/lib
 
 ENV TARGETS=x86_64-fuchsia
 ENV TARGETS=$TARGETS,aarch64-fuchsia
index 73acdf5be6356733909ae059d71837f5c64be18d..80db925775424c0e052669c9fbc0cf2757a35278 100755 (executable)
@@ -3,52 +3,58 @@
 set -ex
 source shared.sh
 
-ZIRCON=e9a26dbc70d631029f8ee9763103910b7e3a2fe1
-
-mkdir -p zircon
-pushd zircon > /dev/null
-
-# Download sources
-git init
-git remote add origin https://github.com/rust-lang-nursery/mirror-google-fuchsia-zircon
-git fetch --depth=1 origin $ZIRCON
-git reset --hard FETCH_HEAD
-
-# Download toolchain
-./scripts/download-toolchain
-chmod -R a+rx prebuilt/downloads/clang+llvm-x86_64-linux
-cp -a prebuilt/downloads/clang+llvm-x86_64-linux/. /usr/local
-
-build() {
-  local arch="$1"
-
-  case "${arch}" in
-    x86_64) tgt="zircon-pc-x86-64" ;;
-    aarch64) tgt="zircon-qemu-arm64" ;;
-  esac
-
-  hide_output make -j$(getconf _NPROCESSORS_ONLN) $tgt
-  dst=/usr/local/${arch}-fuchsia
-  mkdir -p $dst
-  cp -a build-${tgt}/sysroot/include $dst/
-  cp -a build-${tgt}/sysroot/lib $dst/
+FUCHSIA_SDK_URL=https://chrome-infra-packages.appspot.com/dl/fuchsia/sdk/core/linux-amd64
+FUCHSIA_SDK_ID=4xjxrGUrDbQ6_zJwj6cDN1IbWsWV5aCQXC_zO_Hu0XkC
+FUCHSIA_SDK_SHA256=e318f1ac652b0db43aff32708fa70337521b5ac595e5a0905c2ff33bf1eed179
+FUCHSIA_SDK_USR_DIR=/usr/local/core-linux-amd64-fuchsia-sdk
+CLANG_DOWNLOAD_URL=\
+https://chrome-infra-packages.appspot.com/dl/fuchsia/third_party/clang/linux-amd64
+CLANG_DOWNLOAD_ID=vU0vNjSihOV4Q6taQYCpy03JXGiCyVwxen3rFMNMIgsC
+CLANG_DOWNLOAD_SHA256=bd4d2f3634a284e57843ab5a4180a9cb4dc95c6882c95c317a7deb14c34c220b
+
+install_clang() {
+  mkdir -p clang_download
+  pushd clang_download > /dev/null
+
+  # Download clang+llvm
+  curl -LO "${CLANG_DOWNLOAD_URL}/+/${CLANG_DOWNLOAD_ID}"
+  echo "$(echo ${CLANG_DOWNLOAD_SHA256}) ${CLANG_DOWNLOAD_ID}" | sha256sum --check --status
+  unzip -qq ${CLANG_DOWNLOAD_ID} -d clang-linux-amd64
+
+  # Other dists currently depend on our Clang... moving into /usr/local for other
+  #  dist usage instead of a Fuchsia /usr/local directory
+  chmod -R 777 clang-linux-amd64/.
+  cp -a clang-linux-amd64/. /usr/local
+
+  # CFLAGS and CXXFLAGS env variables in main Dockerfile handle sysroot linking
+  for arch in x86_64 aarch64; do
+    for tool in clang clang++; do
+      ln -s /usr/local/bin/${tool} /usr/local/bin/${arch}-fuchsia-${tool}
+    done
+    ln -s /usr/local/bin/llvm-ar /usr/local/bin/${arch}-fuchsia-ar
+  done
+
+  popd > /dev/null
+  rm -rf clang_download
 }
 
-# Build sysroot
-for arch in x86_64 aarch64; do
-  build ${arch}
-done
-
-popd > /dev/null
-rm -rf zircon
-
-for arch in x86_64 aarch64; do
-  for tool in clang clang++; do
-    cat >/usr/local/bin/${arch}-fuchsia-${tool} <<EOF
-#!/bin/sh
-${tool} --target=${arch}-fuchsia --sysroot=/usr/local/${arch}-fuchsia "\$@"
-EOF
-    chmod +x /usr/local/bin/${arch}-fuchsia-${tool}
-  done
-  ln -s /usr/local/bin/llvm-ar /usr/local/bin/${arch}-fuchsia-ar
-done
+install_zircon_libs() {
+  mkdir -p zircon
+  pushd zircon > /dev/null
+
+  # Download Fuchsia SDK (with Zircon libs)
+  curl -LO "${FUCHSIA_SDK_URL}/+/${FUCHSIA_SDK_ID}"
+  echo "$(echo ${FUCHSIA_SDK_SHA256}) ${FUCHSIA_SDK_ID}" | sha256sum --check --status
+  unzip -qq ${FUCHSIA_SDK_ID} -d core-linux-amd64
+
+  # Moving SDK into Docker's user-space
+  mkdir -p ${FUCHSIA_SDK_USR_DIR}
+  chmod -R 777 core-linux-amd64/.
+  cp -r core-linux-amd64/* ${FUCHSIA_SDK_USR_DIR}
+
+  popd > /dev/null
+  rm -rf zircon
+}
+
+hide_output install_clang
+hide_output install_zircon_libs
index b56776df1cbeb2c40af6129125d30b558a8c6ad0..973c43072bf40e5ee953c8fb2dccb0c6b9d46267 100644 (file)
@@ -1,48 +1,40 @@
-# We need recent curl, OpenSSL and CA certificates, so we can download further
-# dependencies in the debian:6 image. We use an ubuntu 20.04 image download
-# those.
-FROM ubuntu:20.04
-RUN apt-get update && \
-    apt-get install -y --no-install-recommends \
-        curl \
-        ca-certificates
-WORKDIR /tmp
-COPY host-x86_64/dist-x86_64-linux/download-openssl-curl.sh /tmp/
-RUN ./download-openssl-curl.sh
-
-# We use Debian 6 (glibc 2.11, kernel 2.6.32) as a common base for other
-# distros that still need Rust support: RHEL 6 (glibc 2.12, kernel 2.6.32) and
-# SLES 11 SP4 (glibc 2.11, kernel 3.0).
-FROM debian:6
+# We document platform support for minimum glibc 2.17 and kernel 3.2.
+# CentOS 7 has headers for kernel 3.10, but that's fine as long as we don't
+# actually use newer APIs in rustc or std without a fallback. It's more
+# important that we match glibc for ELF symbol versioning.
+FROM centos:7
 
 WORKDIR /build
 
-# Debian 6 is EOL and no longer available from the usual mirrors,
-# so we'll need to switch to http://archive.debian.org/
-RUN sed -i '/updates/d' /etc/apt/sources.list && \
-    sed -i 's/httpredir/archive/' /etc/apt/sources.list
-
-RUN apt-get update && \
-    apt-get install --allow-unauthenticated -y --no-install-recommends \
+RUN yum upgrade -y && \
+    yum install -y epel-release && \
+    yum install -y \
       automake \
       bzip2 \
       file \
-      g++ \
-      g++-multilib \
+      cmake3 \
       gcc \
-      gcc-multilib \
+      gcc-c++ \
       git \
-      lib32z1-dev \
-      libedit-dev \
-      libncurses-dev \
+      glibc-devel.i686 \
+      glibc-devel.x86_64 \
+      libedit-devel \
+      libstdc++-devel.i686 \
+      libstdc++-devel.x86_64 \
       make \
+      ncurses-devel \
+      openssl-devel \
       patch \
       perl \
-      pkg-config \
+      pkgconfig \
+      python3 \
       unzip \
       wget \
-      xz-utils \
-      zlib1g-dev
+      xz \
+      zlib-devel.i686 \
+      zlib-devel.x86_64
+
+RUN mkdir -p /rustroot/bin && ln -s /usr/bin/cmake3 /rustroot/bin/cmake
 
 ENV PATH=/rustroot/bin:$PATH
 ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib32:/rustroot/lib
@@ -51,46 +43,9 @@ WORKDIR /tmp
 RUN mkdir /home/user
 COPY host-x86_64/dist-x86_64-linux/shared.sh /tmp/
 
-# We need a build of openssl which supports SNI to download artifacts from
-# static.rust-lang.org. This'll be used to link into libcurl below (and used
-# later as well), so build a copy of OpenSSL with dynamic libraries into our
-# generic root.
-COPY --from=0 /tmp/openssl.tar.gz /tmp/openssl.tar.gz
-COPY host-x86_64/dist-x86_64-linux/build-openssl.sh /tmp/
-RUN ./build-openssl.sh
-
-# The `curl` binary on Debian 6 doesn't support SNI which is needed for fetching
-# some https urls we have, so install a new version of libcurl + curl which is
-# using the openssl we just built previously.
-#
-# Note that we also disable a bunch of optional features of curl that we don't
-# really need.
-COPY --from=0 /tmp/curl.tar.xz /tmp/curl.tar.xz
-COPY host-x86_64/dist-x86_64-linux/build-curl.sh /tmp/
-RUN ./build-curl.sh
-
-# Use up-to-date curl CA bundle
-COPY --from=0 /tmp/cacert.pem /tmp/cacert.pem
-ENV CURL_CA_BUNDLE /tmp/cacert.pem
-
-# binutils < 2.22 has a bug where the 32-bit executables it generates
-# immediately segfault in Rust, so we need to install our own binutils.
-#
-# See https://github.com/rust-lang/rust/issues/20440 for more info
-COPY host-x86_64/dist-x86_64-linux/build-binutils.sh /tmp/
-RUN ./build-binutils.sh
-
 # Need at least GCC 5.1 to compile LLVM nowadays
 COPY host-x86_64/dist-x86_64-linux/build-gcc.sh /tmp/
-RUN ./build-gcc.sh && apt-get remove -y gcc g++
-
-COPY host-x86_64/dist-x86_64-linux/build-python.sh /tmp/
-# Build Python 3 needed for LLVM 12.
-RUN ./build-python.sh 3.9.1
-
-# LLVM needs cmake 3.13.4 or higher.
-COPY host-x86_64/dist-x86_64-linux/build-cmake.sh /tmp/
-RUN ./build-cmake.sh
+RUN ./build-gcc.sh && yum remove -y gcc gcc-c++
 
 # Now build LLVM+Clang, afterwards configuring further compilations to use the
 # clang/clang++ compilers.
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-binutils.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-binutils.sh
deleted file mode 100755 (executable)
index b537824..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/usr/bin/env bash
-
-set -ex
-
-source shared.sh
-
-VERSION=2.26.1
-
-curl https://ftp.gnu.org/gnu/binutils/binutils-$VERSION.tar.bz2 | tar xfj -
-
-mkdir binutils-build
-cd binutils-build
-hide_output ../binutils-$VERSION/configure --prefix=/rustroot
-hide_output make -j$(nproc)
-hide_output make install
-
-cd ..
-rm -rf binutils-build
-rm -rf binutils-$VERSION
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-cmake.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-cmake.sh
deleted file mode 100755 (executable)
index 2f6b1fa..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/usr/bin/env bash
-
-set -ex
-source shared.sh
-
-CMAKE=3.13.4
-curl -L https://github.com/Kitware/CMake/releases/download/v$CMAKE/cmake-$CMAKE.tar.gz | tar xzf -
-
-mkdir cmake-build
-cd cmake-build
-hide_output ../cmake-$CMAKE/configure --prefix=/rustroot
-hide_output make -j$(nproc)
-hide_output make install
-
-cd ..
-rm -rf cmake-build
-rm -rf cmake-$CMAKE
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-curl.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-curl.sh
deleted file mode 100755 (executable)
index 88ee96e..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/usr/bin/env bash
-
-set -ex
-source shared.sh
-
-tar xJf curl.tar.xz
-
-mkdir curl-build
-cd curl-build
-hide_output ../curl-*/configure \
-      --prefix=/rustroot \
-      --with-ssl=/rustroot \
-      --disable-sspi \
-      --disable-gopher \
-      --disable-smtp \
-      --disable-smb \
-      --disable-imap \
-      --disable-pop3 \
-      --disable-tftp \
-      --disable-telnet \
-      --disable-manual \
-      --disable-dict \
-      --disable-rtsp \
-      --disable-ldaps \
-      --disable-ldap
-hide_output make -j$(nproc)
-hide_output make install
-
-cd ..
-rm -rf curl-build
-rm -rf curl-*
index 7992ec3b991883718bd02999f92d173b2e908e4d..9932b2505662278b56d57749185fce2cb177e27c 100755 (executable)
@@ -39,3 +39,8 @@ ln -s gcc /rustroot/bin/cc
 cd ..
 rm -rf gcc-build
 rm -rf gcc-$GCC
+
+# FIXME: clang doesn't find 32-bit libraries in /rustroot/lib,
+# but it does look all the way under /rustroot/lib/[...]/32,
+# so we can link stuff there to help it out.
+ln /rustroot/lib/*.{a,so} -rst /rustroot/lib/gcc/x86_64-pc-linux-gnu/$GCC/32/
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-openssl.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-openssl.sh
deleted file mode 100755 (executable)
index b48b5c4..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/usr/bin/env bash
-
-set -ex
-source shared.sh
-
-tar xzf openssl.tar.gz
-
-cd openssl-*
-hide_output ./config --prefix=/rustroot shared -fPIC
-hide_output make -j$(nproc)
-hide_output make install
-cd ..
-rm -rf openssl-*
-
-# Make the system cert collection available to the new install.
-ln -nsf /etc/pki/tls/cert.pem /rustroot/ssl/
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-python.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-python.sh
deleted file mode 100755 (executable)
index 9a203be..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/usr/bin/env bash
-
-set -ex
-source shared.sh
-
-VERSION=$1
-curl https://www.python.org/ftp/python/$VERSION/Python-$VERSION.tgz | \
-  tar xzf -
-
-mkdir python-build
-cd python-build
-
-# Gotta do some hackery to tell python about our custom OpenSSL build, but other
-# than that fairly normal.
-CFLAGS='-I /rustroot/include' LDFLAGS='-L /rustroot/lib -L /rustroot/lib64' \
-    hide_output ../Python-$VERSION/configure --prefix=/rustroot
-hide_output make -j$(nproc)
-hide_output make install
-
-cd ..
-rm -rf python-build
-rm -rf Python-$VERSION
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/download-openssl-curl.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/download-openssl-curl.sh
deleted file mode 100755 (executable)
index ca40a8c..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/usr/bin/env bash
-
-set -ex
-
-OPENSSL_VERSION=1.0.2k
-CURL_VERSION=7.66.0
-
-curl -f https://ci-mirrors.rust-lang.org/rustc/openssl-$OPENSSL_VERSION.tar.gz -o openssl.tar.gz
-curl -f https://ci-mirrors.rust-lang.org/rustc/curl-$CURL_VERSION.tar.xz -o curl.tar.xz
-curl -f https://curl.se/ca/cacert.pem -o cacert.pem
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/llvm-project-centos.patch b/src/ci/docker/host-x86_64/dist-x86_64-linux/llvm-project-centos.patch
deleted file mode 100644 (file)
index 5265006..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-diff --git a/clang/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp b/clang/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp
-index 176d6d6abf3..a6d63bf24b8 100644
---- a/clang/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp
-+++ b/clang/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp
-@@ -33,6 +33,13 @@ namespace {
- using namespace llvm;
- using namespace clang;
-+#define EPOLL_CLOEXEC -1
-+#define IN_CLOEXEC -1
-+#define O_CLOEXEC -1
-+static int epoll_create1(int flags) { return -1; }
-+static int inotify_init1(int flags) { return -1; }
-+static int pipe2(int *fds, int flags) { return -1; }
-+
- /// Pipe for inter-thread synchronization - for epoll-ing on multiple
- /// conditions. It is meant for uni-directional 1:1 signalling - specifically:
- /// no multiple consumers, no data passing. Thread waiting for signal should
index 92bdc9811fd52140127964b1c016cd1a305d103d..fed4be4c30a74163893253a0f5f72d3e19d801b4 100644 (file)
@@ -21,5 +21,6 @@ ENV \
 
 ENV HOSTS=x86_64-unknown-netbsd
 
-ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
+ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs \
+    --set llvm.allow-old-toolchain
 ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS
index 0182ebb8b597e7249ca12f5fc71b35214d2993ab..1f8d0a64ea48e0ecc380ea6411c21eea80ed36b2 100644 (file)
@@ -27,6 +27,7 @@ RUN mkdir -p /config
 RUN echo "[rust]" > /config/nopt-std-config.toml
 RUN echo "optimize = false" >> /config/nopt-std-config.toml
 
-ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu --disable-optimize-tests
+ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu --disable-optimize-tests \
+    --set llvm.allow-old-toolchain
 ENV SCRIPT python3 ../x.py test --stage 0 --config /config/nopt-std-config.toml library/std \
   && python3 ../x.py --stage 2 test
index feaab819bdda30ab3d7fca2615f96dc29e42b265..7bca0398dea7c6679bcf8e6286b2b5c116392340 100644 (file)
@@ -23,7 +23,8 @@ RUN sh /scripts/sccache.sh
 COPY scripts/cmake.sh /scripts/
 RUN /scripts/cmake.sh
 
-ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu
+ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu \
+    --set llvm.allow-old-toolchain
 # Exclude some tests that are unlikely to be platform specific, to speed up
 # this slow job.
 ENV SCRIPT python3 ../x.py --stage 2 test \
index ee3cd092f4cdbcec937c6e4ec8f913883cab2708..bfc6975c19dc9b174e0b6deaf3ecb4beeb4ec474 100644 (file)
@@ -26,5 +26,6 @@ RUN sh /scripts/sccache.sh
 COPY scripts/cmake.sh /scripts/
 RUN /scripts/cmake.sh
 
-ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu
+ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu \
+    --set llvm.allow-old-toolchain
 ENV RUST_CHECK_TARGET check-aux
index 09d9cda02bda65efb072fdf77e71e7929eec0494..4bb4042cd7e2ffa75a0986c2a7dd3a12dc560c35 100644 (file)
@@ -22,6 +22,7 @@ RUN sh /scripts/sccache.sh
 COPY scripts/cmake.sh /scripts/
 RUN /scripts/cmake.sh
 
-ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu --set rust.ignore-git=false
+ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu --set rust.ignore-git=false \
+    --set llvm.allow-old-toolchain
 ENV SCRIPT python3 ../x.py --stage 2 test distcheck
 ENV DIST_SRC 1
index df1fbc29cf5e6fd0a39ed10108b58c8f449c1a7f..8de9045c3baa73e768223e97192fafc79b4eba30 100644 (file)
@@ -1,6 +1,8 @@
 FROM ubuntu:20.04
 
 ARG DEBIAN_FRONTEND=noninteractive
+
+# NOTE: intentionally installs both python2 and python3 so we can test support for both.
 RUN apt-get update && apt-get install -y --no-install-recommends \
   g++ \
   gcc-multilib \
@@ -10,6 +12,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   curl \
   ca-certificates \
   python2.7 \
+  python3.9 \
   git \
   cmake \
   sudo \
@@ -23,6 +26,14 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   xz-utils \
   nodejs
 
+# Install powershell so we can test x.ps1 on Linux
+RUN apt-get update && \
+    apt-get install -y apt-transport-https software-properties-common && \
+    curl -s "https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/packages-microsoft-prod.deb" > packages-microsoft-prod.deb && \
+    dpkg -i packages-microsoft-prod.deb && \
+    apt-get update && \
+    apt-get install -y powershell
+
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
@@ -33,21 +44,22 @@ ENV RUST_CONFIGURE_ARGS \
       --enable-llvm-link-shared \
       --set rust.thin-lto-import-instr-limit=10
 
-ENV SCRIPT python2.7 ../x.py --stage 2 test --exclude src/tools/tidy && \
+# NOTE: intentionally uses all of `x.py`, `x.sh`, and `x.ps1` to make sure they all work on Linux.
+ENV SCRIPT ../x.py --stage 2 test --exclude src/tools/tidy && \
            # Run the `mir-opt` tests again but this time for a 32-bit target.
            # This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have
            # both 32-bit and 64-bit outputs updated by the PR author, before
            # the PR is approved and tested for merging.
            # It will also detect tests lacking `// EMIT_MIR_FOR_EACH_BIT_WIDTH`,
            # despite having different output on 32-bit vs 64-bit targets.
-           python2.7 ../x.py --stage 2 test src/test/mir-opt \
+           ../x.sh --stage 2 test src/test/mir-opt \
                              --host='' --target=i686-unknown-linux-gnu && \
            # Run the UI test suite again, but in `--pass=check` mode
            #
            # This is intended to make sure that both `--pass=check` continues to
            # work.
            #
-           python2.7 ../x.py --stage 2 test src/test/ui --pass=check \
+           ../x.ps1 --stage 2 test src/test/ui --pass=check \
                              --host='' --target=i686-unknown-linux-gnu && \
            # Run tidy at the very end, after all the other tests.
            python2.7 ../x.py --stage 2 test src/tools/tidy
index 2358091a6dfbf86cd2847625b48b9c6fdf18738a..f442a477a7b1e121a00f8da94ae63b40677cd90d 100644 (file)
@@ -81,6 +81,7 @@ COPY host-x86_64/x86_64-gnu-tools/browser-ui-test.version /tmp/
 RUN npm install -g browser-ui-test@$(head -n 1 /tmp/browser-ui-test.version) --unsafe-perm=true
 
 ENV RUST_CONFIGURE_ARGS \
+  --set llvm.allow-old-toolchain \
   --build=x86_64-unknown-linux-gnu \
   --save-toolstates=/tmp/toolstate/toolstates.json
 
index cb660881b075fa54a41091fb06f4f651ed054070..a21400cc4726d04e5161bb76a4bea7e6bb288843 100644 (file)
@@ -134,7 +134,7 @@ x--expand-yaml-anchors--remove:
         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'
+        if: success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' && github.ref != 'refs/heads/try-perf'
         <<: *step
 
       - name: collect CPU statistics
@@ -596,14 +596,18 @@ jobs:
 
           - name: i686-mingw-1
             env:
-              RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu
+              RUST_CONFIGURE_ARGS: >-
+                --build=i686-pc-windows-gnu
+                --set llvm.allow-old-toolchain
               SCRIPT: make ci-mingw-subset-1
               CUSTOM_MINGW: 1
             <<: *job-windows-xl
 
           - name: i686-mingw-2
             env:
-              RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu
+              RUST_CONFIGURE_ARGS: >-
+                --build=i686-pc-windows-gnu
+                --set llvm.allow-old-toolchain
               SCRIPT: make ci-mingw-subset-2
               CUSTOM_MINGW: 1
             <<: *job-windows-xl
@@ -611,14 +615,20 @@ jobs:
           - name: x86_64-mingw-1
             env:
               SCRIPT: make ci-mingw-subset-1
-              RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-profiler
+              RUST_CONFIGURE_ARGS: >-
+                --build=x86_64-pc-windows-gnu
+                --enable-profiler
+                --set llvm.allow-old-toolchain
               CUSTOM_MINGW: 1
             <<: *job-windows-xl
 
           - name: x86_64-mingw-2
             env:
               SCRIPT: make ci-mingw-subset-2
-              RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-profiler
+              RUST_CONFIGURE_ARGS: >-
+                --build=x86_64-pc-windows-gnu
+                --enable-profiler
+                --set llvm.allow-old-toolchain
               CUSTOM_MINGW: 1
             <<: *job-windows-xl
 
@@ -663,7 +673,11 @@ jobs:
 
           - name: dist-i686-mingw
             env:
-              RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-full-tools --enable-profiler
+              RUST_CONFIGURE_ARGS: >-
+                --build=i686-pc-windows-gnu
+                --enable-full-tools
+                --enable-profiler
+                --set llvm.allow-old-toolchain
               SCRIPT: python x.py dist
               CUSTOM_MINGW: 1
               DIST_REQUIRE_ALL_TOOLS: 1
@@ -672,7 +686,11 @@ jobs:
           - name: dist-x86_64-mingw
             env:
               SCRIPT: python x.py dist
-              RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler
+              RUST_CONFIGURE_ARGS: >-
+                --build=x86_64-pc-windows-gnu
+                --enable-full-tools
+                --enable-profiler
+                --set llvm.allow-old-toolchain
               CUSTOM_MINGW: 1
               DIST_REQUIRE_ALL_TOOLS: 1
             <<: *job-windows-xl
index 3eb4b8f9058328183d498b60c858cc173bf238c1..f6cb8f8a6da65727873f872fb9c46c44a86a61c9 100755 (executable)
@@ -36,10 +36,7 @@ function fetch_github_commit_archive {
     rm $cached
 }
 
-# Archive downloads are temporarily disabled due to sudden 504
-# gateway timeout errors.
-# included="src/llvm-project src/doc/book src/doc/rust-by-example"
-included=""
+included="src/llvm-project src/doc/book src/doc/rust-by-example"
 modules="$(git config --file .gitmodules --get-regexp '\.path$' | cut -d' ' -f2)"
 modules=($modules)
 use_git=""
@@ -63,9 +60,9 @@ done
 retry sh -c "git submodule deinit -f $use_git && \
     git submodule sync && \
     git submodule update -j 16 --init --recursive --depth 1 $use_git"
-STATUS=0
-for pid in ${bg_pids[*]}
-do
-    wait $pid || STATUS=1
-done
-exit ${STATUS}
+STATUS=0
+for pid in ${bg_pids[*]}
+do
+    wait $pid || STATUS=1
+done
+exit ${STATUS}
index 766979590da8100998f0d662499d4a901d8d1640..befe6840874311635c417cf731377f07234ee373 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 766979590da8100998f0d662499d4a901d8d1640
+Subproject commit befe6840874311635c417cf731377f07234ee373
index ff41324ef2645ee68ddac4dcbc0a83c4cba54b53..534af3f85bb96383266016ed54961f4b42db108d 100644 (file)
@@ -44,18 +44,18 @@ The optional \fIKIND\fR can be one of \fIstatic\fR, \fIdylib\fR, or
 \fIframework\fR.
 If omitted, \fIdylib\fR is assumed.
 .TP
-\fB\-\-crate\-type\fR [bin|lib|rlib|dylib|cdylib|staticlib]
+\fB\-\-crate\-type\fR [bin|lib|rlib|dylib|cdylib|staticlib|proc\-macro]
 Comma separated list of types of crates for the compiler to emit.
 .TP
 \fB\-\-crate\-name\fR \fINAME\fR
 Specify the name of the crate being built.
 .TP
-\fB\-\-emit\fR [asm|llvm\-bc|llvm\-ir|obj|link|dep\-info|mir][=\fIPATH\fR]
+\fB\-\-emit\fR [asm|llvm\-bc|llvm\-ir|obj|metadata|link|dep\-info|mir][=\fIPATH\fR]
 Configure the output that \fBrustc\fR will produce. Each emission may also have
 an optional explicit output \fIPATH\fR specified for that particular emission
 kind. This path takes precedence over the \fB-o\fR option.
 .TP
-\fB\-\-print\fR [crate\-name|\:file\-names|\:sysroot|\:cfg|\:target\-list|\:target\-cpus|\:target\-features|\:relocation\-models|\:code\-models|\:tls\-models|\:target\-spec\-json|\:native\-static\-libs]
+\fB\-\-print\fR [crate\-name|\:file\-names|\:sysroot|\:target\-libdir|\:cfg|\:target\-list|\:target\-cpus|\:target\-features|\:relocation\-models|\:code\-models|\:tls\-models|\:target\-spec\-json|\:native\-static\-libs|\:stack\-protector\-strategies|\:link\-args]
 Comma separated list of compiler information to print on stdout.
 .TP
 \fB\-g\fR
index a92be0fef439b3d8e0468d82cb24812d303520a0..f3d3953bf3b158d596c96d55ce5366f9f3f972e9 160000 (submodule)
@@ -1 +1 @@
-Subproject commit a92be0fef439b3d8e0468d82cb24812d303520a0
+Subproject commit f3d3953bf3b158d596c96d55ce5366f9f3f972e9
index 3155db49b0d57cd82c65456ac210b69ecec5ccb1..ee342dc91e1ba1bb1e1f1318f84bbe3bfac04798 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 3155db49b0d57cd82c65456ac210b69ecec5ccb1
+Subproject commit ee342dc91e1ba1bb1e1f1318f84bbe3bfac04798
index d5201cddace979b299ec1bf9fd8997338151aa9d..04f3cf0bb2f5a6ee2bfc4b1a6a6cd8c11d1c5531 160000 (submodule)
@@ -1 +1 @@
-Subproject commit d5201cddace979b299ec1bf9fd8997338151aa9d
+Subproject commit 04f3cf0bb2f5a6ee2bfc4b1a6a6cd8c11d1c5531
index d168af60c2df0f96606f55831452326e2868e4c9..4e6bc41daa712407609ac39121e95cb5d6ab5640 100644 (file)
@@ -18,6 +18,7 @@
     - [aarch64-apple-ios-sim](platform-support/aarch64-apple-ios-sim.md)
     - [\*-apple-watchos\*](platform-support/apple-watchos.md)
     - [aarch64-nintendo-switch-freestanding](platform-support/aarch64-nintendo-switch-freestanding.md)
+    - [armv4t-none-eabi](platform-support/armv4t-none-eabi.md)
     - [armv6k-nintendo-3ds](platform-support/armv6k-nintendo-3ds.md)
     - [armv7-unknown-linux-uclibceabi](platform-support/armv7-unknown-linux-uclibceabi.md)
     - [armv7-unknown-linux-uclibceabihf](platform-support/armv7-unknown-linux-uclibceabihf.md)
index bc04dfd4433f6c463a9efed9b851e19389efd22b..f05ff3f1b6b4e5c95ec60a6b0a0973a43cc58fb2 100644 (file)
@@ -89,9 +89,9 @@ but it is not guaranteed. If you need whole archive semantics use `+whole-archiv
 This modifier is only compatible with the `static` linking kind.
 Using any other kind will result in a compiler error.
 
-When building a rlib or staticlib `+bundle` means that all object files from the native static
-library will be added to the rlib or staticlib archive, and then used from it during linking of
-the final binary.
+When building a rlib or staticlib `+bundle` means that the native static library
+will be packed into the rlib or staticlib archive, and then retrieved from there
+during linking of the final binary.
 
 When building a rlib `-bundle` means that the native static library is registered as a dependency
 of that rlib "by name", and object files from it are included only during linking of the final
index 9c644dd404dc428d57b7a62a68d740041c9a0111..b1854b22a7cd694b92476d87ff9854dd547d7b96 100644 (file)
@@ -30,7 +30,7 @@ Using `rustc` directly:
 # Compile the Rust staticlib
 rustc --crate-type=staticlib -Clinker-plugin-lto -Copt-level=2 ./lib.rs
 # Compile the C code with `-flto=thin`
-clang -c -O2 -flto=thin -o main.o ./main.c
+clang -c -O2 -flto=thin -o cmain.o ./cmain.c
 # Link everything, making sure that we use an appropriate linker
 clang -flto=thin -fuse-ld=lld -L . -l"name-of-your-rust-lib" -o main -O2 ./cmain.o
 ```
@@ -41,7 +41,7 @@ Using `cargo`:
 # Compile the Rust staticlib
 RUSTFLAGS="-Clinker-plugin-lto" cargo build --release
 # Compile the C code with `-flto=thin`
-clang -c -O2 -flto=thin -o main.o ./main.c
+clang -c -O2 -flto=thin -o cmain.o ./cmain.c
 # Link everything, making sure that we use an appropriate linker
 clang -flto=thin -fuse-ld=lld -L . -l"name-of-your-rust-lib" -o main -O2 ./cmain.o
 ```
index 7a03238f13dff013976fb87b8477f4ff17943a21..01489e9aafb255f1a2785837c7de9f25d4958db6 100644 (file)
@@ -30,14 +30,14 @@ All tier 1 targets with host tools support the full standard library.
 
 target | notes
 -------|-------
-`aarch64-unknown-linux-gnu` | ARM64 Linux (kernel 4.2, glibc 2.17+) [^missing-stack-probes]
+`aarch64-unknown-linux-gnu` | ARM64 Linux (kernel 4.1, glibc 2.17+) [^missing-stack-probes]
 `i686-pc-windows-gnu` | 32-bit MinGW (Windows 7+) [^windows-support]
 `i686-pc-windows-msvc` | 32-bit MSVC (Windows 7+) [^windows-support]
-`i686-unknown-linux-gnu` | 32-bit Linux (kernel 2.6.32+, glibc 2.11+)
+`i686-unknown-linux-gnu` | 32-bit Linux (kernel 3.2+, glibc 2.17+)
 `x86_64-apple-darwin` | 64-bit macOS (10.7+, Lion+)
 `x86_64-pc-windows-gnu` | 64-bit MinGW (Windows 7+) [^windows-support]
 `x86_64-pc-windows-msvc` | 64-bit MSVC (Windows 7+) [^windows-support]
-`x86_64-unknown-linux-gnu` | 64-bit Linux (kernel 2.6.32+, glibc 2.11+)
+`x86_64-unknown-linux-gnu` | 64-bit Linux (kernel 3.2+, glibc 2.17+)
 
 [^missing-stack-probes]: Stack probes support is missing on
   `aarch64-unknown-linux-gnu`, but it's planned to be implemented in the near
@@ -90,11 +90,11 @@ target | notes
 `mips64-unknown-linux-gnuabi64` | MIPS64 Linux, n64 ABI (kernel 4.4, glibc 2.23)
 `mips64el-unknown-linux-gnuabi64` | MIPS64 (LE) Linux, n64 ABI (kernel 4.4, glibc 2.23)
 `mipsel-unknown-linux-gnu` | MIPS (LE) Linux (kernel 4.4, glibc 2.23)
-`powerpc-unknown-linux-gnu` | PowerPC Linux (kernel 2.6.32, glibc 2.11)
-`powerpc64-unknown-linux-gnu` | PPC64 Linux (kernel 2.6.32, glibc 2.11)
+`powerpc-unknown-linux-gnu` | PowerPC Linux (kernel 3.2, glibc 2.17)
+`powerpc64-unknown-linux-gnu` | PPC64 Linux (kernel 3.2, glibc 2.17)
 `powerpc64le-unknown-linux-gnu` | PPC64LE Linux (kernel 3.10, glibc 2.17)
 `riscv64gc-unknown-linux-gnu` | RISC-V Linux (kernel 4.20, glibc 2.29)
-`s390x-unknown-linux-gnu` | S390x Linux (kernel 2.6.32, glibc 2.12)
+`s390x-unknown-linux-gnu` | S390x Linux (kernel 3.2, glibc 2.17)
 `x86_64-unknown-freebsd` | 64-bit FreeBSD
 `x86_64-unknown-illumos` | illumos
 `x86_64-unknown-linux-musl` | 64-bit Linux with MUSL
@@ -283,7 +283,7 @@ target | std | host | notes
 `riscv32imc-esp-espidf` | ✓ |  | RISC-V ESP-IDF
 `riscv64gc-unknown-freebsd` |   |   | RISC-V FreeBSD
 `riscv64gc-unknown-linux-musl` |   |   | RISC-V Linux (kernel 4.20, musl 1.2.0)
-`s390x-unknown-linux-musl` |  |  | S390x Linux (kernel 2.6.32, MUSL)
+`s390x-unknown-linux-musl` |  |  | S390x Linux (kernel 3.2, MUSL)
 `sparc-unknown-linux-gnu` | ✓ |  | 32-bit SPARC Linux
 `sparc64-unknown-netbsd` | ✓ | ✓ | NetBSD/sparc64
 [`sparc64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/sparc64
diff --git a/src/doc/rustc/src/platform-support/armv4t_none_eabi.md b/src/doc/rustc/src/platform-support/armv4t_none_eabi.md
new file mode 100644 (file)
index 0000000..cf831e1
--- /dev/null
@@ -0,0 +1,70 @@
+# armv4t-none-eabi
+
+Tier 3
+
+Bare-metal target for any cpu in the ARMv4T architecture family, supporting
+ARM/Thumb code interworking (aka `a32`/`t32`), with ARM code as the default code
+generation.
+
+In particular this supports the Gameboy Advance (GBA), but there's nothing GBA
+specific with this target, so any ARMv4T device should work fine.
+
+## Target Maintainers
+
+* [@Lokathor](https://github.com/lokathor)
+
+## Requirements
+
+The target is cross-compiled, and uses static linking.
+
+The linker that comes with rustc cannot link for this platform (the platform is
+too old). You will need the `arm-none-eabi-ld` linker from a GNU Binutils
+targeting ARM. This can be obtained for Windows/Mac/Linux from the [ARM
+Developer Website][arm-dev], or possibly from your OS's package manager.
+
+[arm-dev]: https://developer.arm.com/Tools%20and%20Software/GNU%20Toolchain
+
+This target doesn't provide a linker script, you'll need to bring your own
+according to the specific device you want to target. Pass
+`-Clink-arg=-Tyour_script.ld` as a rustc argument to make the linker use
+`your_script.ld` during linking.
+
+## Building Rust Programs
+
+Because it is Tier 3, rust does not yet ship pre-compiled artifacts for this target.
+
+Just use the `build-std` nightly cargo feature to build the `core` library. You
+can pass this as a command line argument to cargo, or your `.cargo/config.toml`
+file might include the following lines:
+
+```toml
+[unstable]
+build-std = ["core"]
+```
+
+Most of `core` should work as expected, with the following notes:
+* the target is "soft float", so `f32` and `f64` operations are emulated in
+  software.
+* integer division is also emulated in software.
+* the target is old enough that it doesn't have atomic instructions.
+
+Rust programs are output as ELF files.
+
+For running on hardware, you'll generally need to extract the "raw" program code
+out of the ELF and into a file of its own. The `objcopy` program provided as
+part of the GNU Binutils can do this:
+
+```shell
+arm-none-eabi-objcopy --output-target binary [in_file] [out_file]
+```
+
+## Testing
+
+This is a cross-compiled target that you will need to emulate during testing.
+
+Because this is a device-agnostic target, and the exact emulator that you'll
+need depends on the specific device you want to run your code on.
+
+For example, when programming for the Gameboy Advance, the
+[mgba-test-runner](https://github.com/agbrs/agb) program could be used to make a
+normal set of rust tests be run within the `mgba` emulator.
index 343dd0387f47987c011c2334c80f0c8d0f914ea4..a705e2384959f1b8ad56db2d1a2ce3d2e44d9fc7 100644 (file)
@@ -88,8 +88,8 @@ def check_type(ty):
                         for bound in binding["binding"]["constraint"]:
                             check_generic_bound(bound)
             elif "parenthesized" in args:
-                for ty in args["parenthesized"]["inputs"]:
-                    check_type(ty)
+                for input_ty in args["parenthesized"]["inputs"]:
+                    check_type(input_ty)
                 if args["parenthesized"]["output"]:
                     check_type(args["parenthesized"]["output"])
         if not valid_id(ty["inner"]["id"]):
index 5fe2c9ab4e37b3bd607a46cce346d437f7f9e569..a94520b121926e254adfe628c76a889063ea4783 100644 (file)
@@ -24,7 +24,10 @@ pub(crate) struct AutoTraitFinder<'a, 'tcx> {
     pub(crate) cx: &'a mut core::DocContext<'tcx>,
 }
 
-impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
+impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx>
+where
+    'tcx: 'a, // should be an implied bound; rustc bug #98852.
+{
     pub(crate) fn new(cx: &'a mut core::DocContext<'tcx>) -> Self {
         AutoTraitFinder { cx }
     }
@@ -120,7 +123,7 @@ fn generate_for_trait(
             kind: Box::new(ImplItem(Box::new(Impl {
                 unsafety: hir::Unsafety::Normal,
                 generics: new_generics,
-                trait_: Some(trait_ref.clean(self.cx)),
+                trait_: Some(clean_trait_ref_with_bindings(self.cx, trait_ref, &[])),
                 for_: clean_middle_ty(ty, self.cx, None),
                 items: Vec::new(),
                 polarity,
@@ -345,15 +348,13 @@ fn extract_for_generics(&self, pred: ty::Predicate<'tcx>) -> FxHashSet<GenericPa
     fn make_final_bounds(
         &self,
         ty_to_bounds: FxHashMap<Type, FxHashSet<GenericBound>>,
-        ty_to_fn: FxHashMap<Type, (Option<PolyTrait>, Option<Type>)>,
+        ty_to_fn: FxHashMap<Type, (PolyTrait, Option<Type>)>,
         lifetime_to_bounds: FxHashMap<Lifetime, FxHashSet<GenericBound>>,
     ) -> Vec<WherePredicate> {
         ty_to_bounds
             .into_iter()
             .flat_map(|(ty, mut bounds)| {
-                if let Some(data) = ty_to_fn.get(&ty) {
-                    let (poly_trait, output) =
-                        (data.0.as_ref().unwrap().clone(), data.1.as_ref().cloned().map(Box::new));
+                if let Some((ref poly_trait, ref output)) = ty_to_fn.get(&ty) {
                     let mut new_path = poly_trait.trait_.clone();
                     let last_segment = new_path.segments.pop().expect("segments were empty");
 
@@ -371,8 +372,9 @@ fn make_final_bounds(
                         GenericArgs::Parenthesized { inputs, output } => (inputs, output),
                     };
 
+                    let output = output.as_ref().cloned().map(Box::new);
                     if old_output.is_some() && old_output != output {
-                        panic!("Output mismatch for {:?} {:?} {:?}", ty, old_output, data.1);
+                        panic!("Output mismatch for {:?} {:?} {:?}", ty, old_output, output);
                     }
 
                     let new_params = GenericArgs::Parenthesized { inputs: old_input, output };
@@ -382,7 +384,10 @@ fn make_final_bounds(
                         .push(PathSegment { name: last_segment.name, args: new_params });
 
                     bounds.insert(GenericBound::TraitBound(
-                        PolyTrait { trait_: new_path, generic_params: poly_trait.generic_params },
+                        PolyTrait {
+                            trait_: new_path,
+                            generic_params: poly_trait.generic_params.clone(),
+                        },
                         hir::TraitBoundModifier::None,
                     ));
                 }
@@ -468,10 +473,10 @@ fn param_env_to_generics(
         let mut lifetime_to_bounds: FxHashMap<_, FxHashSet<_>> = Default::default();
         let mut ty_to_traits: FxHashMap<Type, FxHashSet<Path>> = Default::default();
 
-        let mut ty_to_fn: FxHashMap<Type, (Option<PolyTrait>, Option<Type>)> = Default::default();
+        let mut ty_to_fn: FxHashMap<Type, (PolyTrait, Option<Type>)> = Default::default();
 
         for p in clean_where_predicates {
-            let (orig_p, p) = (p, p.clean(self.cx));
+            let (orig_p, p) = (p, clean_predicate(p, self.cx));
             if p.is_none() {
                 continue;
             }
@@ -532,8 +537,8 @@ fn param_env_to_generics(
                         if is_fn {
                             ty_to_fn
                                 .entry(ty.clone())
-                                .and_modify(|e| *e = (Some(poly_trait.clone()), e.1.clone()))
-                                .or_insert(((Some(poly_trait.clone())), None));
+                                .and_modify(|e| *e = (poly_trait.clone(), e.1.clone()))
+                                .or_insert(((poly_trait.clone()), None));
 
                             ty_to_bounds.entry(ty.clone()).or_default();
                         } else {
@@ -556,7 +561,13 @@ fn param_env_to_generics(
                                     .and_modify(|e| {
                                         *e = (e.0.clone(), Some(rhs.ty().unwrap().clone()))
                                     })
-                                    .or_insert((None, Some(rhs.ty().unwrap().clone())));
+                                    .or_insert((
+                                        PolyTrait {
+                                            trait_: trait_.clone(),
+                                            generic_params: Vec::new(),
+                                        },
+                                        Some(rhs.ty().unwrap().clone()),
+                                    ));
                                 continue;
                             }
 
index 8aecd9b15e842e2c95253f3da4dc71e917458bf2..da15c3c2b1fabe2dd2ebf888fc2d7bb737077cdf 100644 (file)
@@ -115,12 +115,12 @@ pub(crate) fn get_blanket_impls(&mut self, item_def_id: DefId) -> Vec<Item> {
                             ),
                             // FIXME(eddyb) compute both `trait_` and `for_` from
                             // the post-inference `trait_ref`, as it's more accurate.
-                            trait_: Some(trait_ref.0.clean(cx)),
+                            trait_: Some(clean_trait_ref_with_bindings(cx, trait_ref.0, &[])),
                             for_: clean_middle_ty(ty.0, cx, None),
                             items: cx.tcx
                                 .associated_items(impl_def_id)
                                 .in_definition_order()
-                                .map(|x| x.clean(cx))
+                                .map(|x| clean_middle_assoc_item(x, cx))
                                 .collect::<Vec<_>>(),
                             polarity: ty::ImplPolarity::Positive,
                             kind: ImplKind::Blanket(Box::new(clean_middle_ty(trait_ref.0.self_ty(), cx, None))),
index 838283e32daf4db61c7721f2ac85f1feb05825ac..e56a715e85780668e0a0a5915390d5c320300a35 100644 (file)
 use rustc_span::symbol::{kw, sym, Symbol};
 
 use crate::clean::{
-    self, clean_fn_decl_from_did_and_sig, clean_middle_field, clean_middle_ty, clean_ty,
+    self, clean_fn_decl_from_did_and_sig, clean_generics, clean_impl_item, clean_middle_assoc_item,
+    clean_middle_field, clean_middle_ty, clean_trait_ref_with_bindings, clean_ty,
     clean_ty_generics, clean_variant_def, clean_visibility, utils, Attributes, AttributesExt,
-    Clean, ImplKind, ItemId, Type, Visibility,
+    ImplKind, ItemId, Type, Visibility,
 };
 use crate::core::DocContext;
 use crate::formats::item_type::ItemType;
@@ -145,6 +146,7 @@ pub(crate) fn try_inline_glob(
     cx: &mut DocContext<'_>,
     res: Res,
     visited: &mut FxHashSet<DefId>,
+    inlined_names: &mut FxHashSet<(ItemType, Symbol)>,
 ) -> Option<Vec<clean::Item>> {
     let did = res.opt_def_id()?;
     if did.is_local() {
@@ -153,8 +155,17 @@ pub(crate) fn try_inline_glob(
 
     match res {
         Res::Def(DefKind::Mod, did) => {
-            let m = build_module(cx, did, visited);
-            Some(m.items)
+            let mut items = build_module_items(cx, did, visited, inlined_names);
+            items.drain_filter(|item| {
+                if let Some(name) = item.name {
+                    // If an item with the same type and name already exists,
+                    // it takes priority over the inlined stuff.
+                    !inlined_names.insert((item.type_(), name))
+                } else {
+                    false
+                }
+            });
+            Some(items)
         }
         // glob imports on things like enums aren't inlined even for local exports, so just bail
         _ => None,
@@ -207,7 +218,7 @@ pub(crate) fn build_external_trait(cx: &mut DocContext<'_>, did: DefId) -> clean
             // which causes methods to have a `pub` prefix, which is invalid since items in traits
             // can not have a visibility prefix. Thus we override the visibility here manually.
             // See https://github.com/rust-lang/rust/issues/81274
-            clean::Item { visibility: Visibility::Inherited, ..item.clean(cx) }
+            clean::Item { visibility: Visibility::Inherited, ..clean_middle_assoc_item(item, cx) }
         })
         .collect();
 
@@ -304,14 +315,14 @@ fn merge_attrs(
         both.extend_from_slice(old_attrs);
         (
             if let Some(new_id) = parent_module {
-                Attributes::from_ast(old_attrs, Some((inner, new_id)))
+                Attributes::from_ast_with_additional(old_attrs, (inner, new_id))
             } else {
-                Attributes::from_ast(&both, None)
+                Attributes::from_ast(&both)
             },
             both.cfg(cx.tcx, &cx.cache.hidden_cfg),
         )
     } else {
-        (old_attrs.clean(cx), old_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg))
+        (Attributes::from_ast(&old_attrs), old_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg))
     }
 }
 
@@ -416,9 +427,9 @@ pub(crate) fn build_impl(
                         true
                     }
                 })
-                .map(|item| item.clean(cx))
+                .map(|item| clean_impl_item(item, cx))
                 .collect::<Vec<_>>(),
-            impl_.generics.clean(cx),
+            clean_generics(impl_.generics, cx),
         ),
         None => (
             tcx.associated_items(did)
@@ -439,10 +450,10 @@ pub(crate) fn build_impl(
                             .unwrap(); // corresponding associated item has to exist
                         !tcx.is_doc_hidden(trait_item.def_id)
                     } else {
-                        item.vis.is_public()
+                        item.visibility(tcx).is_public()
                     }
                 })
-                .map(|item| item.clean(cx))
+                .map(|item| clean_middle_assoc_item(item, cx))
                 .collect::<Vec<_>>(),
             clean::enter_impl_trait(cx, |cx| {
                 clean_ty_generics(cx, tcx.generics_of(did), predicates)
@@ -450,7 +461,7 @@ pub(crate) fn build_impl(
         ),
     };
     let polarity = tcx.impl_polarity(did);
-    let trait_ = associated_trait.map(|t| t.clean(cx));
+    let trait_ = associated_trait.map(|t| clean_trait_ref_with_bindings(cx, t, &[]));
     if trait_.as_ref().map(|t| t.def_id()) == tcx.lang_items().deref_trait() {
         super::build_deref_target_impls(cx, &trait_items, ret);
     }
@@ -517,6 +528,18 @@ fn build_module(
     did: DefId,
     visited: &mut FxHashSet<DefId>,
 ) -> clean::Module {
+    let items = build_module_items(cx, did, visited, &mut FxHashSet::default());
+
+    let span = clean::Span::new(cx.tcx.def_span(did));
+    clean::Module { items, span }
+}
+
+fn build_module_items(
+    cx: &mut DocContext<'_>,
+    did: DefId,
+    visited: &mut FxHashSet<DefId>,
+    inlined_names: &mut FxHashSet<(ItemType, Symbol)>,
+) -> Vec<clean::Item> {
     let mut items = Vec::new();
 
     // If we're re-exporting a re-export it may actually re-export something in
@@ -526,7 +549,13 @@ fn build_module(
         if item.vis.is_public() {
             let res = item.res.expect_non_local();
             if let Some(def_id) = res.mod_def_id() {
-                if did == def_id || !visited.insert(def_id) {
+                // If we're inlining a glob import, it's possible to have
+                // two distinct modules with the same name. We don't want to
+                // inline it, or mark any of its contents as visited.
+                if did == def_id
+                    || inlined_names.contains(&(ItemType::Module, item.ident.name))
+                    || !visited.insert(def_id)
+                {
                     continue;
                 }
             }
@@ -563,8 +592,7 @@ fn build_module(
         }
     }
 
-    let span = clean::Span::new(cx.tcx.def_span(did));
-    clean::Module { items, span }
+    items
 }
 
 pub(crate) fn print_inlined_const(tcx: TyCtxt<'_>, did: DefId) -> String {
index 5071581e5dc43306f1f61317b8f990ef99acf6b2..6e24638548979bfc71895839f23a335b712e636b 100644 (file)
@@ -48,122 +48,107 @@ pub(crate) trait Clean<'tcx, T> {
     fn clean(&self, cx: &mut DocContext<'tcx>) -> T;
 }
 
-impl<'tcx> Clean<'tcx, Item> for DocModule<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> Item {
-        let mut items: Vec<Item> = vec![];
-        items.extend(
-            self.foreigns
-                .iter()
-                .map(|(item, renamed)| clean_maybe_renamed_foreign_item(cx, item, *renamed)),
-        );
-        items.extend(self.mods.iter().map(|x| x.clean(cx)));
-
-        // Split up imports from all other items.
-        //
-        // This covers the case where somebody does an import which should pull in an item,
-        // but there's already an item with the same namespace and same name. Rust gives
-        // priority to the not-imported one, so we should, too.
-        let mut inserted = FxHashSet::default();
-        items.extend(self.items.iter().flat_map(|(item, renamed)| {
-            // First, lower everything other than imports.
-            if matches!(item.kind, hir::ItemKind::Use(..)) {
-                return Vec::new();
-            }
-            let v = clean_maybe_renamed_item(cx, item, *renamed);
-            for item in &v {
-                if let Some(name) = item.name {
-                    inserted.insert((item.type_(), name));
-                }
-            }
-            v
-        }));
-        items.extend(self.items.iter().flat_map(|(item, renamed)| {
-            // Now we actually lower the imports, skipping everything else.
-            if !matches!(item.kind, hir::ItemKind::Use(..)) {
-                return Vec::new();
-            }
-            let mut v = clean_maybe_renamed_item(cx, item, *renamed);
-            v.drain_filter(|item| {
-                if let Some(name) = item.name {
-                    // If an item with the same type and name already exists,
-                    // it takes priority over the inlined stuff.
-                    !inserted.insert((item.type_(), name))
-                } else {
-                    false
-                }
-            });
-            v
-        }));
-
-        // determine if we should display the inner contents or
-        // the outer `mod` item for the source code.
-
-        let span = Span::new({
-            let where_outer = self.where_outer(cx.tcx);
-            let sm = cx.sess().source_map();
-            let outer = sm.lookup_char_pos(where_outer.lo());
-            let inner = sm.lookup_char_pos(self.where_inner.lo());
-            if outer.file.start_pos == inner.file.start_pos {
-                // mod foo { ... }
-                where_outer
-            } else {
-                // mod foo; (and a separate SourceFile for the contents)
-                self.where_inner
+pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext<'tcx>) -> Item {
+    let mut items: Vec<Item> = vec![];
+    let mut inserted = FxHashSet::default();
+    items.extend(doc.foreigns.iter().map(|(item, renamed)| {
+        let item = clean_maybe_renamed_foreign_item(cx, item, *renamed);
+        if let Some(name) = item.name {
+            inserted.insert((item.type_(), name));
+        }
+        item
+    }));
+    items.extend(doc.mods.iter().map(|x| {
+        inserted.insert((ItemType::Module, x.name));
+        clean_doc_module(x, cx)
+    }));
+
+    // Split up imports from all other items.
+    //
+    // This covers the case where somebody does an import which should pull in an item,
+    // but there's already an item with the same namespace and same name. Rust gives
+    // priority to the not-imported one, so we should, too.
+    items.extend(doc.items.iter().flat_map(|(item, renamed)| {
+        // First, lower everything other than imports.
+        if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) {
+            return Vec::new();
+        }
+        let v = clean_maybe_renamed_item(cx, item, *renamed);
+        for item in &v {
+            if let Some(name) = item.name {
+                inserted.insert((item.type_(), name));
             }
-        });
-
-        Item::from_hir_id_and_parts(
-            self.id,
-            Some(self.name),
-            ModuleItem(Module { items, span }),
-            cx,
-        )
-    }
-}
+        }
+        v
+    }));
+    items.extend(doc.items.iter().flat_map(|(item, renamed)| {
+        // Now we actually lower the imports, skipping everything else.
+        if let hir::ItemKind::Use(path, hir::UseKind::Glob) = item.kind {
+            let name = renamed.unwrap_or_else(|| cx.tcx.hir().name(item.hir_id()));
+            clean_use_statement(item, name, path, hir::UseKind::Glob, cx, &mut inserted)
+        } else {
+            // skip everything else
+            Vec::new()
+        }
+    }));
+
+    // determine if we should display the inner contents or
+    // the outer `mod` item for the source code.
+
+    let span = Span::new({
+        let where_outer = doc.where_outer(cx.tcx);
+        let sm = cx.sess().source_map();
+        let outer = sm.lookup_char_pos(where_outer.lo());
+        let inner = sm.lookup_char_pos(doc.where_inner.lo());
+        if outer.file.start_pos == inner.file.start_pos {
+            // mod foo { ... }
+            where_outer
+        } else {
+            // mod foo; (and a separate SourceFile for the contents)
+            doc.where_inner
+        }
+    });
 
-impl<'tcx> Clean<'tcx, Attributes> for [ast::Attribute] {
-    fn clean(&self, _cx: &mut DocContext<'_>) -> Attributes {
-        Attributes::from_ast(self, None)
-    }
+    Item::from_hir_id_and_parts(doc.id, Some(doc.name), ModuleItem(Module { items, span }), cx)
 }
 
-impl<'tcx> Clean<'tcx, Option<GenericBound>> for hir::GenericBound<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> Option<GenericBound> {
-        Some(match *self {
-            hir::GenericBound::Outlives(lt) => GenericBound::Outlives(lt.clean(cx)),
-            hir::GenericBound::LangItemTrait(lang_item, span, _, generic_args) => {
-                let def_id = cx.tcx.require_lang_item(lang_item, Some(span));
-
-                let trait_ref = ty::TraitRef::identity(cx.tcx, def_id).skip_binder();
-
-                let generic_args = generic_args.clean(cx);
-                let GenericArgs::AngleBracketed { bindings, .. } = generic_args
-                else {
-                    bug!("clean: parenthesized `GenericBound::LangItemTrait`");
-                };
+fn clean_generic_bound<'tcx>(
+    bound: &hir::GenericBound<'tcx>,
+    cx: &mut DocContext<'tcx>,
+) -> Option<GenericBound> {
+    Some(match *bound {
+        hir::GenericBound::Outlives(lt) => GenericBound::Outlives(clean_lifetime(lt, cx)),
+        hir::GenericBound::LangItemTrait(lang_item, span, _, generic_args) => {
+            let def_id = cx.tcx.require_lang_item(lang_item, Some(span));
+
+            let trait_ref = ty::TraitRef::identity(cx.tcx, def_id).skip_binder();
+
+            let generic_args = clean_generic_args(generic_args, cx);
+            let GenericArgs::AngleBracketed { bindings, .. } = generic_args
+            else {
+                bug!("clean: parenthesized `GenericBound::LangItemTrait`");
+            };
 
-                let trait_ = clean_trait_ref_with_bindings(cx, trait_ref, &bindings);
-                GenericBound::TraitBound(
-                    PolyTrait { trait_, generic_params: vec![] },
-                    hir::TraitBoundModifier::None,
-                )
+            let trait_ = clean_trait_ref_with_bindings(cx, trait_ref, &bindings);
+            GenericBound::TraitBound(
+                PolyTrait { trait_, generic_params: vec![] },
+                hir::TraitBoundModifier::None,
+            )
+        }
+        hir::GenericBound::Trait(ref t, modifier) => {
+            // `T: ~const Destruct` is hidden because `T: Destruct` is a no-op.
+            if modifier == hir::TraitBoundModifier::MaybeConst
+                && cx.tcx.lang_items().destruct_trait() == Some(t.trait_ref.trait_def_id().unwrap())
+            {
+                return None;
             }
-            hir::GenericBound::Trait(ref t, modifier) => {
-                // `T: ~const Destruct` is hidden because `T: Destruct` is a no-op.
-                if modifier == hir::TraitBoundModifier::MaybeConst
-                    && cx.tcx.lang_items().destruct_trait()
-                        == Some(t.trait_ref.trait_def_id().unwrap())
-                {
-                    return None;
-                }
 
-                GenericBound::TraitBound(t.clean(cx), modifier)
-            }
-        })
-    }
+            GenericBound::TraitBound(clean_poly_trait_ref(t, cx), modifier)
+        }
+    })
 }
 
-fn clean_trait_ref_with_bindings<'tcx>(
+pub(crate) fn clean_trait_ref_with_bindings<'tcx>(
     cx: &mut DocContext<'tcx>,
     trait_ref: ty::TraitRef<'tcx>,
     bindings: &[TypeBinding],
@@ -180,12 +165,6 @@ fn clean_trait_ref_with_bindings<'tcx>(
     path
 }
 
-impl<'tcx> Clean<'tcx, Path> for ty::TraitRef<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> Path {
-        clean_trait_ref_with_bindings(cx, *self, &[])
-    }
-}
-
 fn clean_poly_trait_ref_with_bindings<'tcx>(
     cx: &mut DocContext<'tcx>,
     poly_trait_ref: ty::PolyTraitRef<'tcx>,
@@ -214,27 +193,19 @@ fn clean_poly_trait_ref_with_bindings<'tcx>(
     )
 }
 
-impl<'tcx> Clean<'tcx, GenericBound> for ty::PolyTraitRef<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> GenericBound {
-        clean_poly_trait_ref_with_bindings(cx, *self, &[])
-    }
-}
-
-impl<'tcx> Clean<'tcx, Lifetime> for hir::Lifetime {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> Lifetime {
-        let def = cx.tcx.named_region(self.hir_id);
-        if let Some(
-            rl::Region::EarlyBound(_, node_id)
-            | rl::Region::LateBound(_, _, node_id)
-            | rl::Region::Free(_, node_id),
-        ) = def
-        {
-            if let Some(lt) = cx.substs.get(&node_id).and_then(|p| p.as_lt()).cloned() {
-                return lt;
-            }
+fn clean_lifetime<'tcx>(lifetime: hir::Lifetime, cx: &mut DocContext<'tcx>) -> Lifetime {
+    let def = cx.tcx.named_region(lifetime.hir_id);
+    if let Some(
+        rl::Region::EarlyBound(_, node_id)
+        | rl::Region::LateBound(_, _, node_id)
+        | rl::Region::Free(_, node_id),
+    ) = def
+    {
+        if let Some(lt) = cx.substs.get(&node_id).and_then(|p| p.as_lt()).cloned() {
+            return lt;
         }
-        Lifetime(self.name.ident().name)
     }
+    Lifetime(lifetime.name.ident().name)
 }
 
 pub(crate) fn clean_const<'tcx>(constant: &hir::ConstArg, cx: &mut DocContext<'tcx>) -> Constant {
@@ -256,93 +227,93 @@ pub(crate) fn clean_middle_const<'tcx>(
     }
 }
 
-impl<'tcx> Clean<'tcx, Option<Lifetime>> for ty::Region<'tcx> {
-    fn clean(&self, _cx: &mut DocContext<'_>) -> Option<Lifetime> {
-        match **self {
-            ty::ReStatic => Some(Lifetime::statik()),
-            ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) => {
-                if name != kw::UnderscoreLifetime { Some(Lifetime(name)) } else { None }
-            }
-            ty::ReEarlyBound(ref data) => {
-                if data.name != kw::UnderscoreLifetime {
-                    Some(Lifetime(data.name))
-                } else {
-                    None
-                }
-            }
-            ty::ReLateBound(..)
-            | ty::ReFree(..)
-            | ty::ReVar(..)
-            | ty::RePlaceholder(..)
-            | ty::ReEmpty(_)
-            | ty::ReErased => {
-                debug!("cannot clean region {:?}", self);
+pub(crate) fn clean_middle_region<'tcx>(region: ty::Region<'tcx>) -> Option<Lifetime> {
+    match *region {
+        ty::ReStatic => Some(Lifetime::statik()),
+        ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) => {
+            if name != kw::UnderscoreLifetime { Some(Lifetime(name)) } else { None }
+        }
+        ty::ReEarlyBound(ref data) => {
+            if data.name != kw::UnderscoreLifetime {
+                Some(Lifetime(data.name))
+            } else {
                 None
             }
         }
+        ty::ReLateBound(..)
+        | ty::ReFree(..)
+        | ty::ReVar(..)
+        | ty::RePlaceholder(..)
+        | ty::ReEmpty(_)
+        | ty::ReErased => {
+            debug!("cannot clean region {:?}", region);
+            None
+        }
     }
 }
 
-impl<'tcx> Clean<'tcx, Option<WherePredicate>> for hir::WherePredicate<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> Option<WherePredicate> {
-        if !self.in_where_clause() {
-            return None;
-        }
-        Some(match *self {
-            hir::WherePredicate::BoundPredicate(ref wbp) => {
-                let bound_params = wbp
-                    .bound_generic_params
-                    .iter()
-                    .map(|param| {
-                        // Higher-ranked params must be lifetimes.
-                        // Higher-ranked lifetimes can't have bounds.
-                        assert_matches!(
-                            param,
-                            hir::GenericParam { kind: hir::GenericParamKind::Lifetime { .. }, .. }
-                        );
-                        Lifetime(param.name.ident().name)
-                    })
-                    .collect();
-                WherePredicate::BoundPredicate {
-                    ty: clean_ty(wbp.bounded_ty, cx),
-                    bounds: wbp.bounds.iter().filter_map(|x| x.clean(cx)).collect(),
-                    bound_params,
-                }
+fn clean_where_predicate<'tcx>(
+    predicate: &hir::WherePredicate<'tcx>,
+    cx: &mut DocContext<'tcx>,
+) -> Option<WherePredicate> {
+    if !predicate.in_where_clause() {
+        return None;
+    }
+    Some(match *predicate {
+        hir::WherePredicate::BoundPredicate(ref wbp) => {
+            let bound_params = wbp
+                .bound_generic_params
+                .iter()
+                .map(|param| {
+                    // Higher-ranked params must be lifetimes.
+                    // Higher-ranked lifetimes can't have bounds.
+                    assert_matches!(
+                        param,
+                        hir::GenericParam { kind: hir::GenericParamKind::Lifetime { .. }, .. }
+                    );
+                    Lifetime(param.name.ident().name)
+                })
+                .collect();
+            WherePredicate::BoundPredicate {
+                ty: clean_ty(wbp.bounded_ty, cx),
+                bounds: wbp.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
+                bound_params,
             }
+        }
 
-            hir::WherePredicate::RegionPredicate(ref wrp) => WherePredicate::RegionPredicate {
-                lifetime: wrp.lifetime.clean(cx),
-                bounds: wrp.bounds.iter().filter_map(|x| x.clean(cx)).collect(),
-            },
+        hir::WherePredicate::RegionPredicate(ref wrp) => WherePredicate::RegionPredicate {
+            lifetime: clean_lifetime(wrp.lifetime, cx),
+            bounds: wrp.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
+        },
 
-            hir::WherePredicate::EqPredicate(ref wrp) => WherePredicate::EqPredicate {
-                lhs: clean_ty(wrp.lhs_ty, cx),
-                rhs: clean_ty(wrp.rhs_ty, cx).into(),
-            },
-        })
-    }
+        hir::WherePredicate::EqPredicate(ref wrp) => WherePredicate::EqPredicate {
+            lhs: clean_ty(wrp.lhs_ty, cx),
+            rhs: clean_ty(wrp.rhs_ty, cx).into(),
+        },
+    })
 }
 
-impl<'tcx> Clean<'tcx, Option<WherePredicate>> for ty::Predicate<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> Option<WherePredicate> {
-        let bound_predicate = self.kind();
-        match bound_predicate.skip_binder() {
-            ty::PredicateKind::Trait(pred) => {
-                clean_poly_trait_predicate(bound_predicate.rebind(pred), cx)
-            }
-            ty::PredicateKind::RegionOutlives(pred) => clean_region_outlives_predicate(pred, cx),
-            ty::PredicateKind::TypeOutlives(pred) => clean_type_outlives_predicate(pred, cx),
-            ty::PredicateKind::Projection(pred) => Some(clean_projection_predicate(pred, cx)),
-            ty::PredicateKind::ConstEvaluatable(..) => None,
-            ty::PredicateKind::WellFormed(..) => None,
-
-            ty::PredicateKind::Subtype(..)
-            | ty::PredicateKind::Coerce(..)
-            | ty::PredicateKind::ObjectSafe(..)
-            | ty::PredicateKind::ClosureKind(..)
-            | ty::PredicateKind::ConstEquate(..)
-            | ty::PredicateKind::TypeWellFormedFromEnv(..) => panic!("not user writable"),
+pub(crate) fn clean_predicate<'tcx>(
+    predicate: ty::Predicate<'tcx>,
+    cx: &mut DocContext<'tcx>,
+) -> Option<WherePredicate> {
+    let bound_predicate = predicate.kind();
+    match bound_predicate.skip_binder() {
+        ty::PredicateKind::Trait(pred) => {
+            clean_poly_trait_predicate(bound_predicate.rebind(pred), cx)
         }
+        ty::PredicateKind::RegionOutlives(pred) => clean_region_outlives_predicate(pred),
+        ty::PredicateKind::TypeOutlives(pred) => clean_type_outlives_predicate(pred, cx),
+        ty::PredicateKind::Projection(pred) => Some(clean_projection_predicate(pred, cx)),
+        ty::PredicateKind::ConstEvaluatable(..) => None,
+        ty::PredicateKind::WellFormed(..) => None,
+
+        ty::PredicateKind::Subtype(..)
+        | ty::PredicateKind::Coerce(..)
+        | ty::PredicateKind::ObjectSafe(..)
+        | ty::PredicateKind::ClosureKind(..)
+        | ty::PredicateKind::ConstEquate(..)
+        | ty::PredicateKind::TypeWellFormedFromEnv(..) => panic!("not user writable"),
     }
 }
 
@@ -360,14 +331,13 @@ fn clean_poly_trait_predicate<'tcx>(
     let poly_trait_ref = pred.map_bound(|pred| pred.trait_ref);
     Some(WherePredicate::BoundPredicate {
         ty: clean_middle_ty(poly_trait_ref.skip_binder().self_ty(), cx, None),
-        bounds: vec![poly_trait_ref.clean(cx)],
+        bounds: vec![clean_poly_trait_ref_with_bindings(cx, poly_trait_ref, &[])],
         bound_params: Vec::new(),
     })
 }
 
 fn clean_region_outlives_predicate<'tcx>(
     pred: ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>,
-    cx: &mut DocContext<'tcx>,
 ) -> Option<WherePredicate> {
     let ty::OutlivesPredicate(a, b) = pred;
 
@@ -376,8 +346,10 @@ fn clean_region_outlives_predicate<'tcx>(
     }
 
     Some(WherePredicate::RegionPredicate {
-        lifetime: a.clean(cx).expect("failed to clean lifetime"),
-        bounds: vec![GenericBound::Outlives(b.clean(cx).expect("failed to clean bounds"))],
+        lifetime: clean_middle_region(a).expect("failed to clean lifetime"),
+        bounds: vec![GenericBound::Outlives(
+            clean_middle_region(b).expect("failed to clean bounds"),
+        )],
     })
 }
 
@@ -393,7 +365,9 @@ fn clean_type_outlives_predicate<'tcx>(
 
     Some(WherePredicate::BoundPredicate {
         ty: clean_middle_ty(ty, cx, None),
-        bounds: vec![GenericBound::Outlives(lt.clean(cx).expect("failed to clean lifetimes"))],
+        bounds: vec![GenericBound::Outlives(
+            clean_middle_region(lt).expect("failed to clean lifetimes"),
+        )],
         bound_params: Vec::new(),
     })
 }
@@ -432,7 +406,7 @@ fn clean_projection<'tcx>(
     def_id: Option<DefId>,
 ) -> Type {
     let lifted = ty.lift_to_tcx(cx.tcx).unwrap();
-    let trait_ = lifted.trait_ref(cx.tcx).clean(cx);
+    let trait_ = clean_trait_ref_with_bindings(cx, lifted.trait_ref(cx.tcx), &[]);
     let self_type = clean_middle_ty(ty.self_ty(), cx, None);
     let self_def_id = if let Some(def_id) = def_id {
         cx.tcx.opt_parent(def_id).or(Some(def_id))
@@ -524,7 +498,7 @@ fn clean_generic_param<'tcx>(
                     .filter(|bp| !bp.in_where_clause)
                     .flat_map(|bp| bp.bounds)
                     .map(|bound| match bound {
-                        hir::GenericBound::Outlives(lt) => lt.clean(cx),
+                        hir::GenericBound::Outlives(lt) => clean_lifetime(*lt, cx),
                         _ => panic!(),
                     })
                     .collect()
@@ -539,7 +513,7 @@ fn clean_generic_param<'tcx>(
                     .bounds_for_param(did)
                     .filter(|bp| bp.origin != PredicateOrigin::WhereClause)
                     .flat_map(|bp| bp.bounds)
-                    .filter_map(|x| x.clean(cx))
+                    .filter_map(|x| clean_generic_bound(x, cx))
                     .collect()
             } else {
                 Vec::new()
@@ -587,65 +561,68 @@ fn is_elided_lifetime(param: &hir::GenericParam<'_>) -> bool {
     matches!(param.kind, hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Elided })
 }
 
-impl<'tcx> Clean<'tcx, Generics> for hir::Generics<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> Generics {
-        let impl_trait_params = self
-            .params
-            .iter()
-            .filter(|param| is_impl_trait(param))
-            .map(|param| {
-                let param = clean_generic_param(cx, Some(self), param);
-                match param.kind {
-                    GenericParamDefKind::Lifetime { .. } => unreachable!(),
-                    GenericParamDefKind::Type { did, ref bounds, .. } => {
-                        cx.impl_trait_bounds.insert(did.into(), bounds.clone());
-                    }
-                    GenericParamDefKind::Const { .. } => unreachable!(),
+pub(crate) fn clean_generics<'tcx>(
+    gens: &hir::Generics<'tcx>,
+    cx: &mut DocContext<'tcx>,
+) -> Generics {
+    let impl_trait_params = gens
+        .params
+        .iter()
+        .filter(|param| is_impl_trait(param))
+        .map(|param| {
+            let param = clean_generic_param(cx, Some(gens), param);
+            match param.kind {
+                GenericParamDefKind::Lifetime { .. } => unreachable!(),
+                GenericParamDefKind::Type { did, ref bounds, .. } => {
+                    cx.impl_trait_bounds.insert(did.into(), bounds.clone());
                 }
-                param
-            })
-            .collect::<Vec<_>>();
+                GenericParamDefKind::Const { .. } => unreachable!(),
+            }
+            param
+        })
+        .collect::<Vec<_>>();
 
-        let mut params = Vec::with_capacity(self.params.len());
-        for p in self.params.iter().filter(|p| !is_impl_trait(p) && !is_elided_lifetime(p)) {
-            let p = clean_generic_param(cx, Some(self), p);
-            params.push(p);
-        }
-        params.extend(impl_trait_params);
+    let mut params = Vec::with_capacity(gens.params.len());
+    for p in gens.params.iter().filter(|p| !is_impl_trait(p) && !is_elided_lifetime(p)) {
+        let p = clean_generic_param(cx, Some(gens), p);
+        params.push(p);
+    }
+    params.extend(impl_trait_params);
 
-        let mut generics = Generics {
-            params,
-            where_predicates: self.predicates.iter().filter_map(|x| x.clean(cx)).collect(),
-        };
+    let mut generics = Generics {
+        params,
+        where_predicates: gens
+            .predicates
+            .iter()
+            .filter_map(|x| clean_where_predicate(x, cx))
+            .collect(),
+    };
 
-        // Some duplicates are generated for ?Sized bounds between type params and where
-        // predicates. The point in here is to move the bounds definitions from type params
-        // to where predicates when such cases occur.
-        for where_pred in &mut generics.where_predicates {
-            match *where_pred {
-                WherePredicate::BoundPredicate {
-                    ty: Generic(ref name), ref mut bounds, ..
-                } => {
-                    if bounds.is_empty() {
-                        for param in &mut generics.params {
-                            match param.kind {
-                                GenericParamDefKind::Lifetime { .. } => {}
-                                GenericParamDefKind::Type { bounds: ref mut ty_bounds, .. } => {
-                                    if &param.name == name {
-                                        mem::swap(bounds, ty_bounds);
-                                        break;
-                                    }
+    // Some duplicates are generated for ?Sized bounds between type params and where
+    // predicates. The point in here is to move the bounds definitions from type params
+    // to where predicates when such cases occur.
+    for where_pred in &mut generics.where_predicates {
+        match *where_pred {
+            WherePredicate::BoundPredicate { ty: Generic(ref name), ref mut bounds, .. } => {
+                if bounds.is_empty() {
+                    for param in &mut generics.params {
+                        match param.kind {
+                            GenericParamDefKind::Lifetime { .. } => {}
+                            GenericParamDefKind::Type { bounds: ref mut ty_bounds, .. } => {
+                                if &param.name == name {
+                                    mem::swap(bounds, ty_bounds);
+                                    break;
                                 }
-                                GenericParamDefKind::Const { .. } => {}
                             }
+                            GenericParamDefKind::Const { .. } => {}
                         }
                     }
                 }
-                _ => continue,
             }
+            _ => continue,
         }
-        generics
     }
+    generics
 }
 
 fn clean_ty_generics<'tcx>(
@@ -716,7 +693,7 @@ fn clean_ty_generics<'tcx>(
 
             if let Some(param_idx) = param_idx {
                 if let Some(b) = impl_trait.get_mut(&param_idx.into()) {
-                    let p: WherePredicate = p.clean(cx)?;
+                    let p: WherePredicate = clean_predicate(*p, cx)?;
 
                     b.extend(
                         p.get_bounds()
@@ -773,7 +750,7 @@ fn clean_ty_generics<'tcx>(
     // Now that `cx.impl_trait_bounds` is populated, we can process
     // remaining predicates which could contain `impl Trait`.
     let mut where_predicates =
-        where_predicates.into_iter().flat_map(|p| p.clean(cx)).collect::<Vec<_>>();
+        where_predicates.into_iter().flat_map(|p| clean_predicate(*p, cx)).collect::<Vec<_>>();
 
     // Type parameters have a Sized bound by default unless removed with
     // ?Sized. Scan through the predicates and mark any type parameter with
@@ -911,7 +888,7 @@ fn clean_function<'tcx>(
 ) -> Box<Function> {
     let (generics, decl) = enter_impl_trait(cx, |cx| {
         // NOTE: generics must be cleaned before args
-        let generics = generics.clean(cx);
+        let generics = clean_generics(generics, cx);
         let args = clean_args_from_types_and_body_id(cx, sig.decl.inputs, body_id);
         let decl = clean_fn_decl_with_args(cx, sig.decl, args);
         (generics, decl)
@@ -964,7 +941,11 @@ fn clean_fn_decl_with_args<'tcx>(
     decl: &hir::FnDecl<'tcx>,
     args: Arguments,
 ) -> FnDecl {
-    FnDecl { inputs: args, output: decl.output.clean(cx), c_variadic: decl.c_variadic }
+    let output = match decl.output {
+        hir::FnRetTy::Return(typ) => Return(clean_ty(typ, cx)),
+        hir::FnRetTy::DefaultReturn(..) => DefaultReturn,
+    };
+    FnDecl { inputs: args, output, c_variadic: decl.c_variadic }
 }
 
 fn clean_fn_decl_from_did_and_sig<'tcx>(
@@ -999,331 +980,313 @@ fn clean_fn_decl_from_did_and_sig<'tcx>(
     }
 }
 
-impl<'tcx> Clean<'tcx, FnRetTy> for hir::FnRetTy<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> FnRetTy {
-        match *self {
-            Self::Return(typ) => Return(clean_ty(typ, cx)),
-            Self::DefaultReturn(..) => DefaultReturn,
-        }
-    }
-}
-
-impl<'tcx> Clean<'tcx, bool> for hir::IsAuto {
-    fn clean(&self, _: &mut DocContext<'tcx>) -> bool {
-        match *self {
-            hir::IsAuto::Yes => true,
-            hir::IsAuto::No => false,
-        }
-    }
-}
-
-impl<'tcx> Clean<'tcx, Path> for hir::TraitRef<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> Path {
-        let path = clean_path(self.path, cx);
-        register_res(cx, path.res);
-        path
-    }
+fn clean_trait_ref<'tcx>(trait_ref: &hir::TraitRef<'tcx>, cx: &mut DocContext<'tcx>) -> Path {
+    let path = clean_path(trait_ref.path, cx);
+    register_res(cx, path.res);
+    path
 }
 
-impl<'tcx> Clean<'tcx, PolyTrait> for hir::PolyTraitRef<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> PolyTrait {
-        PolyTrait {
-            trait_: self.trait_ref.clean(cx),
-            generic_params: self
-                .bound_generic_params
-                .iter()
-                .filter(|p| !is_elided_lifetime(p))
-                .map(|x| clean_generic_param(cx, None, x))
-                .collect(),
-        }
+fn clean_poly_trait_ref<'tcx>(
+    poly_trait_ref: &hir::PolyTraitRef<'tcx>,
+    cx: &mut DocContext<'tcx>,
+) -> PolyTrait {
+    PolyTrait {
+        trait_: clean_trait_ref(&poly_trait_ref.trait_ref, cx),
+        generic_params: poly_trait_ref
+            .bound_generic_params
+            .iter()
+            .filter(|p| !is_elided_lifetime(p))
+            .map(|x| clean_generic_param(cx, None, x))
+            .collect(),
     }
 }
 
-impl<'tcx> Clean<'tcx, Item> for hir::TraitItem<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> Item {
-        let local_did = self.def_id.to_def_id();
-        cx.with_param_env(local_did, |cx| {
-            let inner = match self.kind {
-                hir::TraitItemKind::Const(ty, Some(default)) => AssocConstItem(
-                    clean_ty(ty, cx),
-                    ConstantKind::Local { def_id: local_did, body: default },
-                ),
-                hir::TraitItemKind::Const(ty, None) => TyAssocConstItem(clean_ty(ty, cx)),
-                hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
-                    let m = clean_function(cx, sig, self.generics, body);
-                    MethodItem(m, None)
-                }
-                hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(names)) => {
-                    let (generics, decl) = enter_impl_trait(cx, |cx| {
-                        // NOTE: generics must be cleaned before args
-                        let generics = self.generics.clean(cx);
-                        let args = clean_args_from_types_and_names(cx, sig.decl.inputs, names);
-                        let decl = clean_fn_decl_with_args(cx, sig.decl, args);
-                        (generics, decl)
-                    });
-                    TyMethodItem(Box::new(Function { decl, generics }))
-                }
-                hir::TraitItemKind::Type(bounds, Some(default)) => {
-                    let generics = enter_impl_trait(cx, |cx| self.generics.clean(cx));
-                    let bounds = bounds.iter().filter_map(|x| x.clean(cx)).collect();
-                    let item_type = clean_middle_ty(hir_ty_to_ty(cx.tcx, default), cx, None);
-                    AssocTypeItem(
-                        Box::new(Typedef {
-                            type_: clean_ty(default, cx),
-                            generics,
-                            item_type: Some(item_type),
-                        }),
-                        bounds,
-                    )
-                }
-                hir::TraitItemKind::Type(bounds, None) => {
-                    let generics = enter_impl_trait(cx, |cx| self.generics.clean(cx));
-                    let bounds = bounds.iter().filter_map(|x| x.clean(cx)).collect();
-                    TyAssocTypeItem(Box::new(generics), bounds)
-                }
-            };
-            let what_rustc_thinks =
-                Item::from_def_id_and_parts(local_did, Some(self.ident.name), inner, cx);
-            // Trait items always inherit the trait's visibility -- we don't want to show `pub`.
-            Item { visibility: Inherited, ..what_rustc_thinks }
-        })
-    }
+fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext<'tcx>) -> Item {
+    let local_did = trait_item.def_id.to_def_id();
+    cx.with_param_env(local_did, |cx| {
+        let inner = match trait_item.kind {
+            hir::TraitItemKind::Const(ty, Some(default)) => AssocConstItem(
+                clean_ty(ty, cx),
+                ConstantKind::Local { def_id: local_did, body: default },
+            ),
+            hir::TraitItemKind::Const(ty, None) => TyAssocConstItem(clean_ty(ty, cx)),
+            hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
+                let m = clean_function(cx, sig, trait_item.generics, body);
+                MethodItem(m, None)
+            }
+            hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(names)) => {
+                let (generics, decl) = enter_impl_trait(cx, |cx| {
+                    // NOTE: generics must be cleaned before args
+                    let generics = clean_generics(trait_item.generics, cx);
+                    let args = clean_args_from_types_and_names(cx, sig.decl.inputs, names);
+                    let decl = clean_fn_decl_with_args(cx, sig.decl, args);
+                    (generics, decl)
+                });
+                TyMethodItem(Box::new(Function { decl, generics }))
+            }
+            hir::TraitItemKind::Type(bounds, Some(default)) => {
+                let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx));
+                let bounds = bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect();
+                let item_type = clean_middle_ty(hir_ty_to_ty(cx.tcx, default), cx, None);
+                AssocTypeItem(
+                    Box::new(Typedef {
+                        type_: clean_ty(default, cx),
+                        generics,
+                        item_type: Some(item_type),
+                    }),
+                    bounds,
+                )
+            }
+            hir::TraitItemKind::Type(bounds, None) => {
+                let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx));
+                let bounds = bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect();
+                TyAssocTypeItem(Box::new(generics), bounds)
+            }
+        };
+        let what_rustc_thinks =
+            Item::from_def_id_and_parts(local_did, Some(trait_item.ident.name), inner, cx);
+        // Trait items always inherit the trait's visibility -- we don't want to show `pub`.
+        Item { visibility: Inherited, ..what_rustc_thinks }
+    })
 }
 
-impl<'tcx> Clean<'tcx, Item> for hir::ImplItem<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> Item {
-        let local_did = self.def_id.to_def_id();
-        cx.with_param_env(local_did, |cx| {
-            let inner = match self.kind {
-                hir::ImplItemKind::Const(ty, expr) => {
-                    let default = ConstantKind::Local { def_id: local_did, body: expr };
-                    AssocConstItem(clean_ty(ty, cx), default)
-                }
-                hir::ImplItemKind::Fn(ref sig, body) => {
-                    let m = clean_function(cx, sig, self.generics, body);
-                    let defaultness = cx.tcx.associated_item(self.def_id).defaultness;
-                    MethodItem(m, Some(defaultness))
-                }
-                hir::ImplItemKind::TyAlias(hir_ty) => {
-                    let type_ = clean_ty(hir_ty, cx);
-                    let generics = self.generics.clean(cx);
-                    let item_type = clean_middle_ty(hir_ty_to_ty(cx.tcx, hir_ty), cx, None);
-                    AssocTypeItem(
-                        Box::new(Typedef { type_, generics, item_type: Some(item_type) }),
-                        Vec::new(),
-                    )
-                }
-            };
+pub(crate) fn clean_impl_item<'tcx>(
+    impl_: &hir::ImplItem<'tcx>,
+    cx: &mut DocContext<'tcx>,
+) -> Item {
+    let local_did = impl_.def_id.to_def_id();
+    cx.with_param_env(local_did, |cx| {
+        let inner = match impl_.kind {
+            hir::ImplItemKind::Const(ty, expr) => {
+                let default = ConstantKind::Local { def_id: local_did, body: expr };
+                AssocConstItem(clean_ty(ty, cx), default)
+            }
+            hir::ImplItemKind::Fn(ref sig, body) => {
+                let m = clean_function(cx, sig, impl_.generics, body);
+                let defaultness = cx.tcx.impl_defaultness(impl_.def_id);
+                MethodItem(m, Some(defaultness))
+            }
+            hir::ImplItemKind::TyAlias(hir_ty) => {
+                let type_ = clean_ty(hir_ty, cx);
+                let generics = clean_generics(impl_.generics, cx);
+                let item_type = clean_middle_ty(hir_ty_to_ty(cx.tcx, hir_ty), cx, None);
+                AssocTypeItem(
+                    Box::new(Typedef { type_, generics, item_type: Some(item_type) }),
+                    Vec::new(),
+                )
+            }
+        };
 
-            let mut what_rustc_thinks =
-                Item::from_def_id_and_parts(local_did, Some(self.ident.name), inner, cx);
+        let mut what_rustc_thinks =
+            Item::from_def_id_and_parts(local_did, Some(impl_.ident.name), inner, cx);
 
-            let impl_ref = cx.tcx.impl_trait_ref(cx.tcx.local_parent(self.def_id));
+        let impl_ref = cx.tcx.impl_trait_ref(cx.tcx.local_parent(impl_.def_id));
 
-            // Trait impl items always inherit the impl's visibility --
-            // we don't want to show `pub`.
-            if impl_ref.is_some() {
-                what_rustc_thinks.visibility = Inherited;
-            }
+        // Trait impl items always inherit the impl's visibility --
+        // we don't want to show `pub`.
+        if impl_ref.is_some() {
+            what_rustc_thinks.visibility = Inherited;
+        }
 
-            what_rustc_thinks
-        })
-    }
+        what_rustc_thinks
+    })
 }
 
-impl<'tcx> Clean<'tcx, Item> for ty::AssocItem {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> Item {
-        let tcx = cx.tcx;
-        let kind = match self.kind {
-            ty::AssocKind::Const => {
-                let ty = clean_middle_ty(tcx.type_of(self.def_id), cx, Some(self.def_id));
-
-                let provided = match self.container {
-                    ty::ImplContainer(_) => true,
-                    ty::TraitContainer(_) => self.defaultness.has_value(),
-                };
-                if provided {
-                    AssocConstItem(ty, ConstantKind::Extern { def_id: self.def_id })
-                } else {
-                    TyAssocConstItem(ty)
-                }
+pub(crate) fn clean_middle_assoc_item<'tcx>(
+    assoc_item: &ty::AssocItem,
+    cx: &mut DocContext<'tcx>,
+) -> Item {
+    let tcx = cx.tcx;
+    let kind = match assoc_item.kind {
+        ty::AssocKind::Const => {
+            let ty = clean_middle_ty(tcx.type_of(assoc_item.def_id), cx, Some(assoc_item.def_id));
+
+            let provided = match assoc_item.container {
+                ty::ImplContainer => true,
+                ty::TraitContainer => tcx.impl_defaultness(assoc_item.def_id).has_value(),
+            };
+            if provided {
+                AssocConstItem(ty, ConstantKind::Extern { def_id: assoc_item.def_id })
+            } else {
+                TyAssocConstItem(ty)
             }
-            ty::AssocKind::Fn => {
-                let generics = clean_ty_generics(
-                    cx,
-                    tcx.generics_of(self.def_id),
-                    tcx.explicit_predicates_of(self.def_id),
-                );
-                let sig = tcx.fn_sig(self.def_id);
-                let mut decl = clean_fn_decl_from_did_and_sig(cx, Some(self.def_id), sig);
-
-                if self.fn_has_self_parameter {
-                    let self_ty = match self.container {
-                        ty::ImplContainer(def_id) => tcx.type_of(def_id),
-                        ty::TraitContainer(_) => tcx.types.self_param,
-                    };
-                    let self_arg_ty = sig.input(0).skip_binder();
-                    if self_arg_ty == self_ty {
-                        decl.inputs.values[0].type_ = Generic(kw::SelfUpper);
-                    } else if let ty::Ref(_, ty, _) = *self_arg_ty.kind() {
-                        if ty == self_ty {
-                            match decl.inputs.values[0].type_ {
-                                BorrowedRef { ref mut type_, .. } => {
-                                    **type_ = Generic(kw::SelfUpper)
-                                }
-                                _ => unreachable!(),
-                            }
+        }
+        ty::AssocKind::Fn => {
+            let generics = clean_ty_generics(
+                cx,
+                tcx.generics_of(assoc_item.def_id),
+                tcx.explicit_predicates_of(assoc_item.def_id),
+            );
+            let sig = tcx.fn_sig(assoc_item.def_id);
+            let mut decl = clean_fn_decl_from_did_and_sig(cx, Some(assoc_item.def_id), sig);
+
+            if assoc_item.fn_has_self_parameter {
+                let self_ty = match assoc_item.container {
+                    ty::ImplContainer => tcx.type_of(assoc_item.container_id(tcx)),
+                    ty::TraitContainer => tcx.types.self_param,
+                };
+                let self_arg_ty = sig.input(0).skip_binder();
+                if self_arg_ty == self_ty {
+                    decl.inputs.values[0].type_ = Generic(kw::SelfUpper);
+                } else if let ty::Ref(_, ty, _) = *self_arg_ty.kind() {
+                    if ty == self_ty {
+                        match decl.inputs.values[0].type_ {
+                            BorrowedRef { ref mut type_, .. } => **type_ = Generic(kw::SelfUpper),
+                            _ => unreachable!(),
                         }
                     }
                 }
+            }
 
-                let provided = match self.container {
-                    ty::ImplContainer(_) => true,
-                    ty::TraitContainer(_) => self.defaultness.has_value(),
+            let provided = match assoc_item.container {
+                ty::ImplContainer => true,
+                ty::TraitContainer => assoc_item.defaultness(tcx).has_value(),
+            };
+            if provided {
+                let defaultness = match assoc_item.container {
+                    ty::ImplContainer => Some(assoc_item.defaultness(tcx)),
+                    ty::TraitContainer => None,
                 };
-                if provided {
-                    let defaultness = match self.container {
-                        ty::ImplContainer(_) => Some(self.defaultness),
-                        ty::TraitContainer(_) => None,
-                    };
-                    MethodItem(Box::new(Function { generics, decl }), defaultness)
-                } else {
-                    TyMethodItem(Box::new(Function { generics, decl }))
-                }
+                MethodItem(Box::new(Function { generics, decl }), defaultness)
+            } else {
+                TyMethodItem(Box::new(Function { generics, decl }))
             }
-            ty::AssocKind::Type => {
-                let my_name = self.name;
-
-                fn param_eq_arg(param: &GenericParamDef, arg: &GenericArg) -> bool {
-                    match (&param.kind, arg) {
-                        (GenericParamDefKind::Type { .. }, GenericArg::Type(Type::Generic(ty)))
-                            if *ty == param.name =>
-                        {
-                            true
-                        }
-                        (
-                            GenericParamDefKind::Lifetime { .. },
-                            GenericArg::Lifetime(Lifetime(lt)),
-                        ) if *lt == param.name => true,
-                        (GenericParamDefKind::Const { .. }, GenericArg::Const(c)) => {
-                            match &c.kind {
-                                ConstantKind::TyConst { expr } => expr == param.name.as_str(),
-                                _ => false,
-                            }
-                        }
-                        _ => false,
+        }
+        ty::AssocKind::Type => {
+            let my_name = assoc_item.name;
+
+            fn param_eq_arg(param: &GenericParamDef, arg: &GenericArg) -> bool {
+                match (&param.kind, arg) {
+                    (GenericParamDefKind::Type { .. }, GenericArg::Type(Type::Generic(ty)))
+                        if *ty == param.name =>
+                    {
+                        true
+                    }
+                    (GenericParamDefKind::Lifetime { .. }, GenericArg::Lifetime(Lifetime(lt)))
+                        if *lt == param.name =>
+                    {
+                        true
                     }
+                    (GenericParamDefKind::Const { .. }, GenericArg::Const(c)) => match &c.kind {
+                        ConstantKind::TyConst { expr } => expr == param.name.as_str(),
+                        _ => false,
+                    },
+                    _ => false,
                 }
+            }
 
-                if let ty::TraitContainer(_) = self.container {
-                    let bounds = tcx.explicit_item_bounds(self.def_id);
-                    let predicates = ty::GenericPredicates { parent: None, predicates: bounds };
-                    let mut generics =
-                        clean_ty_generics(cx, tcx.generics_of(self.def_id), predicates);
-                    // Filter out the bounds that are (likely?) directly attached to the associated type,
-                    // as opposed to being located in the where clause.
-                    let mut bounds = generics
-                        .where_predicates
-                        .drain_filter(|pred| match *pred {
-                            WherePredicate::BoundPredicate {
-                                ty: QPath { ref assoc, ref self_type, ref trait_, .. },
-                                ..
-                            } => {
-                                if assoc.name != my_name {
-                                    return false;
-                                }
-                                if trait_.def_id() != self.container.id() {
-                                    return false;
-                                }
-                                match **self_type {
-                                    Generic(ref s) if *s == kw::SelfUpper => {}
-                                    _ => return false,
-                                }
-                                match &assoc.args {
-                                    GenericArgs::AngleBracketed { args, bindings } => {
-                                        if !bindings.is_empty()
-                                            || generics
-                                                .params
-                                                .iter()
-                                                .zip(args.iter())
-                                                .any(|(param, arg)| !param_eq_arg(param, arg))
-                                        {
-                                            return false;
-                                        }
-                                    }
-                                    GenericArgs::Parenthesized { .. } => {
-                                        // The only time this happens is if we're inside the rustdoc for Fn(),
-                                        // which only has one associated type, which is not a GAT, so whatever.
+            if let ty::TraitContainer = assoc_item.container {
+                let bounds = tcx.explicit_item_bounds(assoc_item.def_id);
+                let predicates = ty::GenericPredicates { parent: None, predicates: bounds };
+                let mut generics =
+                    clean_ty_generics(cx, tcx.generics_of(assoc_item.def_id), predicates);
+                // Filter out the bounds that are (likely?) directly attached to the associated type,
+                // as opposed to being located in the where clause.
+                let mut bounds = generics
+                    .where_predicates
+                    .drain_filter(|pred| match *pred {
+                        WherePredicate::BoundPredicate {
+                            ty: QPath { ref assoc, ref self_type, ref trait_, .. },
+                            ..
+                        } => {
+                            if assoc.name != my_name {
+                                return false;
+                            }
+                            if trait_.def_id() != assoc_item.container_id(tcx) {
+                                return false;
+                            }
+                            match **self_type {
+                                Generic(ref s) if *s == kw::SelfUpper => {}
+                                _ => return false,
+                            }
+                            match &assoc.args {
+                                GenericArgs::AngleBracketed { args, bindings } => {
+                                    if !bindings.is_empty()
+                                        || generics
+                                            .params
+                                            .iter()
+                                            .zip(args.iter())
+                                            .any(|(param, arg)| !param_eq_arg(param, arg))
+                                    {
+                                        return false;
                                     }
                                 }
-                                true
-                            }
-                            _ => false,
-                        })
-                        .flat_map(|pred| {
-                            if let WherePredicate::BoundPredicate { bounds, .. } = pred {
-                                bounds
-                            } else {
-                                unreachable!()
+                                GenericArgs::Parenthesized { .. } => {
+                                    // The only time this happens is if we're inside the rustdoc for Fn(),
+                                    // which only has one associated type, which is not a GAT, so whatever.
+                                }
                             }
-                        })
-                        .collect::<Vec<_>>();
-                    // Our Sized/?Sized bound didn't get handled when creating the generics
-                    // because we didn't actually get our whole set of bounds until just now
-                    // (some of them may have come from the trait). If we do have a sized
-                    // bound, we remove it, and if we don't then we add the `?Sized` bound
-                    // at the end.
-                    match bounds.iter().position(|b| b.is_sized_bound(cx)) {
-                        Some(i) => {
-                            bounds.remove(i);
+                            true
                         }
-                        None => bounds.push(GenericBound::maybe_sized(cx)),
+                        _ => false,
+                    })
+                    .flat_map(|pred| {
+                        if let WherePredicate::BoundPredicate { bounds, .. } = pred {
+                            bounds
+                        } else {
+                            unreachable!()
+                        }
+                    })
+                    .collect::<Vec<_>>();
+                // Our Sized/?Sized bound didn't get handled when creating the generics
+                // because we didn't actually get our whole set of bounds until just now
+                // (some of them may have come from the trait). If we do have a sized
+                // bound, we remove it, and if we don't then we add the `?Sized` bound
+                // at the end.
+                match bounds.iter().position(|b| b.is_sized_bound(cx)) {
+                    Some(i) => {
+                        bounds.remove(i);
                     }
+                    None => bounds.push(GenericBound::maybe_sized(cx)),
+                }
 
-                    if self.defaultness.has_value() {
-                        AssocTypeItem(
-                            Box::new(Typedef {
-                                type_: clean_middle_ty(
-                                    tcx.type_of(self.def_id),
-                                    cx,
-                                    Some(self.def_id),
-                                ),
-                                generics,
-                                // FIXME: should we obtain the Type from HIR and pass it on here?
-                                item_type: None,
-                            }),
-                            bounds,
-                        )
-                    } else {
-                        TyAssocTypeItem(Box::new(generics), bounds)
-                    }
-                } else {
-                    // FIXME: when could this happen? Associated items in inherent impls?
+                if tcx.impl_defaultness(assoc_item.def_id).has_value() {
                     AssocTypeItem(
                         Box::new(Typedef {
-                            type_: clean_middle_ty(tcx.type_of(self.def_id), cx, Some(self.def_id)),
-                            generics: Generics { params: Vec::new(), where_predicates: Vec::new() },
+                            type_: clean_middle_ty(
+                                tcx.type_of(assoc_item.def_id),
+                                cx,
+                                Some(assoc_item.def_id),
+                            ),
+                            generics,
+                            // FIXME: should we obtain the Type from HIR and pass it on here?
                             item_type: None,
                         }),
-                        Vec::new(),
+                        bounds,
                     )
+                } else {
+                    TyAssocTypeItem(Box::new(generics), bounds)
                 }
+            } else {
+                // FIXME: when could this happen? Associated items in inherent impls?
+                AssocTypeItem(
+                    Box::new(Typedef {
+                        type_: clean_middle_ty(
+                            tcx.type_of(assoc_item.def_id),
+                            cx,
+                            Some(assoc_item.def_id),
+                        ),
+                        generics: Generics { params: Vec::new(), where_predicates: Vec::new() },
+                        item_type: None,
+                    }),
+                    Vec::new(),
+                )
             }
-        };
+        }
+    };
 
-        let mut what_rustc_thinks =
-            Item::from_def_id_and_parts(self.def_id, Some(self.name), kind, cx);
+    let mut what_rustc_thinks =
+        Item::from_def_id_and_parts(assoc_item.def_id, Some(assoc_item.name), kind, cx);
 
-        let impl_ref = tcx.impl_trait_ref(tcx.parent(self.def_id));
+    let impl_ref = tcx.impl_trait_ref(tcx.parent(assoc_item.def_id));
 
-        // Trait impl items always inherit the impl's visibility --
-        // we don't want to show `pub`.
-        if impl_ref.is_some() {
-            what_rustc_thinks.visibility = Visibility::Inherited;
-        }
-
-        what_rustc_thinks
+    // Trait impl items always inherit the impl's visibility --
+    // we don't want to show `pub`.
+    if impl_ref.is_some() {
+        what_rustc_thinks.visibility = Visibility::Inherited;
     }
+
+    what_rustc_thinks
 }
 
 fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type {
@@ -1356,7 +1319,7 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type
             }
 
             let trait_segments = &p.segments[..p.segments.len() - 1];
-            let trait_def = cx.tcx.associated_item(p.res.def_id()).container.id();
+            let trait_def = cx.tcx.associated_item(p.res.def_id()).container_id(cx.tcx);
             let trait_ = self::Path {
                 res: Res::Def(DefKind::Trait, trait_def),
                 segments: trait_segments.iter().map(|x| x.clean(cx)).collect(),
@@ -1431,7 +1394,8 @@ fn maybe_expand_private_type_alias<'tcx>(
                 });
                 if let Some(lt) = lifetime.cloned() {
                     let lt_def_id = cx.tcx.hir().local_def_id(param.hir_id);
-                    let cleaned = if !lt.is_elided() { lt.clean(cx) } else { Lifetime::elided() };
+                    let cleaned =
+                        if !lt.is_elided() { clean_lifetime(lt, cx) } else { Lifetime::elided() };
                     substs.insert(lt_def_id.to_def_id(), SubstParam::Lifetime(cleaned));
                 }
                 indices.lifetimes += 1;
@@ -1503,7 +1467,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
             // there's no case where it could cause the function to fail to compile.
             let elided =
                 l.is_elided() || matches!(l.name, LifetimeName::Param(_, ParamName::Fresh));
-            let lifetime = if elided { None } else { Some(l.clean(cx)) };
+            let lifetime = if elided { None } else { Some(clean_lifetime(*l, cx)) };
             BorrowedRef { lifetime, mutability: m.mutbl, type_: Box::new(clean_ty(m.ty, cx)) }
         }
         TyKind::Slice(ty) => Slice(Box::new(clean_ty(ty, cx))),
@@ -1531,15 +1495,16 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
         TyKind::OpaqueDef(item_id, _) => {
             let item = cx.tcx.hir().item(item_id);
             if let hir::ItemKind::OpaqueTy(ref ty) = item.kind {
-                ImplTrait(ty.bounds.iter().filter_map(|x| x.clean(cx)).collect())
+                ImplTrait(ty.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect())
             } else {
                 unreachable!()
             }
         }
         TyKind::Path(_) => clean_qpath(ty, cx),
         TyKind::TraitObject(bounds, ref lifetime, _) => {
-            let bounds = bounds.iter().map(|bound| bound.clean(cx)).collect();
-            let lifetime = if !lifetime.is_elided() { Some(lifetime.clean(cx)) } else { None };
+            let bounds = bounds.iter().map(|bound| clean_poly_trait_ref(bound, cx)).collect();
+            let lifetime =
+                if !lifetime.is_elided() { Some(clean_lifetime(*lifetime, cx)) } else { None };
             DynTrait(bounds, lifetime)
         }
         TyKind::BareFn(barefn) => BareFunction(Box::new(barefn.clean(cx))),
@@ -1604,7 +1569,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
         }
         ty::RawPtr(mt) => RawPointer(mt.mutbl, Box::new(clean_middle_ty(mt.ty, cx, None))),
         ty::Ref(r, ty, mutbl) => BorrowedRef {
-            lifetime: r.clean(cx),
+            lifetime: clean_middle_region(r),
             mutability: mutbl,
             type_: Box::new(clean_middle_ty(ty, cx, None)),
         },
@@ -1639,9 +1604,10 @@ pub(crate) fn clean_middle_ty<'tcx>(
             // HACK: pick the first `did` as the `did` of the trait object. Someone
             // might want to implement "native" support for marker-trait-only
             // trait objects.
-            let mut dids = obj.principal_def_id().into_iter().chain(obj.auto_traits());
-            let did = dids
-                .next()
+            let mut dids = obj.auto_traits();
+            let did = obj
+                .principal_def_id()
+                .or_else(|| dids.next())
                 .unwrap_or_else(|| panic!("found trait object `{:?}` with no traits?", this));
             let substs = match obj.principal() {
                 Some(principal) => principal.skip_binder().substs,
@@ -1651,20 +1617,19 @@ pub(crate) fn clean_middle_ty<'tcx>(
 
             inline::record_extern_fqn(cx, did, ItemType::Trait);
 
-            let lifetime = reg.clean(cx);
-            let mut bounds = vec![];
-
-            for did in dids {
-                let empty = cx.tcx.intern_substs(&[]);
-                let path = external_path(cx, did, false, vec![], empty);
-                inline::record_extern_fqn(cx, did, ItemType::Trait);
-                let bound = PolyTrait { trait_: path, generic_params: Vec::new() };
-                bounds.push(bound);
-            }
+            let lifetime = clean_middle_region(*reg);
+            let mut bounds = dids
+                .map(|did| {
+                    let empty = cx.tcx.intern_substs(&[]);
+                    let path = external_path(cx, did, false, vec![], empty);
+                    inline::record_extern_fqn(cx, did, ItemType::Trait);
+                    PolyTrait { trait_: path, generic_params: Vec::new() }
+                })
+                .collect::<Vec<_>>();
 
-            let mut bindings = vec![];
-            for pb in obj.projection_bounds() {
-                bindings.push(TypeBinding {
+            let bindings = obj
+                .projection_bounds()
+                .map(|pb| TypeBinding {
                     assoc: projection_to_path_segment(
                         pb.skip_binder()
                             .lift_to_tcx(cx.tcx)
@@ -1678,8 +1643,8 @@ pub(crate) fn clean_middle_ty<'tcx>(
                     kind: TypeBindingKind::Equality {
                         term: clean_middle_term(pb.skip_binder().term, cx),
                     },
-                });
-            }
+                })
+                .collect();
 
             let path = external_path(cx, did, false, bindings, substs);
             bounds.insert(0, PolyTrait { trait_: path, generic_params: Vec::new() });
@@ -1717,7 +1682,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
                     let trait_ref = match bound_predicate.skip_binder() {
                         ty::PredicateKind::Trait(tr) => bound_predicate.rebind(tr.trait_ref),
                         ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(_ty, reg)) => {
-                            if let Some(r) = reg.clean(cx) {
+                            if let Some(r) = clean_middle_region(reg) {
                                 regions.push(GenericBound::Outlives(r));
                             }
                             return None;
@@ -1861,39 +1826,44 @@ fn clean_path<'tcx>(path: &hir::Path<'tcx>, cx: &mut DocContext<'tcx>) -> Path {
     Path { res: path.res, segments: path.segments.iter().map(|x| x.clean(cx)).collect() }
 }
 
-impl<'tcx> Clean<'tcx, GenericArgs> for hir::GenericArgs<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> GenericArgs {
-        if self.parenthesized {
-            let output = clean_ty(self.bindings[0].ty(), cx);
-            let output =
-                if output != Type::Tuple(Vec::new()) { Some(Box::new(output)) } else { None };
-            let inputs = self.inputs().iter().map(|x| clean_ty(x, cx)).collect::<Vec<_>>().into();
-            GenericArgs::Parenthesized { inputs, output }
-        } else {
-            let args = self
-                .args
-                .iter()
-                .map(|arg| match arg {
-                    hir::GenericArg::Lifetime(lt) if !lt.is_elided() => {
-                        GenericArg::Lifetime(lt.clean(cx))
-                    }
-                    hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()),
-                    hir::GenericArg::Type(ty) => GenericArg::Type(clean_ty(ty, cx)),
-                    hir::GenericArg::Const(ct) => GenericArg::Const(Box::new(clean_const(ct, cx))),
-                    hir::GenericArg::Infer(_inf) => GenericArg::Infer,
-                })
-                .collect::<Vec<_>>()
-                .into();
-            let bindings =
-                self.bindings.iter().map(|x| clean_type_binding(x, cx)).collect::<Vec<_>>().into();
-            GenericArgs::AngleBracketed { args, bindings }
-        }
+fn clean_generic_args<'tcx>(
+    generic_args: &hir::GenericArgs<'tcx>,
+    cx: &mut DocContext<'tcx>,
+) -> GenericArgs {
+    if generic_args.parenthesized {
+        let output = clean_ty(generic_args.bindings[0].ty(), cx);
+        let output = if output != Type::Tuple(Vec::new()) { Some(Box::new(output)) } else { None };
+        let inputs =
+            generic_args.inputs().iter().map(|x| clean_ty(x, cx)).collect::<Vec<_>>().into();
+        GenericArgs::Parenthesized { inputs, output }
+    } else {
+        let args = generic_args
+            .args
+            .iter()
+            .map(|arg| match arg {
+                hir::GenericArg::Lifetime(lt) if !lt.is_elided() => {
+                    GenericArg::Lifetime(clean_lifetime(*lt, cx))
+                }
+                hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()),
+                hir::GenericArg::Type(ty) => GenericArg::Type(clean_ty(ty, cx)),
+                hir::GenericArg::Const(ct) => GenericArg::Const(Box::new(clean_const(ct, cx))),
+                hir::GenericArg::Infer(_inf) => GenericArg::Infer,
+            })
+            .collect::<Vec<_>>()
+            .into();
+        let bindings = generic_args
+            .bindings
+            .iter()
+            .map(|x| clean_type_binding(x, cx))
+            .collect::<Vec<_>>()
+            .into();
+        GenericArgs::AngleBracketed { args, bindings }
     }
 }
 
 impl<'tcx> Clean<'tcx, PathSegment> for hir::PathSegment<'tcx> {
     fn clean(&self, cx: &mut DocContext<'tcx>) -> PathSegment {
-        PathSegment { name: self.ident.name, args: self.args().clean(cx) }
+        PathSegment { name: self.ident.name, args: clean_generic_args(self.args(), cx) }
     }
 }
 
@@ -1934,33 +1904,33 @@ fn clean_maybe_renamed_item<'tcx>(
                 kind: ConstantKind::Local { body: body_id, def_id },
             }),
             ItemKind::OpaqueTy(ref ty) => OpaqueTyItem(OpaqueTy {
-                bounds: ty.bounds.iter().filter_map(|x| x.clean(cx)).collect(),
-                generics: ty.generics.clean(cx),
+                bounds: ty.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
+                generics: clean_generics(ty.generics, cx),
             }),
             ItemKind::TyAlias(hir_ty, generics) => {
                 let rustdoc_ty = clean_ty(hir_ty, cx);
                 let ty = clean_middle_ty(hir_ty_to_ty(cx.tcx, hir_ty), cx, None);
                 TypedefItem(Box::new(Typedef {
                     type_: rustdoc_ty,
-                    generics: generics.clean(cx),
+                    generics: clean_generics(generics, cx),
                     item_type: Some(ty),
                 }))
             }
             ItemKind::Enum(ref def, generics) => EnumItem(Enum {
                 variants: def.variants.iter().map(|v| v.clean(cx)).collect(),
-                generics: generics.clean(cx),
+                generics: clean_generics(generics, cx),
             }),
             ItemKind::TraitAlias(generics, bounds) => TraitAliasItem(TraitAlias {
-                generics: generics.clean(cx),
-                bounds: bounds.iter().filter_map(|x| x.clean(cx)).collect(),
+                generics: clean_generics(generics, cx),
+                bounds: bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
             }),
             ItemKind::Union(ref variant_data, generics) => UnionItem(Union {
-                generics: generics.clean(cx),
+                generics: clean_generics(generics, cx),
                 fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(),
             }),
             ItemKind::Struct(ref variant_data, generics) => StructItem(Struct {
                 struct_type: CtorKind::from_hir(variant_data),
-                generics: generics.clean(cx),
+                generics: clean_generics(generics, cx),
                 fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(),
             }),
             ItemKind::Impl(impl_) => return clean_impl(impl_, item.hir_id(), cx),
@@ -1975,21 +1945,23 @@ fn clean_maybe_renamed_item<'tcx>(
                 })
             }
             ItemKind::Trait(_, _, generics, bounds, item_ids) => {
-                let items =
-                    item_ids.iter().map(|ti| cx.tcx.hir().trait_item(ti.id).clean(cx)).collect();
+                let items = item_ids
+                    .iter()
+                    .map(|ti| clean_trait_item(cx.tcx.hir().trait_item(ti.id), cx))
+                    .collect();
 
                 TraitItem(Trait {
                     def_id,
                     items,
-                    generics: generics.clean(cx),
-                    bounds: bounds.iter().filter_map(|x| x.clean(cx)).collect(),
+                    generics: clean_generics(generics, cx),
+                    bounds: bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
                 })
             }
             ItemKind::ExternCrate(orig_name) => {
                 return clean_extern_crate(item, name, orig_name, cx);
             }
             ItemKind::Use(path, kind) => {
-                return clean_use_statement(item, name, path, kind, cx);
+                return clean_use_statement(item, name, path, kind, cx, &mut FxHashSet::default());
             }
             _ => unreachable!("not yet converted"),
         };
@@ -2015,9 +1987,12 @@ fn clean_impl<'tcx>(
 ) -> Vec<Item> {
     let tcx = cx.tcx;
     let mut ret = Vec::new();
-    let trait_ = impl_.of_trait.as_ref().map(|t| t.clean(cx));
-    let items =
-        impl_.items.iter().map(|ii| tcx.hir().impl_item(ii.id).clean(cx)).collect::<Vec<_>>();
+    let trait_ = impl_.of_trait.as_ref().map(|t| clean_trait_ref(t, cx));
+    let items = impl_
+        .items
+        .iter()
+        .map(|ii| clean_impl_item(tcx.hir().impl_item(ii.id), cx))
+        .collect::<Vec<_>>();
     let def_id = tcx.hir().local_def_id(hir_id);
 
     // If this impl block is an implementation of the Deref trait, then we
@@ -2034,7 +2009,7 @@ fn clean_impl<'tcx>(
     let mut make_item = |trait_: Option<Path>, for_: Type, items: Vec<Item>| {
         let kind = ImplItem(Box::new(Impl {
             unsafety: impl_.unsafety,
-            generics: impl_.generics.clean(cx),
+            generics: clean_generics(impl_.generics, cx),
             trait_,
             for_,
             items,
@@ -2096,7 +2071,7 @@ fn clean_extern_crate<'tcx>(
     // FIXME: using `from_def_id_and_kind` breaks `rustdoc/masked` for some reason
     vec![Item {
         name: Some(name),
-        attrs: Box::new(attrs.clean(cx)),
+        attrs: Box::new(Attributes::from_ast(attrs)),
         item_id: crate_def_id.into(),
         visibility: clean_visibility(ty_vis),
         kind: Box::new(ExternCrateItem { src: orig_name }),
@@ -2110,6 +2085,7 @@ fn clean_use_statement<'tcx>(
     path: &hir::Path<'tcx>,
     kind: hir::UseKind,
     cx: &mut DocContext<'tcx>,
+    inlined_names: &mut FxHashSet<(ItemType, Symbol)>,
 ) -> Vec<Item> {
     // We need this comparison because some imports (for std types for example)
     // are "inserted" as well but directly by the compiler and they should not be
@@ -2175,7 +2151,8 @@ fn clean_use_statement<'tcx>(
     let inner = if kind == hir::UseKind::Glob {
         if !denied {
             let mut visited = FxHashSet::default();
-            if let Some(items) = inline::try_inline_glob(cx, path.res, &mut visited) {
+            if let Some(items) = inline::try_inline_glob(cx, path.res, &mut visited, inlined_names)
+            {
                 return items;
             }
         }
@@ -2229,7 +2206,7 @@ fn clean_maybe_renamed_foreign_item<'tcx>(
             hir::ForeignItemKind::Fn(decl, names, generics) => {
                 let (generics, decl) = enter_impl_trait(cx, |cx| {
                     // NOTE: generics must be cleaned before args
-                    let generics = generics.clean(cx);
+                    let generics = clean_generics(generics, cx);
                     let args = clean_args_from_types_and_names(cx, decl.inputs, names);
                     let decl = clean_fn_decl_with_args(cx, decl, args);
                     (generics, decl)
@@ -2256,13 +2233,16 @@ fn clean_type_binding<'tcx>(
     cx: &mut DocContext<'tcx>,
 ) -> TypeBinding {
     TypeBinding {
-        assoc: PathSegment { name: type_binding.ident.name, args: type_binding.gen_args.clean(cx) },
+        assoc: PathSegment {
+            name: type_binding.ident.name,
+            args: clean_generic_args(type_binding.gen_args, cx),
+        },
         kind: match type_binding.kind {
             hir::TypeBindingKind::Equality { ref term } => {
                 TypeBindingKind::Equality { term: clean_hir_term(term, cx) }
             }
             hir::TypeBindingKind::Constraint { bounds } => TypeBindingKind::Constraint {
-                bounds: bounds.iter().filter_map(|b| b.clean(cx)).collect(),
+                bounds: bounds.iter().filter_map(|b| clean_generic_bound(b, cx)).collect(),
             },
         },
     }
index d022ce9696ad0a9c794a16acd974c3cc63653c4a..91d5758077c94fd98b7f9d1c22425af573274dab 100644 (file)
 use rustc_typeck::check::intrinsic::intrinsic_operation_unsafety;
 
 use crate::clean::cfg::Cfg;
+use crate::clean::clean_visibility;
 use crate::clean::external_path;
 use crate::clean::inline::{self, print_inlined_const};
 use crate::clean::utils::{is_literal_expr, print_const_expr, print_evaluated_const};
-use crate::clean::{clean_visibility, Clean};
 use crate::core::DocContext;
 use crate::formats::cache::Cache;
 use crate::formats::item_type::ItemType;
@@ -122,10 +122,6 @@ pub(crate) struct Crate {
     pub(crate) external_traits: Rc<RefCell<FxHashMap<DefId, TraitWithExtraInfo>>>,
 }
 
-// `Crate` is frequently moved by-value. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Crate, 72);
-
 impl Crate {
     pub(crate) fn name(&self, tcx: TyCtxt<'_>) -> Symbol {
         ExternalCrate::LOCAL.name(tcx)
@@ -389,10 +385,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
-// `Item` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Item, 56);
-
 pub(crate) fn rustc_span(def_id: DefId, tcx: TyCtxt<'_>) -> Span {
     Span::new(def_id.as_local().map_or_else(
         || tcx.def_span(def_id),
@@ -477,7 +469,7 @@ pub(crate) fn from_def_id_and_parts(
             def_id,
             name,
             kind,
-            Box::new(ast_attrs.clean(cx)),
+            Box::new(Attributes::from_ast(ast_attrs)),
             cx,
             ast_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg),
         )
@@ -771,10 +763,6 @@ pub(crate) enum ItemKind {
     KeywordItem,
 }
 
-// `ItemKind` is an enum and large variants can bloat up memory usage even for smaller ones
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(ItemKind, 112);
-
 impl ItemKind {
     /// Some items contain others such as structs (for their fields) and Enums
     /// (for their variants). This method returns those contained items.
@@ -994,10 +982,6 @@ pub(crate) struct DocFragment {
     pub(crate) indent: usize,
 }
 
-// `DocFragment` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(DocFragment, 32);
-
 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
 pub(crate) enum DocFragmentKind {
     /// A doc fragment created from a `///` or `//!` doc comment.
@@ -1177,14 +1161,16 @@ pub(crate) fn has_doc_flag(&self, flag: Symbol) -> bool {
         false
     }
 
-    pub(crate) fn from_ast(
+    pub(crate) fn from_ast(attrs: &[ast::Attribute]) -> Attributes {
+        Attributes::from_ast_iter(attrs.iter().map(|attr| (attr, None)), false)
+    }
+
+    pub(crate) fn from_ast_with_additional(
         attrs: &[ast::Attribute],
-        additional_attrs: Option<(&[ast::Attribute], DefId)>,
+        (additional_attrs, def_id): (&[ast::Attribute], DefId),
     ) -> Attributes {
         // Additional documentation should be shown before the original documentation.
-        let attrs1 = additional_attrs
-            .into_iter()
-            .flat_map(|(attrs, def_id)| attrs.iter().map(move |attr| (attr, Some(def_id))));
+        let attrs1 = additional_attrs.iter().map(|attr| (attr, Some(def_id)));
         let attrs2 = attrs.iter().map(|attr| (attr, None));
         Attributes::from_ast_iter(attrs1.chain(attrs2), false)
     }
@@ -1382,10 +1368,6 @@ pub(crate) struct GenericParamDef {
     pub(crate) kind: GenericParamDefKind,
 }
 
-// `GenericParamDef` is used in many places. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(GenericParamDef, 56);
-
 impl GenericParamDef {
     pub(crate) fn is_synthetic_type_param(&self) -> bool {
         match self.kind {
@@ -1590,10 +1572,6 @@ pub(crate) enum Type {
     ImplTrait(Vec<GenericBound>),
 }
 
-// `Type` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Type, 72);
-
 impl Type {
     /// When comparing types for equality, it can help to ignore `&` wrapping.
     pub(crate) fn without_borrowed_ref(&self) -> &Type {
@@ -2230,33 +2208,18 @@ pub(crate) enum GenericArg {
     Infer,
 }
 
-// `GenericArg` can occur many times in a single `Path`, so make sure it
-// doesn't increase in size unexpectedly.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(GenericArg, 80);
-
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
 pub(crate) enum GenericArgs {
     AngleBracketed { args: Box<[GenericArg]>, bindings: ThinVec<TypeBinding> },
     Parenthesized { inputs: Box<[Type]>, output: Option<Box<Type>> },
 }
 
-// `GenericArgs` is in every `PathSegment`, so its size can significantly
-// affect rustdoc's memory usage.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(GenericArgs, 32);
-
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
 pub(crate) struct PathSegment {
     pub(crate) name: Symbol,
     pub(crate) args: GenericArgs,
 }
 
-// `PathSegment` usually occurs multiple times in every `Path`, so its size can
-// significantly affect rustdoc's memory usage.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(PathSegment, 40);
-
 #[derive(Clone, Debug)]
 pub(crate) struct Typedef {
     pub(crate) type_: Type,
@@ -2527,3 +2490,20 @@ pub(crate) fn as_lt(&self) -> Option<&Lifetime> {
         if let Self::Lifetime(lt) = self { Some(lt) } else { None }
     }
 }
+
+// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+mod size_asserts {
+    use super::*;
+    use rustc_data_structures::static_assert_size;
+    // These are in alphabetical order, which is easy to maintain.
+    static_assert_size!(Crate, 72); // frequently moved by-value
+    static_assert_size!(DocFragment, 32);
+    static_assert_size!(GenericArg, 80);
+    static_assert_size!(GenericArgs, 32);
+    static_assert_size!(GenericParamDef, 56);
+    static_assert_size!(Item, 56);
+    static_assert_size!(ItemKind, 112);
+    static_assert_size!(PathSegment, 40);
+    static_assert_size!(Type, 72);
+}
index 621f70f0da9865f18fbaa564613dbad70b78e479..718cbbd2b83742bf4e97e7d5ce93710e1ea906fe 100644 (file)
@@ -2,9 +2,9 @@
 use crate::clean::blanket_impl::BlanketImplFinder;
 use crate::clean::render_macro_matchers::render_macro_matcher;
 use crate::clean::{
-    clean_middle_const, clean_middle_ty, inline, Clean, Crate, ExternalCrate, Generic, GenericArg,
-    GenericArgs, ImportSource, Item, ItemKind, Lifetime, Path, PathSegment, Primitive,
-    PrimitiveType, Type, TypeBinding, Visibility,
+    clean_doc_module, clean_middle_const, clean_middle_region, clean_middle_ty, inline, Crate,
+    ExternalCrate, Generic, GenericArg, GenericArgs, ImportSource, Item, ItemKind, Lifetime, Path,
+    PathSegment, Primitive, PrimitiveType, Type, TypeBinding, Visibility,
 };
 use crate::core::DocContext;
 use crate::formats::item_type::ItemType;
@@ -37,7 +37,7 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate {
 
     // Clean the crate, translating the entire librustc_ast AST to one that is
     // understood by rustdoc.
-    let mut module = module.clean(cx);
+    let mut module = clean_doc_module(&module, cx);
 
     match *module.kind {
         ItemKind::ModuleItem(ref module) => {
@@ -86,7 +86,7 @@ pub(crate) fn substs_to_args<'tcx>(
         Vec::with_capacity(substs.len().saturating_sub(if skip_first { 1 } else { 0 }));
     ret_val.extend(substs.iter().filter_map(|kind| match kind.unpack() {
         GenericArgKind::Lifetime(lt) => {
-            Some(GenericArg::Lifetime(lt.clean(cx).unwrap_or(Lifetime::elided())))
+            Some(GenericArg::Lifetime(clean_middle_region(lt).unwrap_or(Lifetime::elided())))
         }
         GenericArgKind::Type(_) if skip_first => {
             skip_first = false;
index 213f564ce2db593adcf111041aefdba1d48bf7b6..20ae102bc27d30ce7cee4a74eda73c4b145dad4d 100644 (file)
@@ -1222,7 +1222,7 @@ fn visit_testable<F: FnOnce(&mut Self)>(
 
         // The collapse-docs pass won't combine sugared/raw doc attributes, or included files with
         // anything else, this will combine them for us.
-        let attrs = Attributes::from_ast(ast_attrs, None);
+        let attrs = Attributes::from_ast(ast_attrs);
         if let Some(doc) = attrs.collapsed_doc_value() {
             // Use the outermost invocation, so that doctest names come from where the docs were written.
             let span = ast_attrs
@@ -1289,14 +1289,9 @@ fn visit_foreign_item(&mut self, item: &'hir hir::ForeignItem<'_>) {
         });
     }
 
-    fn visit_variant(
-        &mut self,
-        v: &'hir hir::Variant<'_>,
-        g: &'hir hir::Generics<'_>,
-        item_id: hir::HirId,
-    ) {
+    fn visit_variant(&mut self, v: &'hir hir::Variant<'_>) {
         self.visit_testable(v.ident.to_string(), v.id, v.span, |this| {
-            intravisit::walk_variant(this, v, g, item_id);
+            intravisit::walk_variant(this, v);
         });
     }
 
index 36a47b05cb9d674b0dadd2a817fac9e35bdf7c3b..3dee4d1acc819f4a5ac7fcbdfda502cffe64e1d2 100644 (file)
@@ -152,7 +152,7 @@ pub(crate) fn len(&self) -> usize {
     }
 }
 
-fn comma_sep<T: fmt::Display>(
+pub(crate) fn comma_sep<T: fmt::Display>(
     items: impl Iterator<Item = T>,
     space_after_comma: bool,
 ) -> impl fmt::Display {
index d2ef89078bf6d131751c33f49267359336fa8619..5a6720a8dd95643c07f6c02894daccbf1697e192 100644 (file)
@@ -33,27 +33,39 @@ pub(crate) struct HrefContext<'a, 'b, 'c> {
 
 /// Decorations are represented as a map from CSS class to vector of character ranges.
 /// Each range will be wrapped in a span with that class.
+#[derive(Default)]
 pub(crate) struct DecorationInfo(pub(crate) FxHashMap<&'static str, Vec<(u32, u32)>>);
 
-/// Highlights `src`, returning the HTML output.
-pub(crate) fn render_with_highlighting(
+#[derive(Eq, PartialEq, Clone, Copy)]
+pub(crate) enum Tooltip {
+    Ignore,
+    CompileFail,
+    ShouldPanic,
+    Edition(Edition),
+    None,
+}
+
+/// Highlights `src` as an inline example, returning the HTML output.
+pub(crate) fn render_example_with_highlighting(
     src: &str,
     out: &mut Buffer,
-    class: Option<&str>,
+    tooltip: Tooltip,
     playground_button: Option<&str>,
-    tooltip: Option<(Option<Edition>, &str)>,
-    edition: Edition,
-    extra_content: Option<Buffer>,
-    href_context: Option<HrefContext<'_, '_, '_>>,
-    decoration_info: Option<DecorationInfo>,
 ) {
-    debug!("highlighting: ================\n{}\n==============", src);
-    if let Some((edition_info, class)) = tooltip {
+    let class = match tooltip {
+        Tooltip::Ignore => " ignore",
+        Tooltip::CompileFail => " compile_fail",
+        Tooltip::ShouldPanic => " should_panic",
+        Tooltip::Edition(_) => " edition",
+        Tooltip::None => "",
+    };
+
+    if tooltip != Tooltip::None {
         write!(
             out,
-            "<div class='information'><div class='tooltip {}'{}>ⓘ</div></div>",
+            "<div class='information'><div class='tooltip{}'{}>ⓘ</div></div>",
             class,
-            if let Some(edition_info) = edition_info {
+            if let Tooltip::Edition(edition_info) = tooltip {
                 format!(" data-edition=\"{}\"", edition_info)
             } else {
                 String::new()
@@ -61,20 +73,40 @@ pub(crate) fn render_with_highlighting(
         );
     }
 
-    write_header(out, class, extra_content);
-    write_code(out, src, edition, href_context, decoration_info);
+    write_header(out, &format!("rust-example-rendered{}", class), None);
+    write_code(out, src, None, None);
     write_footer(out, playground_button);
 }
 
-fn write_header(out: &mut Buffer, class: Option<&str>, extra_content: Option<Buffer>) {
+/// Highlights `src` as a macro, returning the HTML output.
+pub(crate) fn render_macro_with_highlighting(src: &str, out: &mut Buffer) {
+    write_header(out, "macro", None);
+    write_code(out, src, None, None);
+    write_footer(out, None);
+}
+
+/// Highlights `src` as a source code page, returning the HTML output.
+pub(crate) fn render_source_with_highlighting(
+    src: &str,
+    out: &mut Buffer,
+    line_numbers: Buffer,
+    href_context: HrefContext<'_, '_, '_>,
+    decoration_info: DecorationInfo,
+) {
+    write_header(out, "", Some(line_numbers));
+    write_code(out, src, Some(href_context), Some(decoration_info));
+    write_footer(out, None);
+}
+
+fn write_header(out: &mut Buffer, class: &str, extra_content: Option<Buffer>) {
     write!(out, "<div class=\"example-wrap\">");
     if let Some(extra) = extra_content {
         out.push_buffer(extra);
     }
-    if let Some(class) = class {
-        write!(out, "<pre class=\"rust {}\">", class);
-    } else {
+    if class.is_empty() {
         write!(out, "<pre class=\"rust\">");
+    } else {
+        write!(out, "<pre class=\"rust {}\">", class);
     }
     write!(out, "<code>");
 }
@@ -93,7 +125,6 @@ fn write_header(out: &mut Buffer, class: Option<&str>, extra_content: Option<Buf
 fn write_code(
     out: &mut Buffer,
     src: &str,
-    edition: Edition,
     href_context: Option<HrefContext<'_, '_, '_>>,
     decoration_info: Option<DecorationInfo>,
 ) {
@@ -102,7 +133,6 @@ fn write_code(
     let mut closing_tags: Vec<&'static str> = Vec::new();
     Classifier::new(
         &src,
-        edition,
         href_context.as_ref().map(|c| c.file_span).unwrap_or(DUMMY_SP),
         decoration_info,
     )
@@ -213,14 +243,14 @@ fn next(&mut self) -> Option<(TokenKind, &'a str)> {
             return None;
         }
         let token = rustc_lexer::first_token(self.src);
-        let (text, rest) = self.src.split_at(token.len);
+        let (text, rest) = self.src.split_at(token.len as usize);
         self.src = rest;
         Some((token.kind, text))
     }
 }
 
 /// Classifies into identifier class; returns `None` if this is a non-keyword identifier.
-fn get_real_ident_class(text: &str, edition: Edition, allow_path_keywords: bool) -> Option<Class> {
+fn get_real_ident_class(text: &str, allow_path_keywords: bool) -> Option<Class> {
     let ignore: &[&str] =
         if allow_path_keywords { &["self", "Self", "super", "crate"] } else { &["self", "Self"] };
     if ignore.iter().any(|k| *k == text) {
@@ -229,7 +259,7 @@ fn get_real_ident_class(text: &str, edition: Edition, allow_path_keywords: bool)
     Some(match text {
         "ref" | "mut" => Class::RefKeyWord,
         "false" | "true" => Class::Bool,
-        _ if Symbol::intern(text).is_reserved(|| edition) => Class::KeyWord,
+        _ if Symbol::intern(text).is_reserved(|| Edition::Edition2021) => Class::KeyWord,
         _ => return None,
     })
 }
@@ -311,7 +341,6 @@ struct Classifier<'a> {
     in_attribute: bool,
     in_macro: bool,
     in_macro_nonterminal: bool,
-    edition: Edition,
     byte_pos: u32,
     file_span: Span,
     src: &'a str,
@@ -321,12 +350,7 @@ struct Classifier<'a> {
 impl<'a> Classifier<'a> {
     /// Takes as argument the source code to HTML-ify, the rust edition to use and the source code
     /// file span which will be used later on by the `span_correspondance_map`.
-    fn new(
-        src: &str,
-        edition: Edition,
-        file_span: Span,
-        decoration_info: Option<DecorationInfo>,
-    ) -> Classifier<'_> {
+    fn new(src: &str, file_span: Span, decoration_info: Option<DecorationInfo>) -> Classifier<'_> {
         let tokens = PeekIter::new(TokenIter { src });
         let decorations = decoration_info.map(Decorations::new);
         Classifier {
@@ -334,7 +358,6 @@ fn new(
             in_attribute: false,
             in_macro: false,
             in_macro_nonterminal: false,
-            edition,
             byte_pos: 0,
             file_span,
             src,
@@ -354,7 +377,6 @@ fn get_full_ident_path(&mut self) -> Vec<(TokenKind, usize, usize)> {
         let start = self.byte_pos as usize;
         let mut pos = start;
         let mut has_ident = false;
-        let edition = self.edition;
 
         loop {
             let mut nb = 0;
@@ -376,7 +398,7 @@ fn get_full_ident_path(&mut self) -> Vec<(TokenKind, usize, usize)> {
 
             if let Some((None, text)) = self.tokens.peek().map(|(token, text)| {
                 if *token == TokenKind::Ident {
-                    let class = get_real_ident_class(text, edition, true);
+                    let class = get_real_ident_class(text, true);
                     (class, text)
                 } else {
                     // Doesn't matter which Class we put in here...
@@ -634,7 +656,7 @@ fn advance(
                 sink(Highlight::Token { text, class: None });
                 return;
             }
-            TokenKind::Ident => match get_real_ident_class(text, self.edition, false) {
+            TokenKind::Ident => match get_real_ident_class(text, false) {
                 None => match text {
                     "Option" | "Result" => Class::PreludeTy,
                     "Some" | "None" | "Ok" | "Err" => Class::PreludeVal,
index 1fea7e983b4482d4113f6d71b6b1dbde88e35088..4861a8ad32da6fa34b63478a637536c841fa792f 100644 (file)
@@ -3,7 +3,6 @@
 use expect_test::expect_file;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_span::create_default_session_globals_then;
-use rustc_span::edition::Edition;
 
 const STYLE: &str = r#"
 <style>
@@ -23,7 +22,7 @@ fn test_html_highlighting() {
         let src = include_str!("fixtures/sample.rs");
         let html = {
             let mut out = Buffer::new();
-            write_code(&mut out, src, Edition::Edition2018, None, None);
+            write_code(&mut out, src, None, None);
             format!("{}<pre><code>{}</code></pre>\n", STYLE, out.into_inner())
         };
         expect_file!["fixtures/sample.html"].assert_eq(&html);
@@ -37,7 +36,7 @@ fn test_dos_backline() {
     println!(\"foo\");\r\n\
 }\r\n";
         let mut html = Buffer::new();
-        write_code(&mut html, src, Edition::Edition2018, None, None);
+        write_code(&mut html, src, None, None);
         expect_file!["fixtures/dos_line.html"].assert_eq(&html.into_inner());
     });
 }
@@ -51,7 +50,7 @@ fn test_keyword_highlight() {
 let y = Self::whatever;";
 
         let mut html = Buffer::new();
-        write_code(&mut html, src, Edition::Edition2018, None, None);
+        write_code(&mut html, src, None, None);
         expect_file!["fixtures/highlight.html"].assert_eq(&html.into_inner());
     });
 }
@@ -61,7 +60,7 @@ fn test_union_highlighting() {
     create_default_session_globals_then(|| {
         let src = include_str!("fixtures/union.rs");
         let mut html = Buffer::new();
-        write_code(&mut html, src, Edition::Edition2018, None, None);
+        write_code(&mut html, src, None, None);
         expect_file!["fixtures/union.html"].assert_eq(&html.into_inner());
     });
 }
@@ -75,7 +74,7 @@ fn test_decorations() {
         decorations.insert("example", vec![(0, 10)]);
 
         let mut html = Buffer::new();
-        write_code(&mut html, src, Edition::Edition2018, None, Some(DecorationInfo(decorations)));
+        write_code(&mut html, src, None, Some(DecorationInfo(decorations)));
         expect_file!["fixtures/decorations.html"].assert_eq(&html.into_inner());
     });
 }
index 52a2effca0ff7957db687d69d1a8eae9df941269..ec2e129c364e80e25a4885049e23c102eb2671ec 100644 (file)
@@ -330,34 +330,27 @@ fn dont_escape(c: u8) -> bool {
         });
 
         let tooltip = if ignore != Ignore::None {
-            Some((None, "ignore"))
+            highlight::Tooltip::Ignore
         } else if compile_fail {
-            Some((None, "compile_fail"))
+            highlight::Tooltip::CompileFail
         } else if should_panic {
-            Some((None, "should_panic"))
+            highlight::Tooltip::ShouldPanic
         } else if explicit_edition {
-            Some((Some(edition), "edition"))
+            highlight::Tooltip::Edition(edition)
         } else {
-            None
+            highlight::Tooltip::None
         };
 
         // insert newline to clearly separate it from the
         // previous block so we can shorten the html output
         let mut s = Buffer::new();
         s.push_str("\n");
-        highlight::render_with_highlighting(
+
+        highlight::render_example_with_highlighting(
             &text,
             &mut s,
-            Some(&format!(
-                "rust-example-rendered{}",
-                if let Some((_, class)) = tooltip { format!(" {}", class) } else { String::new() }
-            )),
-            playground_button.as_deref(),
             tooltip,
-            edition,
-            None,
-            None,
-            None,
+            playground_button.as_deref(),
         );
         Some(Event::Html(s.into_inner().into()))
     }
@@ -1446,6 +1439,8 @@ fn init_id_map() -> FxHashMap<Cow<'static, str>, usize> {
     map.insert("not-displayed".into(), 1);
     map.insert("alternative-display".into(), 1);
     map.insert("search".into(), 1);
+    map.insert("crate-search".into(), 1);
+    map.insert("crate-search-div".into(), 1);
     // This is the list of IDs used in HTML generated in Rust (including the ones
     // used in tera template files).
     map.insert("mainThemeStyle".into(), 1);
@@ -1453,7 +1448,6 @@ fn init_id_map() -> FxHashMap<Cow<'static, str>, usize> {
     map.insert("settings-menu".into(), 1);
     map.insert("help-button".into(), 1);
     map.insert("main-content".into(), 1);
-    map.insert("crate-search".into(), 1);
     map.insert("toggle-all-docs".into(), 1);
     map.insert("all-types".into(), 1);
     map.insert("default-settings".into(), 1);
index a262c8f7d1948657041bbbba1d392a042a182ace..09c54969ef1228e7281901ba6dc629af0563fed4 100644 (file)
@@ -1550,6 +1550,15 @@ fn render_default_items(
         rendering_params: ImplRenderingParameters,
     ) {
         for trait_item in &t.items {
+            // Skip over any default trait items that are impossible to call
+            // (e.g. if it has a `Self: Sized` bound on an unsized type).
+            if let Some(impl_def_id) = parent.item_id.as_def_id()
+                && let Some(trait_item_def_id) = trait_item.item_id.as_def_id()
+                && cx.tcx().is_impossible_method((impl_def_id, trait_item_def_id))
+            {
+                continue;
+            }
+
             let n = trait_item.name;
             if i.items.iter().any(|m| m.name == n) {
                 continue;
@@ -2764,11 +2773,10 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite
         sources::print_src(
             w,
             contents_subset,
-            call_data.edition,
             file_span,
             cx,
             &root_path,
-            Some(highlight::DecorationInfo(decoration_info)),
+            highlight::DecorationInfo(decoration_info),
             sources::SourceContext::Embedded { offset: line_min },
         );
         write!(w, "</div></div>");
index 547d6696a431d26a81a69aa0cdbde0a6c06ee79f..6d0a825fec866aa47a7c04bd4bdb29d5dd1a056c 100644 (file)
@@ -345,7 +345,7 @@ fn cmp(
             clean::ImportItem(ref import) => {
                 let (stab, stab_tags) = if let Some(import_def_id) = import.source.did {
                     let ast_attrs = cx.tcx().get_attrs_unchecked(import_def_id);
-                    let import_attrs = Box::new(clean::Attributes::from_ast(ast_attrs, None));
+                    let import_attrs = Box::new(clean::Attributes::from_ast(ast_attrs));
 
                     // Just need an item with the correct def_id and attrs
                     let import_item = clean::Item {
@@ -1322,17 +1322,7 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
 
 fn item_macro(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::Macro) {
     wrap_into_docblock(w, |w| {
-        highlight::render_with_highlighting(
-            &t.source,
-            w,
-            Some("macro"),
-            None,
-            None,
-            it.span(cx.tcx()).inner().edition(),
-            None,
-            None,
-            None,
-        );
+        highlight::render_macro_with_highlighting(&t.source, w);
     });
     document(w, cx, it, None, HeadingOffset::H2)
 }
index 27ad91d09e0643c0daedbafaf625c9e5ce00126d..f9abb46207d748e957b70261d8fa2c4451425505 100644 (file)
@@ -1,5 +1,4 @@
 use std::ffi::OsStr;
-use std::fmt::Write;
 use std::fs::{self, File};
 use std::io::prelude::*;
 use std::io::{self, BufReader};
@@ -10,7 +9,8 @@
 use itertools::Itertools;
 use rustc_data_structures::flock;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use serde::Serialize;
+use serde::ser::SerializeSeq;
+use serde::{Serialize, Serializer};
 
 use super::{collect_paths_for_type, ensure_trailing_slash, Context, BASIC_KEYWORDS};
 use crate::clean::Crate;
@@ -284,25 +284,43 @@ fn ver_url(cx: &Context<'_>, basename: &'static str) -> String {
         cx.write_shared(SharedResource::Unversioned { name }, contents, &options.emit)?;
     }
 
-    fn collect(path: &Path, krate: &str, key: &str) -> io::Result<(Vec<String>, Vec<String>)> {
+    /// Read a file and return all lines that match the `"{crate}":{data},` format,
+    /// and return a tuple `(Vec<DataString>, Vec<CrateNameString>)`.
+    ///
+    /// This forms the payload of files that look like this:
+    ///
+    /// ```javascript
+    /// var data = {
+    /// "{crate1}":{data},
+    /// "{crate2}":{data}
+    /// };
+    /// use_data(data);
+    /// ```
+    ///
+    /// The file needs to be formatted so that *only crate data lines start with `"`*.
+    fn collect(path: &Path, krate: &str) -> io::Result<(Vec<String>, Vec<String>)> {
         let mut ret = Vec::new();
         let mut krates = Vec::new();
 
         if path.exists() {
-            let prefix = format!(r#"{}["{}"]"#, key, krate);
+            let prefix = format!("\"{}\"", krate);
             for line in BufReader::new(File::open(path)?).lines() {
                 let line = line?;
-                if !line.starts_with(key) {
+                if !line.starts_with('"') {
                     continue;
                 }
                 if line.starts_with(&prefix) {
                     continue;
                 }
-                ret.push(line.to_string());
+                if line.ends_with(",") {
+                    ret.push(line[..line.len() - 1].to_string());
+                } else {
+                    // No comma (it's the case for the last added crate line)
+                    ret.push(line.to_string());
+                }
                 krates.push(
-                    line[key.len() + 2..]
-                        .split('"')
-                        .next()
+                    line.split('"')
+                        .find(|s| !s.is_empty())
                         .map(|s| s.to_owned())
                         .unwrap_or_else(String::new),
                 );
@@ -311,6 +329,20 @@ fn collect(path: &Path, krate: &str, key: &str) -> io::Result<(Vec<String>, Vec<
         Ok((ret, krates))
     }
 
+    /// Read a file and return all lines that match the <code>"{crate}":{data},\</code> format,
+    /// and return a tuple `(Vec<DataString>, Vec<CrateNameString>)`.
+    ///
+    /// This forms the payload of files that look like this:
+    ///
+    /// ```javascript
+    /// var data = JSON.parse('{\
+    /// "{crate1}":{data},\
+    /// "{crate2}":{data}\
+    /// }');
+    /// use_data(data);
+    /// ```
+    ///
+    /// The file needs to be formatted so that *only crate data lines start with `"`*.
     fn collect_json(path: &Path, krate: &str) -> io::Result<(Vec<String>, Vec<String>)> {
         let mut ret = Vec::new();
         let mut krates = Vec::new();
@@ -366,13 +398,15 @@ fn to_json_string(&self) -> String {
                 .collect::<Vec<_>>();
             files.sort_unstable();
             let subs = subs.iter().map(|s| s.to_json_string()).collect::<Vec<_>>().join(",");
-            let dirs =
-                if subs.is_empty() { String::new() } else { format!(",\"dirs\":[{}]", subs) };
+            let dirs = if subs.is_empty() && files.is_empty() {
+                String::new()
+            } else {
+                format!(",[{}]", subs)
+            };
             let files = files.join(",");
-            let files =
-                if files.is_empty() { String::new() } else { format!(",\"files\":[{}]", files) };
+            let files = if files.is_empty() { String::new() } else { format!(",[{}]", files) };
             format!(
-                "{{\"name\":\"{name}\"{dirs}{files}}}",
+                "[\"{name}\"{dirs}{files}]",
                 name = self.elem.to_str().expect("invalid osstring conversion"),
                 dirs = dirs,
                 files = files
@@ -411,18 +445,23 @@ fn to_json_string(&self) -> String {
         let dst = cx.dst.join(&format!("source-files{}.js", cx.shared.resource_suffix));
         let make_sources = || {
             let (mut all_sources, _krates) =
-                try_err!(collect(&dst, krate.name(cx.tcx()).as_str(), "sourcesIndex"), &dst);
+                try_err!(collect_json(&dst, krate.name(cx.tcx()).as_str()), &dst);
             all_sources.push(format!(
-                "sourcesIndex[\"{}\"] = {};",
+                r#""{}":{}"#,
                 &krate.name(cx.tcx()),
-                hierarchy.to_json_string()
+                hierarchy
+                    .to_json_string()
+                    // All these `replace` calls are because we have to go through JS string for JSON content.
+                    .replace('\\', r"\\")
+                    .replace('\'', r"\'")
+                    // We need to escape double quotes for the JSON.
+                    .replace("\\\"", "\\\\\"")
             ));
             all_sources.sort();
-            Ok(format!(
-                "var sourcesIndex = {{}};\n{}\ncreateSourceSidebar();\n",
-                all_sources.join("\n")
-            )
-            .into_bytes())
+            let mut v = String::from("var sourcesIndex = JSON.parse('{\\\n");
+            v.push_str(&all_sources.join(",\\\n"));
+            v.push_str("\\\n}');\ncreateSourceSidebar();\n");
+            Ok(v.into_bytes())
         };
         write_crate("source-files.js", &make_sources)?;
     }
@@ -519,13 +558,27 @@ fn to_json_string(&self) -> String {
             },
         };
 
-        #[derive(Serialize)]
         struct Implementor {
             text: String,
             synthetic: bool,
             types: Vec<String>,
         }
 
+        impl Serialize for Implementor {
+            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+            where
+                S: Serializer,
+            {
+                let mut seq = serializer.serialize_seq(None)?;
+                seq.serialize_element(&self.text)?;
+                if self.synthetic {
+                    seq.serialize_element(&1)?;
+                    seq.serialize_element(&self.types)?;
+                }
+                seq.end()
+            }
+        }
+
         let implementors = imps
             .iter()
             .filter_map(|imp| {
@@ -556,9 +609,9 @@ struct Implementor {
         }
 
         let implementors = format!(
-            r#"implementors["{}"] = {};"#,
+            r#""{}":{}"#,
             krate.name(cx.tcx()),
-            serde_json::to_string(&implementors).unwrap()
+            serde_json::to_string(&implementors).expect("failed serde conversion"),
         );
 
         let mut mydst = dst.clone();
@@ -569,16 +622,15 @@ struct Implementor {
         mydst.push(&format!("{}.{}.js", remote_item_type, remote_path[remote_path.len() - 1]));
 
         let (mut all_implementors, _) =
-            try_err!(collect(&mydst, krate.name(cx.tcx()).as_str(), "implementors"), &mydst);
+            try_err!(collect(&mydst, krate.name(cx.tcx()).as_str()), &mydst);
         all_implementors.push(implementors);
         // Sort the implementors by crate so the file will be generated
         // identically even with rustdoc running in parallel.
         all_implementors.sort();
 
-        let mut v = String::from("(function() {var implementors = {};\n");
-        for implementor in &all_implementors {
-            writeln!(v, "{}", *implementor).unwrap();
-        }
+        let mut v = String::from("(function() {var implementors = {\n");
+        v.push_str(&all_implementors.join(",\n"));
+        v.push_str("\n};");
         v.push_str(
             "if (window.register_implementors) {\
                  window.register_implementors(implementors);\
index d0fd637ba884322c6eea9ef8c630cffb672b7124..f508808a8b6f5c3fae86e527563c80522d11f516 100644 (file)
@@ -11,7 +11,6 @@
 use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
-use rustc_span::edition::Edition;
 use rustc_span::source_map::FileName;
 
 use std::ffi::OsStr;
@@ -213,11 +212,10 @@ fn emit_source(
                 print_src(
                     buf,
                     contents,
-                    cx.shared.edition(),
                     file_span,
                     cx,
                     &root_path,
-                    None,
+                    highlight::DecorationInfo::default(),
                     SourceContext::Standalone,
                 )
             },
@@ -266,11 +264,10 @@ pub(crate) enum SourceContext {
 pub(crate) fn print_src(
     buf: &mut Buffer,
     s: &str,
-    edition: Edition,
     file_span: rustc_span::Span,
     context: &Context<'_>,
     root_path: &str,
-    decoration_info: Option<highlight::DecorationInfo>,
+    decoration_info: highlight::DecorationInfo,
     source_context: SourceContext,
 ) {
     let lines = s.lines().count();
@@ -289,15 +286,11 @@ pub(crate) fn print_src(
         }
     }
     line_numbers.write_str("</pre>");
-    highlight::render_with_highlighting(
+    highlight::render_source_with_highlighting(
         s,
         buf,
-        None,
-        None,
-        None,
-        edition,
-        Some(line_numbers),
-        Some(highlight::HrefContext { context, file_span, root_path }),
+        line_numbers,
+        highlight::HrefContext { context, file_span, root_path },
         decoration_info,
     );
 }
index aecc9aa879a69fe1e392723de2c89d9aa8f2d487..710ca3ee7c7e7e082a4ef478912965a4d5aa179a 100644 (file)
@@ -947,18 +947,33 @@ table,
        height: 100%;
 }
 .search-results-title {
-       display: inline;
+       margin-top: 0;
+       white-space: nowrap;
+       /* flex layout allows shrinking the <select> appropriately if it becomes too large */
+       display: inline-flex;
+       max-width: 100%;
+       /* make things look like in a line, despite the fact that we're using a layout
+       with boxes (i.e. from the flex layout) */
+       align-items: baseline;
 }
-#search-settings {
-       font-size: 1.5rem;
-       font-weight: 500;
-       margin-bottom: 20px;
+#crate-search-div {
+       display: inline-block;
+       /* ensures that 100% in properties of #crate-search-div:after
+       are relative to the size of this div */
+       position: relative;
+       /* allows this div (and with it the <select>-element "#crate-search") to be shrunk */
+       min-width: 5em;
 }
 #crate-search {
        min-width: 115px;
-       margin-top: 5px;
-       padding-left: 0.15em;
+       padding: 0;
+       /* keep these two in sync with "@-moz-document url-prefix()" below */
+       padding-left: 4px;
        padding-right: 23px;
+       /* prevents the <select> from overflowing the containing div in case it's shrunk */
+       max-width: 100%;
+       /* contents can overflow because of max-width limit, then show ellipsis */
+       text-overflow: ellipsis;
        border: 1px solid;
        border-radius: 4px;
        outline: none;
@@ -966,13 +981,37 @@ table,
        -moz-appearance: none;
        -webkit-appearance: none;
        /* Removes default arrow from firefox */
+       text-indent: 0.01px;
+       background-color: var(--main-background-color);
+}
+/* cancel stylistic differences in padding in firefox
+for "appearance: none"-style (or equivalent) <select>s */
+@-moz-document url-prefix() {
+       #crate-search {
+               padding-left: 0px; /* == 4px - 4px */
+               padding-right: 19px; /* == 23px - 4px */
+       }
+}
+/* pseudo-element for holding the dropdown-arrow image; needs to be a separate thing
+so that we can apply CSS-filters to change the arrow color in themes */
+#crate-search-div::after {
+       /* lets clicks through! */
+       pointer-events: none;
+       /* completely covers the underlying div */
+       width: 100%;
+       height: 100%;
+       position: absolute;
+       top: 0;
+       left: 0;
+       content: "";
        background-repeat: no-repeat;
-       background-color: transparent;
        background-size: 20px;
-       background-position: calc(100% - 1px) 56%;
+       background-position: calc(100% - 2px) 56%;
+       /* image is black color, themes should apply a "filter" property to change the color */
        background-image: /* AUTOREPLACE: */url("down-arrow.svg");
-       max-width: 100%;
-       text-overflow: ellipsis;
+}
+#crate-search > option {
+       font-size: 1rem;
 }
 .search-container {
        margin-top: 4px;
@@ -1111,7 +1150,14 @@ table,
 }
 
 .item-info .stab {
-       display: inline-block;
+       width: fit-content;
+       /* This min-height is needed to unify the height of the stab elements because some of them
+          have emojis.
+       */
+       min-height: 36px;
+       display: flex;
+       align-items: center;
+       white-space: pre-wrap;
 }
 .stab {
        padding: 3px;
@@ -1121,6 +1167,7 @@ table,
 }
 .stab p {
        display: inline;
+       margin: 0;
 }
 
 .stab .emoji {
index c42cac59bd6fa36f43bf262b9ae74b15478d91da..39a4dae3348c15032d1871d09fd9d0f5d349f6c3 100644 (file)
@@ -182,7 +182,7 @@ details.rustdoc-toggle > summary::before {
        filter: invert(100%);
 }
 
-#crate-search, .search-input {
+.search-input {
        background-color: #141920;
        border-color: #424c57;
 }
@@ -191,7 +191,17 @@ details.rustdoc-toggle > summary::before {
        /* Without the `!important`, the border-color is ignored for `<select>`...
           It cannot be in the group above because `.search-input` has a different border color on
           hover. */
-       border-color: #424c57 !important;
+       border-color: #5c6773 !important;
+}
+#crate-search-div::after {
+       /* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
+       filter: invert(41%) sepia(12%) saturate(487%) hue-rotate(171deg) brightness(94%) contrast(94%);
+}
+#crate-search:hover, #crate-search:focus {
+       border-color: #e0e0e0 !important;
+}
+#crate-search-div:hover::after, #crate-search-div:focus-within::after {
+       filter: invert(98%) sepia(12%) saturate(81%) hue-rotate(343deg) brightness(113%) contrast(76%);
 }
 
 .search-input {
@@ -203,20 +213,9 @@ details.rustdoc-toggle > summary::before {
        color: #000;
 }
 
-/* Created this empty rule to satisfy the theme checks. */
-.stab.empty-impl {}
-.stab.must_implement {}
-
-.stab.unstable,
-.stab.deprecated,
-.stab.portability,
-.stab.empty-impl,
-.stab.must_implement {
+.stab {
        color: #c5c5c5;
        background: #314559 !important;
-       border-style: none !important;
-       border-radius: 4px;
-       padding: 3px 6px 3px 6px;
 }
 
 .stab.portability > code {
index a550eb1c130afd655c7247454f438b9b5adf5dfd..6188e0ac0a9d3c04cadc39a26d431850d11d2117 100644 (file)
@@ -152,7 +152,7 @@ details.rustdoc-toggle > summary::before {
        filter: invert(100%);
 }
 
-#crate-search, .search-input {
+.search-input {
        color: #111;
        background-color: #f0f0f0;
        border-color: #f0f0f0;
@@ -162,7 +162,17 @@ details.rustdoc-toggle > summary::before {
        /* Without the `!important`, the border-color is ignored for `<select>`...
           It cannot be in the group above because `.search-input` has a different border color on
           hover. */
-       border-color: #f0f0f0 !important;
+       border-color: #d2d2d2 !important;
+}
+#crate-search-div::after {
+       /* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
+       filter: invert(94%) sepia(0%) saturate(721%) hue-rotate(255deg) brightness(90%) contrast(90%);
+}
+#crate-search:hover, #crate-search:focus {
+       border-color: #2196f3 !important;
+}
+#crate-search-div:hover::after, #crate-search-div:focus-within::after {
+       filter: invert(69%) sepia(60%) saturate(6613%) hue-rotate(184deg) brightness(100%) contrast(91%);
 }
 
 .search-input {
@@ -173,12 +183,12 @@ details.rustdoc-toggle > summary::before {
        border-color: #008dfd;
 }
 
-.stab.empty-impl { background: #FFF5D6; border-color: #FFC600; color: #2f2f2f; }
-.stab.unstable { background: #FFF5D6; border-color: #FFC600; color: #2f2f2f; }
-.stab.deprecated { background: #ffc4c4; border-color: #db7b7b; color: #2f2f2f; }
-.stab.must_implement { background: #F3DFFF; border-color: #b07bdb; color: #2f2f2f; }
-.stab.portability { background: #F3DFFF; border-color: #b07bdb; color: #2f2f2f; }
-.stab.portability > code { background: none; }
+.stab { background: #314559; }
+
+.stab.portability > code {
+       color: #e6e1cf;
+       background: none;
+}
 
 .rightside,
 .out-of-band {
index b751acff152cb4b2863fcd600999bc4c57728033..fba790b619371e4b23fd7605a6d063b289501c21 100644 (file)
@@ -144,27 +144,32 @@ details.rustdoc-toggle > summary::before {
        color: #999;
 }
 
-#crate-search, .search-input {
+.search-input {
        background-color: white;
        border-color: #e0e0e0;
 }
-
 #crate-search {
        /* Without the `!important`, the border-color is ignored for `<select>`...
           It cannot be in the group above because `.search-input` has a different border color on
           hover. */
        border-color: #e0e0e0 !important;
 }
+#crate-search-div::after {
+       /* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
+       filter: invert(100%) sepia(0%) saturate(4223%) hue-rotate(289deg) brightness(114%) contrast(76%);
+}
+#crate-search:hover, #crate-search:focus {
+       border-color: #717171 !important;
+}
+#crate-search-div:hover::after, #crate-search-div:focus-within::after {
+       filter: invert(44%) sepia(18%) saturate(23%) hue-rotate(317deg) brightness(96%) contrast(93%);
+}
 
 .search-input:focus {
        border-color: #66afe9;
 }
 
-.stab.empty-impl { background: #FFF5D6; border-color: #FFC600; }
-.stab.unstable { background: #FFF5D6; border-color: #FFC600; }
-.stab.deprecated { background: #ffc4c4; border-color: #db7b7b; }
-.stab.must_implement { background: #F3DFFF; border-color: #b07bdb; }
-.stab.portability { background: #F3DFFF; border-color: #b07bdb; }
+.stab { background: #FFF5D6; border-color: #FFC600; }
 .stab.portability > code { background: none; }
 
 .rightside,
@@ -321,7 +326,7 @@ kbd {
 
 .popover, .popover::before,
 #help-button span.top, #help-button span.bottom {
-       border-color: #DDDDDD;
+       border-color: #e0e0e0;
 }
 
 #copy-path {
index 35437e77a710cac4f1aec365dbfc38d478e3425f..5d76a64e92c70ea2bf86b5010406e641aa680e79 100644 (file)
@@ -1 +1 @@
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="Layer_1" width="128" height="128" enable-background="new 0 0 128 128" version="1.1" viewBox="-30 -20 176 176" xml:space="preserve"><g><line x1="111" x2="64" y1="40.5" y2="87.499" fill="none" stroke="#2F3435" stroke-linecap="square" stroke-miterlimit="10" stroke-width="12"/><line x1="64" x2="17" y1="87.499" y2="40.5" fill="none" stroke="#2F3435" stroke-linecap="square" stroke-miterlimit="10" stroke-width="12"/></g></svg>
\ No newline at end of file
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="Layer_1" width="128" height="128" enable-background="new 0 0 128 128" version="1.1" viewBox="-30 -20 176 176" xml:space="preserve"><g><line x1="111" x2="64" y1="40.5" y2="87.499" fill="none" stroke="#000000" stroke-linecap="square" stroke-miterlimit="10" stroke-width="12"/><line x1="64" x2="17" y1="87.499" y2="40.5" fill="none" stroke="#000000" stroke-linecap="square" stroke-miterlimit="10" stroke-width="12"/></g></svg>
\ No newline at end of file
index 2aef978a072d289bc91a02fd12e87cb512f1f93d..5dec610b30c7b66ffe86d6aaa56cc4392c6db42c 100644 (file)
@@ -348,8 +348,7 @@ function loadCss(cssFileName) {
 
     function onHashChange(ev) {
         // If we're in mobile mode, we should hide the sidebar in any case.
-        const sidebar = document.getElementsByClassName("sidebar")[0];
-        removeClass(sidebar, "shown");
+        hideSidebar();
         handleHashes(ev);
     }
 
@@ -501,6 +500,10 @@ function loadCss(cssFileName) {
         const synthetic_implementors = document.getElementById("synthetic-implementors-list");
         const inlined_types = new Set();
 
+        const TEXT_IDX = 0;
+        const SYNTHETIC_IDX = 1;
+        const TYPES_IDX = 2;
+
         if (synthetic_implementors) {
             // This `inlined_types` variable is used to avoid having the same implementation
             // showing up twice. For example "String" in the "Sync" doc page.
@@ -536,10 +539,12 @@ function loadCss(cssFileName) {
 
             struct_loop:
             for (const struct of structs) {
-                const list = struct.synthetic ? synthetic_implementors : implementors;
+                const list = struct[SYNTHETIC_IDX] ? synthetic_implementors : implementors;
 
-                if (struct.synthetic) {
-                    for (const struct_type of struct.types) {
+                // The types list is only used for synthetic impls.
+                // If this changes, `main.js` and `write_shared.rs` both need changed.
+                if (struct[SYNTHETIC_IDX]) {
+                    for (const struct_type of struct[TYPES_IDX]) {
                         if (inlined_types.has(struct_type)) {
                             continue struct_loop;
                         }
@@ -548,7 +553,7 @@ function loadCss(cssFileName) {
                 }
 
                 const code = document.createElement("h3");
-                code.innerHTML = struct.text;
+                code.innerHTML = struct[TEXT_IDX];
                 addClass(code, "code-header");
                 addClass(code, "in-band");
 
@@ -728,11 +733,50 @@ function loadCss(cssFileName) {
         });
     }());
 
+    let oldSidebarScrollPosition = null;
+
+    function showSidebar() {
+        if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) {
+            // This is to keep the scroll position on mobile.
+            oldSidebarScrollPosition = window.scrollY;
+            document.body.style.width = `${document.body.offsetWidth}px`;
+            document.body.style.position = "fixed";
+            document.body.style.top = `-${oldSidebarScrollPosition}px`;
+            document.querySelector(".mobile-topbar").style.top = `${oldSidebarScrollPosition}px`;
+            document.querySelector(".mobile-topbar").style.position = "relative";
+        } else {
+            oldSidebarScrollPosition = null;
+        }
+        const sidebar = document.getElementsByClassName("sidebar")[0];
+        addClass(sidebar, "shown");
+    }
+
     function hideSidebar() {
+        if (oldSidebarScrollPosition !== null) {
+            // This is to keep the scroll position on mobile.
+            document.body.style.width = "";
+            document.body.style.position = "";
+            document.body.style.top = "";
+            document.querySelector(".mobile-topbar").style.top = "";
+            document.querySelector(".mobile-topbar").style.position = "";
+            // The scroll position is lost when resetting the style, hence why we store it in
+            // `oldSidebarScrollPosition`.
+            window.scrollTo(0, oldSidebarScrollPosition);
+            oldSidebarScrollPosition = null;
+        }
         const sidebar = document.getElementsByClassName("sidebar")[0];
         removeClass(sidebar, "shown");
     }
 
+    window.addEventListener("resize", () => {
+        if (window.innerWidth >= window.RUSTDOC_MOBILE_BREAKPOINT &&
+            oldSidebarScrollPosition !== null) {
+            // If the user opens the sidebar in "mobile" mode, and then grows the browser window,
+            // we need to switch away from mobile mode and make the main content area scrollable.
+            hideSidebar();
+        }
+    });
+
     function handleClick(id, f) {
         const elem = document.getElementById(id);
         if (elem) {
@@ -775,9 +819,9 @@ function loadCss(cssFileName) {
         sidebar_menu_toggle.addEventListener("click", () => {
             const sidebar = document.getElementsByClassName("sidebar")[0];
             if (!hasClass(sidebar, "shown")) {
-                addClass(sidebar, "shown");
+                showSidebar();
             } else {
-                removeClass(sidebar, "shown");
+                hideSidebar();
             }
         });
     }
@@ -816,7 +860,7 @@ function loadCss(cssFileName) {
              <code>enum</code>, <code>trait</code>, <code>type</code>, <code>macro</code>, \
              and <code>const</code>.",
             "Search functions by type signature (e.g., <code>vec -&gt; usize</code> or \
-             <code>-&gt; vec</code>)",
+             <code>-&gt; vec</code>)",
             "Search multiple things at once by splitting your query with comma (e.g., \
              <code>str,u8</code> or <code>String,struct:Vec,test</code>)",
             "You can look for items with an exact name by putting double quotes around \
index 75c7bd45a294923575e89e888548f67da87c5154..d04ec357c40acd5434de2ccd86217642c7c58c03 100644 (file)
@@ -429,9 +429,9 @@ function initSearch(rawSearchIndex) {
             }
             const posBefore = parserState.pos;
             getNextElem(query, parserState, elems, endChar === ">");
-            // This case can be encountered if `getNextElem` encounted a "stop character" right from
-            // the start. For example if you have `,,` or `<>`. In this case, we simply move up the
-            // current position to continue the parsing.
+            // This case can be encountered if `getNextElem` encountered a "stop character" right
+            // from the start. For example if you have `,,` or `<>`. In this case, we simply move up
+            // the current position to continue the parsing.
             if (posBefore === parserState.pos) {
                 parserState.pos += 1;
             }
@@ -581,7 +581,7 @@ function initSearch(rawSearchIndex) {
         const elem = document.getElementById("crate-search");
 
         if (elem &&
-            elem.value !== "All crates" &&
+            elem.value !== "all crates" &&
             hasOwnPropertyRustdoc(rawSearchIndex, elem.value)
         ) {
             return elem.value;
@@ -1551,12 +1551,6 @@ function initSearch(rawSearchIndex) {
         return [displayPath, href];
     }
 
-    function escape(content) {
-        const h1 = document.createElement("h1");
-        h1.textContent = content;
-        return h1.innerHTML;
-    }
-
     function pathSplitter(path) {
         const tmp = "<span>" + path.replace(/::/g, "::</span><span>");
         if (tmp.endsWith("<span>")) {
@@ -1710,22 +1704,15 @@ function initSearch(rawSearchIndex) {
         let crates = "";
         const crates_list = Object.keys(rawSearchIndex);
         if (crates_list.length > 1) {
-            crates = " in <select id=\"crate-search\"><option value=\"All crates\">" +
-                "All crates</option>";
+            crates = " in&nbsp;<div id=\"crate-search-div\"><select id=\"crate-search\">" +
+                "<option value=\"all crates\">all crates</option>";
             for (const c of crates_list) {
                 crates += `<option value="${c}" ${c === filterCrates && "selected"}>${c}</option>`;
             }
-            crates += "</select>";
-        }
-
-        let typeFilter = "";
-        if (results.query.typeFilter !== NO_TYPE_FILTER) {
-            typeFilter = " (type: " + escape(itemTypes[results.query.typeFilter]) + ")";
+            crates += "</select></div>";
         }
 
-        let output = "<div id=\"search-settings\">" +
-            `<h1 class="search-results-title">Results for ${escape(results.query.userQuery)}` +
-            `${typeFilter}</h1>${crates}</div>`;
+        let output = `<h1 class="search-results-title">Results${crates}</h1>`;
         if (results.query.error !== null) {
             output += `<h3>Query parser error: "${results.query.error}".</h3>`;
             output += "<div id=\"titles\">" +
@@ -2245,7 +2232,7 @@ function initSearch(rawSearchIndex) {
     }
 
     function updateCrate(ev) {
-        if (ev.target.value === "All crates") {
+        if (ev.target.value === "all crates") {
             // If we don't remove it from the URL, it'll be picked up again by the search.
             const params = searchState.getQueryStringParams();
             const query = searchState.input.value.trim();
index a6a0b09ef31fef7c6ed1edd0204d0e93573fd89d..06d15d9e5ffea9ad239ad69ee5f8f50fefe302df 100644 (file)
 (function() {
 
 const rootPath = document.getElementById("rustdoc-vars").attributes["data-root-path"].value;
-let oldScrollPosition = 0;
+let oldScrollPosition = null;
+
+const NAME_OFFSET = 0;
+const DIRS_OFFSET = 1;
+const FILES_OFFSET = 2;
 
 function closeSidebarIfMobile() {
     if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) {
@@ -24,15 +28,15 @@ function createDirEntry(elem, parent, fullPath, hasFoundFile) {
 
     dirEntry.className = "dir-entry";
 
-    fullPath += elem["name"] + "/";
+    fullPath += elem[NAME_OFFSET] + "/";
 
-    summary.innerText = elem["name"];
+    summary.innerText = elem[NAME_OFFSET];
     dirEntry.appendChild(summary);
 
     const folders = document.createElement("div");
     folders.className = "folders";
-    if (elem.dirs) {
-        for (const dir of elem.dirs) {
+    if (elem[DIRS_OFFSET]) {
+        for (const dir of elem[DIRS_OFFSET]) {
             if (createDirEntry(dir, folders, fullPath, false)) {
                 dirEntry.open = true;
                 hasFoundFile = true;
@@ -43,8 +47,8 @@ function createDirEntry(elem, parent, fullPath, hasFoundFile) {
 
     const files = document.createElement("div");
     files.className = "files";
-    if (elem.files) {
-        for (const file_text of elem.files) {
+    if (elem[FILES_OFFSET]) {
+        for (const file_text of elem[FILES_OFFSET]) {
             const file = document.createElement("a");
             file.innerText = file_text;
             file.href = rootPath + "src/" + fullPath + file_text + ".html";
@@ -71,18 +75,21 @@ function toggleSidebar() {
             oldScrollPosition = window.scrollY;
             document.body.style.position = "fixed";
             document.body.style.top = `-${oldScrollPosition}px`;
+        } else {
+            oldScrollPosition = null;
         }
         addClass(document.documentElement, "source-sidebar-expanded");
         child.innerText = "<";
         updateLocalStorage("source-sidebar-show", "true");
     } else {
-        if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) {
+        if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT && oldScrollPosition !== null) {
             // This is to keep the scroll position on mobile.
             document.body.style.position = "";
             document.body.style.top = "";
             // The scroll position is lost when resetting the style, hence why we store it in
-            // `oldScroll`.
+            // `oldScrollPosition`.
             window.scrollTo(0, oldScrollPosition);
+            oldScrollPosition = null;
         }
         removeClass(document.documentElement, "source-sidebar-expanded");
         child.innerText = ">";
@@ -90,6 +97,17 @@ function toggleSidebar() {
     }
 }
 
+window.addEventListener("resize", () => {
+    if (window.innerWidth >= window.RUSTDOC_MOBILE_BREAKPOINT && oldScrollPosition !== null) {
+        // If the user opens the sidebar in "mobile" mode, and then grows the browser window,
+        // we need to switch away from mobile mode and make the main content area scrollable.
+        document.body.style.position = "";
+        document.body.style.top = "";
+        window.scrollTo(0, oldScrollPosition);
+        oldScrollPosition = null;
+    }
+});
+
 function createSidebarToggle() {
     const sidebarToggle = document.createElement("div");
     sidebarToggle.id = "sidebar-toggle";
@@ -125,7 +143,7 @@ function createSourceSidebar() {
     title.innerText = "Files";
     sidebar.appendChild(title);
     Object.keys(sourcesIndex).forEach(key => {
-        sourcesIndex[key].name = key;
+        sourcesIndex[key][NAME_OFFSET] = key;
         hasFoundFile = createDirEntry(sourcesIndex[key], sidebar, "",
             hasFoundFile);
     });
index 716a4c9ea4319d1d56ab74535fab1465f4b75bde..4c21fd553289bd2a6066e8d01e86cf82b5483dbb 100644 (file)
@@ -119,6 +119,16 @@ fn into_tcx(self, tcx: TyCtxt<'_>) -> U {
     }
 }
 
+impl<I, T, U> FromWithTcx<I> for Vec<U>
+where
+    I: IntoIterator<Item = T>,
+    U: FromWithTcx<T>,
+{
+    fn from_tcx(f: I, tcx: TyCtxt<'_>) -> Vec<U> {
+        f.into_iter().map(|x| x.into_tcx(tcx)).collect()
+    }
+}
+
 pub(crate) fn from_deprecation(deprecation: rustc_attr::Deprecation) -> Deprecation {
     #[rustfmt::skip]
     let rustc_attr::Deprecation { since, note, is_since_rustc_version: _, suggestion: _ } = deprecation;
@@ -130,11 +140,11 @@ fn from_tcx(args: clean::GenericArgs, tcx: TyCtxt<'_>) -> Self {
         use clean::GenericArgs::*;
         match args {
             AngleBracketed { args, bindings } => GenericArgs::AngleBracketed {
-                args: args.into_vec().into_iter().map(|a| a.into_tcx(tcx)).collect(),
-                bindings: bindings.into_iter().map(|a| a.into_tcx(tcx)).collect(),
+                args: args.into_vec().into_tcx(tcx),
+                bindings: bindings.into_tcx(tcx),
             },
             Parenthesized { inputs, output } => GenericArgs::Parenthesized {
-                inputs: inputs.into_vec().into_iter().map(|a| a.into_tcx(tcx)).collect(),
+                inputs: inputs.into_vec().into_tcx(tcx),
                 output: output.map(|a| (*a).into_tcx(tcx)),
             },
         }
@@ -145,7 +155,7 @@ impl FromWithTcx<clean::GenericArg> for GenericArg {
     fn from_tcx(arg: clean::GenericArg, tcx: TyCtxt<'_>) -> Self {
         use clean::GenericArg::*;
         match arg {
-            Lifetime(l) => GenericArg::Lifetime(l.0.to_string()),
+            Lifetime(l) => GenericArg::Lifetime(convert_lifetime(l)),
             Type(t) => GenericArg::Type(t.into_tcx(tcx)),
             Const(box c) => GenericArg::Const(c.into_tcx(tcx)),
             Infer => GenericArg::Infer,
@@ -177,9 +187,7 @@ fn from_tcx(kind: clean::TypeBindingKind, tcx: TyCtxt<'_>) -> Self {
         use clean::TypeBindingKind::*;
         match kind {
             Equality { term } => TypeBindingKind::Equality(term.into_tcx(tcx)),
-            Constraint { bounds } => {
-                TypeBindingKind::Constraint(bounds.into_iter().map(|a| a.into_tcx(tcx)).collect())
-            }
+            Constraint { bounds } => TypeBindingKind::Constraint(bounds.into_tcx(tcx)),
         }
     }
 }
@@ -244,7 +252,7 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum {
         TraitAliasItem(t) => ItemEnum::TraitAlias(t.into_tcx(tcx)),
         MethodItem(m, _) => ItemEnum::Method(from_function_method(m, true, header.unwrap(), tcx)),
         TyMethodItem(m) => ItemEnum::Method(from_function_method(m, false, header.unwrap(), tcx)),
-        ImplItem(i) => ItemEnum::Impl(i.into_tcx(tcx)),
+        ImplItem(i) => ItemEnum::Impl((*i).into_tcx(tcx)),
         StaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)),
         ForeignStaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)),
         ForeignTypeItem => ItemEnum::ForeignType,
@@ -260,12 +268,12 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum {
         }
         TyAssocTypeItem(g, b) => ItemEnum::AssocType {
             generics: (*g).into_tcx(tcx),
-            bounds: b.into_iter().map(|x| x.into_tcx(tcx)).collect(),
+            bounds: b.into_tcx(tcx),
             default: None,
         },
         AssocTypeItem(t, b) => ItemEnum::AssocType {
             generics: t.generics.into_tcx(tcx),
-            bounds: b.into_iter().map(|x| x.into_tcx(tcx)).collect(),
+            bounds: b.into_tcx(tcx),
             default: Some(t.item_type.unwrap_or(t.type_).into_tcx(tcx)),
         },
         // `convert_item` early returns `None` for stripped items and keywords.
@@ -347,15 +355,15 @@ fn convert_abi(a: RustcAbi) -> Abi {
     }
 }
 
+fn convert_lifetime(l: clean::Lifetime) -> String {
+    l.0.to_string()
+}
+
 impl FromWithTcx<clean::Generics> for Generics {
     fn from_tcx(generics: clean::Generics, tcx: TyCtxt<'_>) -> Self {
         Generics {
-            params: generics.params.into_iter().map(|x| x.into_tcx(tcx)).collect(),
-            where_predicates: generics
-                .where_predicates
-                .into_iter()
-                .map(|x| x.into_tcx(tcx))
-                .collect(),
+            params: generics.params.into_tcx(tcx),
+            where_predicates: generics.where_predicates.into_tcx(tcx),
         }
     }
 }
@@ -374,10 +382,10 @@ fn from_tcx(kind: clean::GenericParamDefKind, tcx: TyCtxt<'_>) -> Self {
         use clean::GenericParamDefKind::*;
         match kind {
             Lifetime { outlives } => GenericParamDefKind::Lifetime {
-                outlives: outlives.into_iter().map(|lt| lt.0.to_string()).collect(),
+                outlives: outlives.into_iter().map(convert_lifetime).collect(),
             },
             Type { did: _, bounds, default, synthetic } => GenericParamDefKind::Type {
-                bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
+                bounds: bounds.into_tcx(tcx),
                 default: default.map(|x| (*x).into_tcx(tcx)),
                 synthetic,
             },
@@ -395,7 +403,7 @@ fn from_tcx(predicate: clean::WherePredicate, tcx: TyCtxt<'_>) -> Self {
         match predicate {
             BoundPredicate { ty, bounds, bound_params } => WherePredicate::BoundPredicate {
                 type_: ty.into_tcx(tcx),
-                bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
+                bounds: bounds.into_tcx(tcx),
                 generic_params: bound_params
                     .into_iter()
                     .map(|x| GenericParamDef {
@@ -405,8 +413,8 @@ fn from_tcx(predicate: clean::WherePredicate, tcx: TyCtxt<'_>) -> Self {
                     .collect(),
             },
             RegionPredicate { lifetime, bounds } => WherePredicate::RegionPredicate {
-                lifetime: lifetime.0.to_string(),
-                bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
+                lifetime: convert_lifetime(lifetime),
+                bounds: bounds.into_tcx(tcx),
             },
             EqPredicate { lhs, rhs } => {
                 WherePredicate::EqPredicate { lhs: lhs.into_tcx(tcx), rhs: rhs.into_tcx(tcx) }
@@ -424,11 +432,11 @@ fn from_tcx(bound: clean::GenericBound, tcx: TyCtxt<'_>) -> Self {
                 let trait_ = clean::Type::Path { path: trait_ }.into_tcx(tcx);
                 GenericBound::TraitBound {
                     trait_,
-                    generic_params: generic_params.into_iter().map(|x| x.into_tcx(tcx)).collect(),
+                    generic_params: generic_params.into_tcx(tcx),
                     modifier: from_trait_bound_modifier(modifier),
                 }
             }
-            Outlives(lifetime) => GenericBound::Outlives(lifetime.0.to_string()),
+            Outlives(lifetime) => GenericBound::Outlives(convert_lifetime(lifetime)),
         }
     }
 }
@@ -447,8 +455,8 @@ pub(crate) fn from_trait_bound_modifier(
 impl FromWithTcx<clean::Type> for Type {
     fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self {
         use clean::Type::{
-            Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive,
-            QPath, RawPointer, Slice, Tuple,
+            Array, BareFunction, BorrowedRef, Generic, ImplTrait, Infer, Primitive, QPath,
+            RawPointer, Slice, Tuple,
         };
 
         match ty {
@@ -458,40 +466,24 @@ fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self {
                 args: path.segments.last().map(|args| Box::new(args.clone().args.into_tcx(tcx))),
                 param_names: Vec::new(),
             },
-            DynTrait(mut bounds, lt) => {
-                let first_trait = bounds.remove(0).trait_;
-
-                Type::ResolvedPath {
-                    name: first_trait.whole_name(),
-                    id: from_item_id(first_trait.def_id().into(), tcx),
-                    args: first_trait
-                        .segments
-                        .last()
-                        .map(|args| Box::new(args.clone().args.into_tcx(tcx))),
-                    param_names: bounds
-                        .into_iter()
-                        .map(|t| {
-                            clean::GenericBound::TraitBound(t, rustc_hir::TraitBoundModifier::None)
-                        })
-                        .chain(lt.map(clean::GenericBound::Outlives))
-                        .map(|bound| bound.into_tcx(tcx))
-                        .collect(),
-                }
-            }
+            clean::Type::DynTrait(bounds, lt) => Type::DynTrait(DynTrait {
+                lifetime: lt.map(convert_lifetime),
+                traits: bounds.into_tcx(tcx),
+            }),
             Generic(s) => Type::Generic(s.to_string()),
             Primitive(p) => Type::Primitive(p.as_sym().to_string()),
             BareFunction(f) => Type::FunctionPointer(Box::new((*f).into_tcx(tcx))),
-            Tuple(t) => Type::Tuple(t.into_iter().map(|x| x.into_tcx(tcx)).collect()),
+            Tuple(t) => Type::Tuple(t.into_tcx(tcx)),
             Slice(t) => Type::Slice(Box::new((*t).into_tcx(tcx))),
             Array(t, s) => Type::Array { type_: Box::new((*t).into_tcx(tcx)), len: s },
-            ImplTrait(g) => Type::ImplTrait(g.into_iter().map(|x| x.into_tcx(tcx)).collect()),
+            ImplTrait(g) => Type::ImplTrait(g.into_tcx(tcx)),
             Infer => Type::Infer,
             RawPointer(mutability, type_) => Type::RawPointer {
                 mutable: mutability == ast::Mutability::Mut,
                 type_: Box::new((*type_).into_tcx(tcx)),
             },
             BorrowedRef { lifetime, mutability, type_ } => Type::BorrowedRef {
-                lifetime: lifetime.map(|l| l.0.to_string()),
+                lifetime: lifetime.map(convert_lifetime),
                 mutable: mutability == ast::Mutability::Mut,
                 type_: Box::new((*type_).into_tcx(tcx)),
             },
@@ -528,7 +520,7 @@ fn from_tcx(bare_decl: clean::BareFunctionDecl, tcx: TyCtxt<'_>) -> Self {
                 async_: false,
                 abi: convert_abi(abi),
             },
-            generic_params: generic_params.into_iter().map(|x| x.into_tcx(tcx)).collect(),
+            generic_params: generic_params.into_tcx(tcx),
             decl: decl.into_tcx(tcx),
         }
     }
@@ -562,16 +554,28 @@ fn from_tcx(trait_: clean::Trait, tcx: TyCtxt<'_>) -> Self {
             is_unsafe,
             items: ids(items, tcx),
             generics: generics.into_tcx(tcx),
-            bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
+            bounds: bounds.into_tcx(tcx),
             implementations: Vec::new(), // Added in JsonRenderer::item
         }
     }
 }
 
-impl FromWithTcx<Box<clean::Impl>> for Impl {
-    fn from_tcx(impl_: Box<clean::Impl>, tcx: TyCtxt<'_>) -> Self {
+impl FromWithTcx<clean::PolyTrait> for PolyTrait {
+    fn from_tcx(
+        clean::PolyTrait { trait_, generic_params }: clean::PolyTrait,
+        tcx: TyCtxt<'_>,
+    ) -> Self {
+        PolyTrait {
+            trait_: clean::Type::Path { path: trait_ }.into_tcx(tcx),
+            generic_params: generic_params.into_tcx(tcx),
+        }
+    }
+}
+
+impl FromWithTcx<clean::Impl> for Impl {
+    fn from_tcx(impl_: clean::Impl, tcx: TyCtxt<'_>) -> Self {
         let provided_trait_methods = impl_.provided_trait_methods(tcx);
-        let clean::Impl { unsafety, generics, trait_, for_, items, polarity, kind } = *impl_;
+        let clean::Impl { unsafety, generics, trait_, for_, items, polarity, kind } = impl_;
         // FIXME: should `trait_` be a clean::Path equivalent in JSON?
         let trait_ = trait_.map(|path| clean::Type::Path { path }.into_tcx(tcx));
         // FIXME: use something like ImplKind in JSON?
@@ -681,24 +685,18 @@ fn from_tcx(variant: clean::Variant, tcx: TyCtxt<'_>) -> Self {
 impl FromWithTcx<clean::Import> for Import {
     fn from_tcx(import: clean::Import, tcx: TyCtxt<'_>) -> Self {
         use clean::ImportKind::*;
-        match import.kind {
-            Simple(s) => Import {
-                source: import.source.path.whole_name(),
-                name: s.to_string(),
-                id: import.source.did.map(ItemId::from).map(|i| from_item_id(i, tcx)),
-                glob: false,
-            },
-            Glob => Import {
-                source: import.source.path.whole_name(),
-                name: import
-                    .source
-                    .path
-                    .last_opt()
-                    .unwrap_or_else(|| Symbol::intern("*"))
-                    .to_string(),
-                id: import.source.did.map(ItemId::from).map(|i| from_item_id(i, tcx)),
-                glob: true,
-            },
+        let (name, glob) = match import.kind {
+            Simple(s) => (s.to_string(), false),
+            Glob => (
+                import.source.path.last_opt().unwrap_or_else(|| Symbol::intern("*")).to_string(),
+                true,
+            ),
+        };
+        Import {
+            source: import.source.path.whole_name(),
+            name,
+            id: import.source.did.map(ItemId::from).map(|i| from_item_id(i, tcx)),
+            glob,
         }
     }
 }
@@ -730,10 +728,7 @@ fn from_tcx(typedef: Box<clean::Typedef>, tcx: TyCtxt<'_>) -> Self {
 
 impl FromWithTcx<clean::OpaqueTy> for OpaqueTy {
     fn from_tcx(opaque: clean::OpaqueTy, tcx: TyCtxt<'_>) -> Self {
-        OpaqueTy {
-            bounds: opaque.bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
-            generics: opaque.generics.into_tcx(tcx),
-        }
+        OpaqueTy { bounds: opaque.bounds.into_tcx(tcx), generics: opaque.generics.into_tcx(tcx) }
     }
 }
 
@@ -749,10 +744,7 @@ fn from_tcx(stat: clean::Static, tcx: TyCtxt<'_>) -> Self {
 
 impl FromWithTcx<clean::TraitAlias> for TraitAlias {
     fn from_tcx(alias: clean::TraitAlias, tcx: TyCtxt<'_>) -> Self {
-        TraitAlias {
-            generics: alias.generics.into_tcx(tcx),
-            params: alias.bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
-        }
+        TraitAlias { generics: alias.generics.into_tcx(tcx), params: alias.bounds.into_tcx(tcx) }
     }
 }
 
index 1751249fa626d44f7f5cebe5b25963fe4d4c924f..7d7a63c53847a501ed20f29b785715d60144789f 100644 (file)
@@ -234,7 +234,7 @@ pub(crate) fn render(&self, s: &mut String, tcx: TyCtxt<'_>) {
             &UrlFragment::Item(def_id) => {
                 let kind = match tcx.def_kind(def_id) {
                     DefKind::AssocFn => {
-                        if tcx.associated_item(def_id).defaultness.has_value() {
+                        if tcx.impl_defaultness(def_id).has_value() {
                             "method."
                         } else {
                             "tymethod."
index 533e2ce46ddd844acb4691f68b5591007c45fef3..9914edf3036e431ba5bedd089b32b3b4cfb6b4e8 100644 (file)
@@ -17,6 +17,7 @@
 /// Strip items marked `#[doc(hidden)]`
 pub(crate) fn strip_hidden(krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate {
     let mut retained = ItemIdSet::default();
+    let is_json_output = cx.output_format.is_json() && !cx.show_coverage;
 
     // strip all #[doc(hidden)] items
     let krate = {
@@ -25,7 +26,12 @@ pub(crate) fn strip_hidden(krate: clean::Crate, cx: &mut DocContext<'_>) -> clea
     };
 
     // strip all impls referencing stripped items
-    let mut stripper = ImplStripper { retained: &retained, cache: &cx.cache };
+    let mut stripper = ImplStripper {
+        retained: &retained,
+        cache: &cx.cache,
+        is_json_output,
+        document_private: cx.render_options.document_private,
+    };
     stripper.fold_crate(krate)
 }
 
index 9ba841a31cf9545b71a207ffb4cd7958dae6e72c..f3aa3c7ce2459d4ac5b4fbc676d65d80e51a213c 100644 (file)
@@ -17,6 +17,7 @@
 pub(crate) fn strip_private(mut krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate {
     // This stripper collects all *retained* nodes.
     let mut retained = ItemIdSet::default();
+    let is_json_output = cx.output_format.is_json() && !cx.show_coverage;
 
     // strip all private items
     {
@@ -24,12 +25,17 @@ pub(crate) fn strip_private(mut krate: clean::Crate, cx: &mut DocContext<'_>) ->
             retained: &mut retained,
             access_levels: &cx.cache.access_levels,
             update_retained: true,
-            is_json_output: cx.output_format.is_json() && !cx.show_coverage,
+            is_json_output,
         };
         krate = ImportStripper.fold_crate(stripper.fold_crate(krate));
     }
 
     // strip all impls referencing private items
-    let mut stripper = ImplStripper { retained: &retained, cache: &cx.cache };
+    let mut stripper = ImplStripper {
+        retained: &retained,
+        cache: &cx.cache,
+        is_json_output,
+        document_private: cx.render_options.document_private,
+    };
     stripper.fold_crate(krate)
 }
index 0d419042a10a47508097a8bf2102445f2a4cab54..3f069e8393f7e9667bfea7a05834ea86f21e0ee8 100644 (file)
@@ -14,17 +14,19 @@ pub(crate) struct Stripper<'a> {
     pub(crate) is_json_output: bool,
 }
 
-impl<'a> Stripper<'a> {
-    // We need to handle this differently for the JSON output because some non exported items could
-    // be used in public API. And so, we need these items as well. `is_exported` only checks if they
-    // are in the public API, which is not enough.
-    #[inline]
-    fn is_item_reachable(&self, item_id: ItemId) -> bool {
-        if self.is_json_output {
-            self.access_levels.is_reachable(item_id.expect_def_id())
-        } else {
-            self.access_levels.is_exported(item_id.expect_def_id())
-        }
+// We need to handle this differently for the JSON output because some non exported items could
+// be used in public API. And so, we need these items as well. `is_exported` only checks if they
+// are in the public API, which is not enough.
+#[inline]
+fn is_item_reachable(
+    is_json_output: bool,
+    access_levels: &AccessLevels<DefId>,
+    item_id: ItemId,
+) -> bool {
+    if is_json_output {
+        access_levels.is_reachable(item_id.expect_def_id())
+    } else {
+        access_levels.is_exported(item_id.expect_def_id())
     }
 }
 
@@ -61,7 +63,9 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
             | clean::MacroItem(..)
             | clean::ForeignTypeItem => {
                 let item_id = i.item_id;
-                if item_id.is_local() && !self.is_item_reachable(item_id) {
+                if item_id.is_local()
+                    && !is_item_reachable(self.is_json_output, self.access_levels, item_id)
+                {
                     debug!("Stripper: stripping {:?} {:?}", i.type_(), i.name);
                     return None;
                 }
@@ -133,6 +137,8 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
 pub(crate) struct ImplStripper<'a> {
     pub(crate) retained: &'a ItemIdSet,
     pub(crate) cache: &'a Cache,
+    pub(crate) is_json_output: bool,
+    pub(crate) document_private: bool,
 }
 
 impl<'a> DocFolder for ImplStripper<'a> {
@@ -140,8 +146,27 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
         if let clean::ImplItem(ref imp) = *i.kind {
             // Impl blocks can be skipped if they are: empty; not a trait impl; and have no
             // documentation.
-            if imp.trait_.is_none() && imp.items.is_empty() && i.doc_value().is_none() {
-                return None;
+            //
+            // There is one special case: if the impl block contains only private items.
+            if imp.trait_.is_none() {
+                // If the only items present are private ones and we're not rendering private items,
+                // we don't document it.
+                if !imp.items.is_empty()
+                    && !self.document_private
+                    && imp.items.iter().all(|i| {
+                        let item_id = i.item_id;
+                        item_id.is_local()
+                            && !is_item_reachable(
+                                self.is_json_output,
+                                &self.cache.access_levels,
+                                item_id,
+                            )
+                    })
+                {
+                    return None;
+                } else if imp.items.is_empty() && i.doc_value().is_none() {
+                    return None;
+                }
             }
             if let Some(did) = imp.for_.def_id(self.cache) {
                 if did.is_local() && !imp.for_.is_assoc_ty() && !self.retained.contains(&did.into())
index fd0b19034a259022f51f2f9db9f5bd10e4992c65..0d96840250332b5cb77c05c56334e2be8bdaa56a 100644 (file)
@@ -304,6 +304,12 @@ pub(crate) fn run(
         let mut finder = FindCalls { calls: &mut calls, tcx, map: tcx.hir(), cx, target_crates };
         tcx.hir().visit_all_item_likes_in_crate(&mut finder);
 
+        // The visitor might have found a type error, which we need to
+        // promote to a fatal error
+        if tcx.sess.diagnostic().has_errors_or_lint_errors().is_some() {
+            return Err(String::from("Compilation failed, aborting rustdoc"));
+        }
+
         // Sort call locations within a given file in document order
         for fn_calls in calls.values_mut() {
             for file_calls in fn_calls.values_mut() {
index 8b6b5014fdad3a750f7242a6bfdcad83619498d4..e3be3f64ecac101d14ceda759ba078ad0aaf3747 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 8b6b5014fdad3a750f7242a6bfdcad83619498d4
+Subproject commit e3be3f64ecac101d14ceda759ba078ad0aaf3747
index 761e94c7ebbc44d66df46c8dab17b9c3b1c9cffe..ecdecadd2efb560833a9dc7d0bb466b4b36c9bc1 100644 (file)
@@ -9,7 +9,7 @@
 use serde::{Deserialize, Serialize};
 
 /// rustdoc format-version.
-pub const FORMAT_VERSION: u32 = 16;
+pub const FORMAT_VERSION: u32 = 17;
 
 /// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information
 /// about the language items in the local crate, as well as info about external items to allow
@@ -115,6 +115,35 @@ pub enum Visibility {
     },
 }
 
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub struct DynTrait {
+    /// All the traits implemented. One of them is the vtable, and the rest must be auto traits.
+    pub traits: Vec<PolyTrait>,
+    /// The lifetime of the whole dyn object
+    /// ```text
+    /// dyn Debug + 'static
+    ///             ^^^^^^^
+    ///             |
+    ///             this part
+    /// ```
+    pub lifetime: Option<String>,
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
+/// A trait and potential HRTBs
+pub struct PolyTrait {
+    #[serde(rename = "trait")]
+    pub trait_: Type,
+    /// Used for Higher-Rank Trait Bounds (HRTBs)
+    /// ```text
+    /// dyn for<'a> Fn() -> &'a i32"
+    ///     ^^^^^^^
+    ///       |
+    ///       this part
+    /// ```
+    pub generic_params: Vec<GenericParamDef>,
+}
+
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum GenericArgs {
@@ -395,7 +424,7 @@ pub enum WherePredicate {
         type_: Type,
         bounds: Vec<GenericBound>,
         /// Used for Higher-Rank Trait Bounds (HRTBs)
-        /// ```plain
+        /// ```text
         /// where for<'a> &'a T: Iterator,"
         ///       ^^^^^^^
         ///       |
@@ -420,7 +449,7 @@ pub enum GenericBound {
         #[serde(rename = "trait")]
         trait_: Type,
         /// Used for Higher-Rank Trait Bounds (HRTBs)
-        /// ```plain
+        /// ```text
         /// where F: for<'a, 'b> Fn(&'a u8, &'b u8)
         ///          ^^^^^^^^^^^
         ///          |
@@ -458,6 +487,7 @@ pub enum Type {
         args: Option<Box<GenericArgs>>,
         param_names: Vec<GenericBound>,
     },
+    DynTrait(DynTrait),
     /// Parameterized types
     Generic(String),
     /// Fixed-size numeric types (plus int/usize/float), char, arrays, slices, and tuples
@@ -505,7 +535,7 @@ pub enum Type {
 pub struct FunctionPointer {
     pub decl: FnDecl,
     /// Used for Higher-Rank Trait Bounds (HRTBs)
-    /// ```plain
+    /// ```text
     /// for<'c> fn(val: &'c i32) -> i32
     /// ^^^^^^^
     ///       |
@@ -561,8 +591,11 @@ pub struct Import {
     /// May be different from the last segment of `source` when renaming imports:
     /// `use source as name;`
     pub name: String,
-    /// The ID of the item being imported.
-    pub id: Option<Id>, // FIXME is this actually ever None?
+    /// The ID of the item being imported. Will be `None` in case of re-exports of primitives:
+    /// ```rust
+    /// pub use i32 as my_i32;
+    /// ```
+    pub id: Option<Id>,
     /// Whether this import uses a glob: `use source::*;`
     pub glob: bool,
 }
index 0f9f61bd6d916a85d4bd7c5aa908574949e2aaa1..68dc186ea0c7658e38ff31eae9568acf52ac84d9 100644 (file)
@@ -56,7 +56,7 @@ pub unsafe fn sym_fn() {
 // CHECK-LABEL: sym_static:
 // CHECK: #APP
 // CHECK: auipc t0, %pcrel_hi(extern_static)
-// CHECK: lb t0, %pcrel_lo(.Lpcrel_hi0)(t0)
+// CHECK: lb t0, %pcrel_lo(.Lpcrel_hi{{[0-9]+}})(t0)
 // CHECK: #NO_APP
 #[no_mangle]
 pub unsafe fn sym_static() {
index 25cf5dad61403652be06567ab0e587cd480059a3..6df4ff7e58bb2839493bbc39a29656ca26190210 100644 (file)
@@ -34,9 +34,9 @@ enum EnumNoDrop<T1, T2> {
 }
 
 
-struct NonGenericNoDrop(i32);
+struct NonGenericNoDrop(#[allow(unused_tuple_struct_fields)] i32);
 
-struct NonGenericWithDrop(i32);
+struct NonGenericWithDrop(#[allow(unused_tuple_struct_fields)] i32);
 //~ MONO_ITEM fn std::ptr::drop_in_place::<NonGenericWithDrop> - shim(Some(NonGenericWithDrop)) @@ generic_drop_glue-cgu.0[Internal]
 
 impl Drop for NonGenericWithDrop {
index 8249e7cba946b7ac81f2b9c1fa5ba57414b7edfd..e286c800b7cae4c048253ee84d785a1235e78e25 100644 (file)
@@ -6,9 +6,9 @@
 #![feature(start)]
 
 //~ MONO_ITEM fn std::ptr::drop_in_place::<Root> - shim(Some(Root)) @@ transitive_drop_glue-cgu.0[Internal]
-struct Root(Intermediate);
+struct Root(#[allow(unused_tuple_struct_fields)] Intermediate);
 //~ MONO_ITEM fn std::ptr::drop_in_place::<Intermediate> - shim(Some(Intermediate)) @@ transitive_drop_glue-cgu.0[Internal]
-struct Intermediate(Leaf);
+struct Intermediate(#[allow(unused_tuple_struct_fields)] Leaf);
 //~ MONO_ITEM fn std::ptr::drop_in_place::<Leaf> - shim(Some(Leaf)) @@ transitive_drop_glue-cgu.0[Internal]
 struct Leaf;
 
@@ -17,9 +17,9 @@ impl Drop for Leaf {
     fn drop(&mut self) {}
 }
 
-struct RootGen<T>(IntermediateGen<T>);
-struct IntermediateGen<T>(LeafGen<T>);
-struct LeafGen<T>(T);
+struct RootGen<T>(#[allow(unused_tuple_struct_fields)] IntermediateGen<T>);
+struct IntermediateGen<T>(#[allow(unused_tuple_struct_fields)] LeafGen<T>);
+struct LeafGen<T>(#[allow(unused_tuple_struct_fields)] T);
 
 impl<T> Drop for LeafGen<T> {
     fn drop(&mut self) {}
index 81675377941bd6ba04f17b646ef414e5e8870d0c..111a7231209a15f41ed394937ac4d4e6fdf03a40 100644 (file)
@@ -40,7 +40,7 @@ fn foo(&self) {}
 }
 
 #[derive(Clone, Copy)]
-struct Wrapper<T: ?Sized>(*const T);
+struct Wrapper<T: ?Sized>(#[allow(unused_tuple_struct_fields)] *const T);
 
 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Wrapper<U>> for Wrapper<T> {}
 
diff --git a/src/test/codegen/layout-size-checks.rs b/src/test/codegen/layout-size-checks.rs
new file mode 100644 (file)
index 0000000..d067cc1
--- /dev/null
@@ -0,0 +1,31 @@
+// compile-flags: -O
+// only-x86_64
+// ignore-debug: the debug assertions get in the way
+
+#![crate_type = "lib"]
+
+use std::alloc::Layout;
+
+type RGB48 = [u16; 3];
+
+// CHECK-LABEL: @layout_array_rgb48
+#[no_mangle]
+pub fn layout_array_rgb48(n: usize) -> Layout {
+    // CHECK-NOT: llvm.umul.with.overflow.i64
+    // CHECK: icmp ugt i64 %n, 1537228672809129301
+    // CHECK-NOT: llvm.umul.with.overflow.i64
+    // CHECK: mul nuw nsw i64 %n, 6
+    // CHECK-NOT: llvm.umul.with.overflow.i64
+    Layout::array::<RGB48>(n).unwrap()
+}
+
+// CHECK-LABEL: @layout_array_i32
+#[no_mangle]
+pub fn layout_array_i32(n: usize) -> Layout {
+    // CHECK-NOT: llvm.umul.with.overflow.i64
+    // CHECK: icmp ugt i64 %n, 2305843009213693951
+    // CHECK-NOT: llvm.umul.with.overflow.i64
+    // CHECK: shl nuw nsw i64 %n, 2
+    // CHECK-NOT: llvm.umul.with.overflow.i64
+    Layout::array::<i32>(n).unwrap()
+}
index 5eefc0f98f1fe5888266eeea2141434e21a6d511..d6caeeee8966985e54e7f46d6fb350600068e581 100644 (file)
@@ -1,7 +1,9 @@
-// compile-flags: -O
+// revisions: O Os
+//[Os] compile-flags: -Copt-level=s
+//[O] compile-flags: -O
 #![crate_type = "lib"]
 
-// CHECK: @func2 = {{.*}}alias{{.*}}@func1
+// CHECK: @func{{2|1}} = {{.*}}alias{{.*}}@func{{1|2}}
 
 #[no_mangle]
 pub fn func1(c: char) -> bool {
diff --git a/src/test/debuginfo/no_mangle-info.rs b/src/test/debuginfo/no_mangle-info.rs
new file mode 100644 (file)
index 0000000..e22d368
--- /dev/null
@@ -0,0 +1,40 @@
+// compile-flags:-g
+// min-gdb-version: 10.1
+
+// === GDB TESTS ===================================================================================
+// gdb-command:run
+// gdb-command:p TEST
+// gdb-check:$1 = 3735928559
+// gdb-command:p no_mangle_info::namespace::OTHER_TEST
+// gdb-check:$2 = 42
+
+// === LLDB TESTS ==================================================================================
+// lldb-command:run
+// lldb-command:p TEST
+// lldb-check: (unsigned long) $0 = 3735928559
+// lldb-command:p OTHER_TEST
+// lldb-check: (unsigned long) $1 = 42
+
+// === CDB TESTS ==================================================================================
+// cdb-command: g
+// Note: LLDB and GDB allow referring to items that are in the same namespace of the symbol
+// we currently have a breakpoint on in an unqualified way. CDB does not, and thus we need to
+// refer to it in a fully qualified way.
+// cdb-command: dx a!no_mangle_info::TEST
+// cdb-check: a!no_mangle_info::TEST : 0xdeadbeef [Type: unsigned __int64]
+// cdb-command: dx a!no_mangle_info::namespace::OTHER_TEST
+// cdb-check: a!no_mangle_info::namespace::OTHER_TEST : 0x2a [Type: unsigned __int64]
+
+#[no_mangle]
+pub static TEST: u64 = 0xdeadbeef;
+
+// FIXME(rylev, wesleywiser): uncommenting this item breaks the test, and we're not sure why
+// pub static OTHER_TEST: u64 = 43;
+pub mod namespace {
+    pub static OTHER_TEST: u64 = 42;
+}
+
+pub fn main() {
+    println!("TEST: {}", TEST);
+    println!("OTHER TEST: {}", namespace::OTHER_TEST); // #break
+}
index 69883058335f0566486a9ced7cdd10d412b1ee46..1abbff32c6f349ece60c2d60622a4bf3c6bc85e6 100644 (file)
@@ -116,9 +116,9 @@ pub fn method_body_inlined() {
 // Change Method Privacy -------------------------------------------------------
 #[cfg(any(cfail1,cfail4))]
 impl Foo {
-    //----------------------------------------------------
     //--------------------------
-    //------------------------------------------------------------------------------
+    //--------------------------
+    //--------------------------------------------------------------
     //--------------------------
     pub fn method_privacy() { }
 }
@@ -129,9 +129,9 @@ pub fn method_privacy() { }
 #[rustc_clean(cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 impl Foo {
-    #[rustc_clean(cfg="cfail2", except="associated_item")]
+    #[rustc_clean(cfg="cfail2")]
     #[rustc_clean(cfg="cfail3")]
-    #[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,associated_item")]
+    #[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")]
     #[rustc_clean(cfg="cfail6")]
     fn     method_privacy() { }
 }
index 9b79fd8a0a105fe71f85a13f46e6f7b3ef479cd5..1988f3f35417cbc94be1426148328e0bdd54cf0e 100644 (file)
@@ -277,22 +277,22 @@ trait TraitChangeMethodParametersOrder {
 // Add default implementation to method
 #[cfg(any(cfail1,cfail4))]
 trait TraitAddMethodAutoImplementation {
-    // -----------------------------------------------------------------------------
+    // -------------------------------------------------------------
     // -------------------------
-    // -----------------------------------------------------------------------------
+    // -------------------------------------------------------------
     // -------------------------
     fn method()  ;
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
+#[rustc_clean(except="hir_owner_nodes", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddMethodAutoImplementation {
-    #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail2")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
     #[rustc_clean(cfg="cfail3")]
-    #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail5")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
     #[rustc_clean(cfg="cfail6")]
     fn method() {}
 }
@@ -795,20 +795,24 @@ trait TraitAddLifetimeBoundToAssociatedType<'a> {
 // Add default to associated type
 #[cfg(any(cfail1,cfail4))]
 trait TraitAddDefaultToAssociatedType {
-    type Associated;
+    //--------------------------------------------------------------
+    //--------------------------
+    //--------------------------------------------------------------
+    //--------------------------
+    type Associated                 ;
 
     fn method();
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
+#[rustc_clean(except="hir_owner_nodes", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddDefaultToAssociatedType {
-    #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail2")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
     #[rustc_clean(cfg="cfail3")]
-    #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail5")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
     #[rustc_clean(cfg="cfail6")]
     type Associated = ReferenceType0;
 
@@ -839,20 +843,28 @@ trait TraitAddAssociatedConstant {
 // Add initializer to associated constant
 #[cfg(any(cfail1,cfail4))]
 trait TraitAddInitializerToAssociatedConstant {
-    const Value: u32;
+    //--------------------------------------------------------------
+    //--------------------------
+    //--------------------------------------------------------------
+    //--------------------------
+    const Value: u32    ;
 
+    //--------------------------
+    //--------------------------
+    //--------------------------
+    //--------------------------
     fn method();
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
+#[rustc_clean(except="hir_owner_nodes", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddInitializerToAssociatedConstant {
-    #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail2")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
     #[rustc_clean(cfg="cfail3")]
-    #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail5")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
     #[rustc_clean(cfg="cfail6")]
     const Value: u32 = 1;
 
index cc63aa4f5566399f6aa575c2b01769332404a943..f555f555f9236c7c214c78324d5ce8a345ed7094 100644 (file)
@@ -320,7 +320,11 @@ fn method_name() { }
 
 #[cfg(any(cfail1,cfail4))]
 pub trait ChangeHasValueTrait {
-    fn method_name();
+    //--------------------------------------------------------------
+    //--------------------------
+    //--------------------------------------------------------------
+    //--------------------------
+    fn method_name()   ;
 }
 
 #[cfg(any(cfail1,cfail4))]
@@ -329,14 +333,14 @@ fn method_name() { }
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
+#[rustc_clean(except="hir_owner_nodes", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 pub trait ChangeHasValueTrait {
-    #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail2")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
     #[rustc_clean(cfg="cfail3")]
-    #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail5")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
     #[rustc_clean(cfg="cfail6")]
     fn method_name() { }
 }
@@ -358,22 +362,22 @@ pub trait AddDefaultTrait {
 
 #[cfg(any(cfail1,cfail4))]
 impl AddDefaultTrait for Foo {
-    // ----------------------------------------------------
+    // -------------------------------------------------------------
     // -------------------------
-    // ----------------------------------------------------
+    // -------------------------------------------------------------
     // -------------------------
     fn         method_name() { }
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
+#[rustc_clean(cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 impl AddDefaultTrait for Foo {
-    #[rustc_clean(except="associated_item", cfg="cfail2")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
     #[rustc_clean(cfg="cfail3")]
-    #[rustc_clean(except="associated_item", cfg="cfail5")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
     #[rustc_clean(cfg="cfail6")]
     default fn method_name() { }
 }
index a0550466cf07b4c8b805d1fff53c9f3576ca52f0..0721d9f7019bccdadbd15164e6e36d949fa66c86 100644 (file)
@@ -14,6 +14,18 @@ presence of pointers in constants or other bit width dependent things. In that c
 
 to your test, causing separate files to be generated for 32bit and 64bit systems.
 
+## Unit testing
+
+If you are only testing the behavior of a particular mir-opt pass on some specific input (as is
+usually the case), you should add
+
+```
+// unit-test: PassName
+```
+
+to the top of the file. This makes sure that other passes don't run which means you'll get the input
+you expected and your test won't break when other code changes.
+
 ## Emit a diff of the mir for a specific optimization
 
 This is what you want most often when you want to see how an optimization changes the MIR.
index 3ff046325dc1f5d957a0a2ec597bafe51e480ad0..4435bf5b0f2c8b480531b4689913c1c96f828a9b 100644 (file)
@@ -1,3 +1,5 @@
+// unit-test: InstCombine
+
 // EMIT_MIR bool_compare.opt1.InstCombine.diff
 fn opt1(x: bool) -> u32 {
     if x != true { 0 } else { 1 }
diff --git a/src/test/mir-opt/combine_array_len.norm2.InstCombine.32bit.diff b/src/test/mir-opt/combine_array_len.norm2.InstCombine.32bit.diff
deleted file mode 100644 (file)
index c73150f..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-- // MIR for `norm2` before InstCombine
-+ // MIR for `norm2` after InstCombine
-  
-  fn norm2(_1: [f32; 2]) -> f32 {
-      debug x => _1;                       // in scope 0 at $DIR/combine_array_len.rs:+0:10: +0:11
-      let mut _0: f32;                     // return place in scope 0 at $DIR/combine_array_len.rs:+0:26: +0:29
-      let _2: f32;                         // in scope 0 at $DIR/combine_array_len.rs:+1:9: +1:10
-      let _3: usize;                       // in scope 0 at $DIR/combine_array_len.rs:+1:15: +1:16
-      let mut _4: usize;                   // in scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
-      let mut _5: bool;                    // in scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
-      let _7: usize;                       // in scope 0 at $DIR/combine_array_len.rs:+2:15: +2:16
-      let mut _8: usize;                   // in scope 0 at $DIR/combine_array_len.rs:+2:13: +2:17
-      let mut _9: bool;                    // in scope 0 at $DIR/combine_array_len.rs:+2:13: +2:17
-      let mut _10: f32;                    // in scope 0 at $DIR/combine_array_len.rs:+3:5: +3:8
-      let mut _11: f32;                    // in scope 0 at $DIR/combine_array_len.rs:+3:5: +3:6
-      let mut _12: f32;                    // in scope 0 at $DIR/combine_array_len.rs:+3:7: +3:8
-      let mut _13: f32;                    // in scope 0 at $DIR/combine_array_len.rs:+3:11: +3:14
-      let mut _14: f32;                    // in scope 0 at $DIR/combine_array_len.rs:+3:11: +3:12
-      let mut _15: f32;                    // in scope 0 at $DIR/combine_array_len.rs:+3:13: +3:14
-      scope 1 {
-          debug a => _2;                   // in scope 1 at $DIR/combine_array_len.rs:+1:9: +1:10
-          let _6: f32;                     // in scope 1 at $DIR/combine_array_len.rs:+2:9: +2:10
-          scope 2 {
-              debug b => _6;               // in scope 2 at $DIR/combine_array_len.rs:+2:9: +2:10
-          }
-      }
-  
-      bb0: {
-          StorageLive(_2);                 // scope 0 at $DIR/combine_array_len.rs:+1:9: +1:10
-          StorageLive(_3);                 // scope 0 at $DIR/combine_array_len.rs:+1:15: +1:16
-          _3 = const 0_usize;              // scope 0 at $DIR/combine_array_len.rs:+1:15: +1:16
--         _4 = Len(_1);                    // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
-+         _4 = const 2_usize;              // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
-          _5 = Lt(_3, _4);                 // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
-          assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
-      }
-  
-      bb1: {
-          _2 = _1[_3];                     // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
-          StorageDead(_3);                 // scope 0 at $DIR/combine_array_len.rs:+1:17: +1:18
-          StorageLive(_6);                 // scope 1 at $DIR/combine_array_len.rs:+2:9: +2:10
-          StorageLive(_7);                 // scope 1 at $DIR/combine_array_len.rs:+2:15: +2:16
-          _7 = const 1_usize;              // scope 1 at $DIR/combine_array_len.rs:+2:15: +2:16
--         _8 = Len(_1);                    // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17
-+         _8 = const 2_usize;              // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17
-          _9 = Lt(_7, _8);                 // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17
-          assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb2; // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17
-      }
-  
-      bb2: {
-          _6 = _1[_7];                     // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17
-          StorageDead(_7);                 // scope 1 at $DIR/combine_array_len.rs:+2:17: +2:18
-          StorageLive(_10);                // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:8
-          StorageLive(_11);                // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:6
-          _11 = _2;                        // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:6
-          StorageLive(_12);                // scope 2 at $DIR/combine_array_len.rs:+3:7: +3:8
-          _12 = _2;                        // scope 2 at $DIR/combine_array_len.rs:+3:7: +3:8
-          _10 = Mul(move _11, move _12);   // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:8
-          StorageDead(_12);                // scope 2 at $DIR/combine_array_len.rs:+3:7: +3:8
-          StorageDead(_11);                // scope 2 at $DIR/combine_array_len.rs:+3:7: +3:8
-          StorageLive(_13);                // scope 2 at $DIR/combine_array_len.rs:+3:11: +3:14
-          StorageLive(_14);                // scope 2 at $DIR/combine_array_len.rs:+3:11: +3:12
-          _14 = _6;                        // scope 2 at $DIR/combine_array_len.rs:+3:11: +3:12
-          StorageLive(_15);                // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
-          _15 = _6;                        // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
-          _13 = Mul(move _14, move _15);   // scope 2 at $DIR/combine_array_len.rs:+3:11: +3:14
-          StorageDead(_15);                // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
-          StorageDead(_14);                // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
-          _0 = Add(move _10, move _13);    // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:14
-          StorageDead(_13);                // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
-          StorageDead(_10);                // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
-          StorageDead(_6);                 // scope 1 at $DIR/combine_array_len.rs:+4:1: +4:2
-          StorageDead(_2);                 // scope 0 at $DIR/combine_array_len.rs:+4:1: +4:2
-          return;                          // scope 0 at $DIR/combine_array_len.rs:+4:2: +4:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/combine_array_len.norm2.InstCombine.64bit.diff b/src/test/mir-opt/combine_array_len.norm2.InstCombine.64bit.diff
deleted file mode 100644 (file)
index c73150f..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-- // MIR for `norm2` before InstCombine
-+ // MIR for `norm2` after InstCombine
-  
-  fn norm2(_1: [f32; 2]) -> f32 {
-      debug x => _1;                       // in scope 0 at $DIR/combine_array_len.rs:+0:10: +0:11
-      let mut _0: f32;                     // return place in scope 0 at $DIR/combine_array_len.rs:+0:26: +0:29
-      let _2: f32;                         // in scope 0 at $DIR/combine_array_len.rs:+1:9: +1:10
-      let _3: usize;                       // in scope 0 at $DIR/combine_array_len.rs:+1:15: +1:16
-      let mut _4: usize;                   // in scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
-      let mut _5: bool;                    // in scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
-      let _7: usize;                       // in scope 0 at $DIR/combine_array_len.rs:+2:15: +2:16
-      let mut _8: usize;                   // in scope 0 at $DIR/combine_array_len.rs:+2:13: +2:17
-      let mut _9: bool;                    // in scope 0 at $DIR/combine_array_len.rs:+2:13: +2:17
-      let mut _10: f32;                    // in scope 0 at $DIR/combine_array_len.rs:+3:5: +3:8
-      let mut _11: f32;                    // in scope 0 at $DIR/combine_array_len.rs:+3:5: +3:6
-      let mut _12: f32;                    // in scope 0 at $DIR/combine_array_len.rs:+3:7: +3:8
-      let mut _13: f32;                    // in scope 0 at $DIR/combine_array_len.rs:+3:11: +3:14
-      let mut _14: f32;                    // in scope 0 at $DIR/combine_array_len.rs:+3:11: +3:12
-      let mut _15: f32;                    // in scope 0 at $DIR/combine_array_len.rs:+3:13: +3:14
-      scope 1 {
-          debug a => _2;                   // in scope 1 at $DIR/combine_array_len.rs:+1:9: +1:10
-          let _6: f32;                     // in scope 1 at $DIR/combine_array_len.rs:+2:9: +2:10
-          scope 2 {
-              debug b => _6;               // in scope 2 at $DIR/combine_array_len.rs:+2:9: +2:10
-          }
-      }
-  
-      bb0: {
-          StorageLive(_2);                 // scope 0 at $DIR/combine_array_len.rs:+1:9: +1:10
-          StorageLive(_3);                 // scope 0 at $DIR/combine_array_len.rs:+1:15: +1:16
-          _3 = const 0_usize;              // scope 0 at $DIR/combine_array_len.rs:+1:15: +1:16
--         _4 = Len(_1);                    // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
-+         _4 = const 2_usize;              // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
-          _5 = Lt(_3, _4);                 // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
-          assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
-      }
-  
-      bb1: {
-          _2 = _1[_3];                     // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
-          StorageDead(_3);                 // scope 0 at $DIR/combine_array_len.rs:+1:17: +1:18
-          StorageLive(_6);                 // scope 1 at $DIR/combine_array_len.rs:+2:9: +2:10
-          StorageLive(_7);                 // scope 1 at $DIR/combine_array_len.rs:+2:15: +2:16
-          _7 = const 1_usize;              // scope 1 at $DIR/combine_array_len.rs:+2:15: +2:16
--         _8 = Len(_1);                    // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17
-+         _8 = const 2_usize;              // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17
-          _9 = Lt(_7, _8);                 // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17
-          assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb2; // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17
-      }
-  
-      bb2: {
-          _6 = _1[_7];                     // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17
-          StorageDead(_7);                 // scope 1 at $DIR/combine_array_len.rs:+2:17: +2:18
-          StorageLive(_10);                // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:8
-          StorageLive(_11);                // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:6
-          _11 = _2;                        // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:6
-          StorageLive(_12);                // scope 2 at $DIR/combine_array_len.rs:+3:7: +3:8
-          _12 = _2;                        // scope 2 at $DIR/combine_array_len.rs:+3:7: +3:8
-          _10 = Mul(move _11, move _12);   // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:8
-          StorageDead(_12);                // scope 2 at $DIR/combine_array_len.rs:+3:7: +3:8
-          StorageDead(_11);                // scope 2 at $DIR/combine_array_len.rs:+3:7: +3:8
-          StorageLive(_13);                // scope 2 at $DIR/combine_array_len.rs:+3:11: +3:14
-          StorageLive(_14);                // scope 2 at $DIR/combine_array_len.rs:+3:11: +3:12
-          _14 = _6;                        // scope 2 at $DIR/combine_array_len.rs:+3:11: +3:12
-          StorageLive(_15);                // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
-          _15 = _6;                        // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
-          _13 = Mul(move _14, move _15);   // scope 2 at $DIR/combine_array_len.rs:+3:11: +3:14
-          StorageDead(_15);                // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
-          StorageDead(_14);                // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
-          _0 = Add(move _10, move _13);    // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:14
-          StorageDead(_13);                // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
-          StorageDead(_10);                // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
-          StorageDead(_6);                 // scope 1 at $DIR/combine_array_len.rs:+4:1: +4:2
-          StorageDead(_2);                 // scope 0 at $DIR/combine_array_len.rs:+4:1: +4:2
-          return;                          // scope 0 at $DIR/combine_array_len.rs:+4:2: +4:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/combine_array_len.norm2.InstCombine.diff b/src/test/mir-opt/combine_array_len.norm2.InstCombine.diff
new file mode 100644 (file)
index 0000000..c73150f
--- /dev/null
@@ -0,0 +1,77 @@
+- // MIR for `norm2` before InstCombine
++ // MIR for `norm2` after InstCombine
+  
+  fn norm2(_1: [f32; 2]) -> f32 {
+      debug x => _1;                       // in scope 0 at $DIR/combine_array_len.rs:+0:10: +0:11
+      let mut _0: f32;                     // return place in scope 0 at $DIR/combine_array_len.rs:+0:26: +0:29
+      let _2: f32;                         // in scope 0 at $DIR/combine_array_len.rs:+1:9: +1:10
+      let _3: usize;                       // in scope 0 at $DIR/combine_array_len.rs:+1:15: +1:16
+      let mut _4: usize;                   // in scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
+      let mut _5: bool;                    // in scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
+      let _7: usize;                       // in scope 0 at $DIR/combine_array_len.rs:+2:15: +2:16
+      let mut _8: usize;                   // in scope 0 at $DIR/combine_array_len.rs:+2:13: +2:17
+      let mut _9: bool;                    // in scope 0 at $DIR/combine_array_len.rs:+2:13: +2:17
+      let mut _10: f32;                    // in scope 0 at $DIR/combine_array_len.rs:+3:5: +3:8
+      let mut _11: f32;                    // in scope 0 at $DIR/combine_array_len.rs:+3:5: +3:6
+      let mut _12: f32;                    // in scope 0 at $DIR/combine_array_len.rs:+3:7: +3:8
+      let mut _13: f32;                    // in scope 0 at $DIR/combine_array_len.rs:+3:11: +3:14
+      let mut _14: f32;                    // in scope 0 at $DIR/combine_array_len.rs:+3:11: +3:12
+      let mut _15: f32;                    // in scope 0 at $DIR/combine_array_len.rs:+3:13: +3:14
+      scope 1 {
+          debug a => _2;                   // in scope 1 at $DIR/combine_array_len.rs:+1:9: +1:10
+          let _6: f32;                     // in scope 1 at $DIR/combine_array_len.rs:+2:9: +2:10
+          scope 2 {
+              debug b => _6;               // in scope 2 at $DIR/combine_array_len.rs:+2:9: +2:10
+          }
+      }
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $DIR/combine_array_len.rs:+1:9: +1:10
+          StorageLive(_3);                 // scope 0 at $DIR/combine_array_len.rs:+1:15: +1:16
+          _3 = const 0_usize;              // scope 0 at $DIR/combine_array_len.rs:+1:15: +1:16
+-         _4 = Len(_1);                    // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
++         _4 = const 2_usize;              // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
+          _5 = Lt(_3, _4);                 // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
+          assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
+      }
+  
+      bb1: {
+          _2 = _1[_3];                     // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
+          StorageDead(_3);                 // scope 0 at $DIR/combine_array_len.rs:+1:17: +1:18
+          StorageLive(_6);                 // scope 1 at $DIR/combine_array_len.rs:+2:9: +2:10
+          StorageLive(_7);                 // scope 1 at $DIR/combine_array_len.rs:+2:15: +2:16
+          _7 = const 1_usize;              // scope 1 at $DIR/combine_array_len.rs:+2:15: +2:16
+-         _8 = Len(_1);                    // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17
++         _8 = const 2_usize;              // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17
+          _9 = Lt(_7, _8);                 // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17
+          assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb2; // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17
+      }
+  
+      bb2: {
+          _6 = _1[_7];                     // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17
+          StorageDead(_7);                 // scope 1 at $DIR/combine_array_len.rs:+2:17: +2:18
+          StorageLive(_10);                // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:8
+          StorageLive(_11);                // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:6
+          _11 = _2;                        // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:6
+          StorageLive(_12);                // scope 2 at $DIR/combine_array_len.rs:+3:7: +3:8
+          _12 = _2;                        // scope 2 at $DIR/combine_array_len.rs:+3:7: +3:8
+          _10 = Mul(move _11, move _12);   // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:8
+          StorageDead(_12);                // scope 2 at $DIR/combine_array_len.rs:+3:7: +3:8
+          StorageDead(_11);                // scope 2 at $DIR/combine_array_len.rs:+3:7: +3:8
+          StorageLive(_13);                // scope 2 at $DIR/combine_array_len.rs:+3:11: +3:14
+          StorageLive(_14);                // scope 2 at $DIR/combine_array_len.rs:+3:11: +3:12
+          _14 = _6;                        // scope 2 at $DIR/combine_array_len.rs:+3:11: +3:12
+          StorageLive(_15);                // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
+          _15 = _6;                        // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
+          _13 = Mul(move _14, move _15);   // scope 2 at $DIR/combine_array_len.rs:+3:11: +3:14
+          StorageDead(_15);                // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
+          StorageDead(_14);                // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
+          _0 = Add(move _10, move _13);    // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:14
+          StorageDead(_13);                // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
+          StorageDead(_10);                // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
+          StorageDead(_6);                 // scope 1 at $DIR/combine_array_len.rs:+4:1: +4:2
+          StorageDead(_2);                 // scope 0 at $DIR/combine_array_len.rs:+4:1: +4:2
+          return;                          // scope 0 at $DIR/combine_array_len.rs:+4:2: +4:2
+      }
+  }
+  
index 93490c14fd6458f830df7c4971df6857ce912d98..3ef3bd09afdef2ad8594db7252d50ae52823ed4d 100644 (file)
@@ -1,4 +1,4 @@
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
+// unit-test: InstCombine
 // EMIT_MIR combine_array_len.norm2.InstCombine.diff
 
 fn norm2(x: [f32; 2]) -> f32 {
index 939902e70e94b5e65e634c845a5ce6ff4f81f3b4..6f84f186b31152dc3b65e2c9324f6a3c925ff78c 100644 (file)
@@ -1,3 +1,5 @@
+// unit-test: ConstGoto
+
 pub enum Foo {
     A,
     B,
index 2b09ef7866126fde742be0d7b0cb334c1129baf6..81c356cb1db526b0373d8664983d63a44ae428ba 100644 (file)
@@ -17,7 +17,7 @@
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/const_goto_storage.rs:+1:9: +1:12
 -         StorageLive(_2);                 // scope 0 at $DIR/const_goto_storage.rs:+1:21: +1:23
--         nop;                             // scope 0 at $DIR/const_goto_storage.rs:+1:21: +1:23
+-         Deinit(_2);                      // scope 0 at $DIR/const_goto_storage.rs:+1:21: +1:23
 -         StorageLive(_3);                 // scope 0 at $DIR/const_goto_storage.rs:+2:15: +6:10
 -         StorageLive(_4);                 // scope 0 at $DIR/const_goto_storage.rs:+2:18: +2:76
 -         StorageLive(_5);                 // scope 0 at $DIR/const_goto_storage.rs:+2:21: +2:52
index 4ef68e7e1faf0e38fc9acb882272abc4a10cf149..459599c73eb9ccefabeef4d73f687fe2f97282ab 100644 (file)
@@ -1,3 +1,5 @@
+// unit-test: ConstGoto
+
 // EMIT_MIR const_goto_storage.match_nested_if.ConstGoto.diff
 fn match_nested_if() -> bool {
     let val = match () {
index f2d4bee1bf94dabedba57ff9908e9d0feda87579..73fdf14049896a8f6d7c522b78a3c92271e4fc7f 100644 (file)
@@ -12,8 +12,6 @@
       let mut _7: std::boxed::Box<i32>;    // in scope 0 at $DIR/boxes.rs:+1:14: +1:22
       let mut _8: *const i32;              // in scope 0 at $DIR/boxes.rs:+1:14: +1:22
       let mut _9: *const i32;              // in scope 0 at $DIR/boxes.rs:+1:14: +1:22
-      let mut _10: *const i32;             // in scope 0 at $DIR/boxes.rs:+1:14: +1:22
-      let mut _11: *const i32;             // in scope 0 at $DIR/boxes.rs:+1:14: +1:22
       scope 1 {
           debug x => _1;                   // in scope 1 at $DIR/boxes.rs:+1:9: +1:10
       }
index 342e222431b49e81bd0f35a5a3367b8ded820ea4..ee59402af386ba1d16ec8ffd93edfd1889acc608 100644 (file)
@@ -1,3 +1,5 @@
+// unit-test: Deaggregator
+
 struct Baz {
     x: usize,
     y: f32,
index 02b63a1f55d4e3f581d9f1b305697dd48940f77a..ea402dafdec7a8f23cebe29f036f1f05aea64d1c 100644 (file)
@@ -1,3 +1,5 @@
+// unit-test: Deaggregator
+
 enum Baz {
     Empty,
     Foo { x: usize },
index 489854ff0aa3d4864634c40a5bfa650170b247fa..955c317324aa8418059bfc7635dda5521e825df8 100644 (file)
@@ -1,3 +1,4 @@
+// unit-test: Deaggregator
 // Test that deaggregate fires in more than one basic block
 
 enum Foo {
index 9730b9aa8e5c0e13bffaa6bb5a12a49b99a6bafe..46305fe21d28c2c33d325974fb8f6cd1e7bb4b53 100644 (file)
@@ -1,3 +1,4 @@
+// unit-test: Deaggregator
 // Test that deaggregate fires more than once per block
 
 enum Foo {
index 01864ba24ac087908da8e34837322f83cdfa6964..53f977de5d6ad6b09b1a679d7d57a666cb712a06 100644 (file)
       let mut _2: &[u8];                   // in scope 0 at $DIR/deduplicate_blocks.rs:+1:11: +1:23
       let mut _3: &str;                    // in scope 0 at $DIR/deduplicate_blocks.rs:+1:11: +1:23
       let mut _4: usize;                   // in scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31
-      let mut _5: bool;                    // in scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31
-      let mut _6: usize;                   // in scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37
-      let mut _7: bool;                    // in scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37
-      scope 1 (inlined core::str::<impl str>::as_bytes) { // at $DIR/deduplicate_blocks.rs:3:11: 3:23
-          debug self => _3;                // in scope 1 at $SRC_DIR/core/src/str/mod.rs:LL:COL
-          let mut _8: &str;                // in scope 1 at $SRC_DIR/core/src/str/mod.rs:LL:COL
-          scope 2 {
-          }
-      }
+      let mut _5: usize;                   // in scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31
+      let mut _6: bool;                    // in scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31
+      let mut _7: usize;                   // in scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37
+      let mut _8: usize;                   // in scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37
+      let mut _9: bool;                    // in scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37
   
       bb0: {
           StorageLive(_2);                 // scope 0 at $DIR/deduplicate_blocks.rs:+1:11: +1:23
           StorageLive(_3);                 // scope 0 at $DIR/deduplicate_blocks.rs:+1:11: +1:23
-          _3 = _1;                         // scope 0 at $DIR/deduplicate_blocks.rs:+1:11: +1:23
-          StorageLive(_8);                 // scope 2 at $SRC_DIR/core/src/str/mod.rs:LL:COL
-          _8 = _3;                         // scope 2 at $SRC_DIR/core/src/str/mod.rs:LL:COL
--         _2 = transmute::<&str, &[u8]>(move _8) -> bb14; // scope 2 at $SRC_DIR/core/src/str/mod.rs:LL:COL
-+         _2 = transmute::<&str, &[u8]>(move _8) -> bb12; // scope 2 at $SRC_DIR/core/src/str/mod.rs:LL:COL
+          _3 = &(*_1);                     // scope 0 at $DIR/deduplicate_blocks.rs:+1:11: +1:23
+          _2 = core::str::<impl str>::as_bytes(move _3) -> bb1; // scope 0 at $DIR/deduplicate_blocks.rs:+1:11: +1:23
                                            // mir::Constant
-                                           // + span: $SRC_DIR/core/src/str/mod.rs:LL:COL
-                                           // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&str) -> &[u8] {transmute::<&str, &[u8]>}, val: Value(<ZST>) }
+                                           // + span: $DIR/deduplicate_blocks.rs:5:13: 5:21
+                                           // + literal: Const { ty: for<'r> fn(&'r str) -> &'r [u8] {core::str::<impl str>::as_bytes}, val: Value(<ZST>) }
       }
   
       bb1: {
-          switchInt((*_2)[0 of 4]) -> [47_u8: bb2, otherwise: bb5]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
+          StorageDead(_3);                 // scope 0 at $DIR/deduplicate_blocks.rs:+1:22: +1:23
+          _7 = Len((*_2));                 // scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37
+          _8 = const 4_usize;              // scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37
+          _9 = Ge(move _7, move _8);       // scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37
+          switchInt(move _9) -> [false: bb6, otherwise: bb2]; // scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37
       }
   
       bb2: {
-          switchInt((*_2)[1 of 4]) -> [47_u8: bb3, otherwise: bb5]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
+          switchInt((*_2)[0 of 4]) -> [47_u8: bb3, otherwise: bb6]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
       }
   
       bb3: {
-          switchInt((*_2)[2 of 4]) -> [47_u8: bb4, otherwise: bb5]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
+          switchInt((*_2)[1 of 4]) -> [47_u8: bb4, otherwise: bb6]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
       }
   
       bb4: {
--         switchInt((*_2)[3 of 4]) -> [47_u8: bb10, otherwise: bb5]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
-+         switchInt((*_2)[3 of 4]) -> [47_u8: bb9, otherwise: bb5]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
+          switchInt((*_2)[2 of 4]) -> [47_u8: bb5, otherwise: bb6]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
       }
   
       bb5: {
-          _4 = Len((*_2));                 // scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31
-          _5 = Ge(move _4, const 3_usize); // scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31
-          switchInt(move _5) -> [false: bb9, otherwise: bb6]; // scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31
+-         switchInt((*_2)[3 of 4]) -> [47_u8: bb11, otherwise: bb6]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
++         switchInt((*_2)[3 of 4]) -> [47_u8: bb10, otherwise: bb6]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
       }
   
       bb6: {
-          switchInt((*_2)[0 of 3]) -> [47_u8: bb7, otherwise: bb9]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
+          _4 = Len((*_2));                 // scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31
+          _5 = const 3_usize;              // scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31
+          _6 = Ge(move _4, move _5);       // scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31
+          switchInt(move _6) -> [false: bb10, otherwise: bb7]; // scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31
       }
   
       bb7: {
-          switchInt((*_2)[1 of 3]) -> [47_u8: bb8, otherwise: bb9]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
+          switchInt((*_2)[0 of 3]) -> [47_u8: bb8, otherwise: bb10]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
       }
   
       bb8: {
--         switchInt((*_2)[2 of 3]) -> [47_u8: bb11, 33_u8: bb12, otherwise: bb9]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
-+         switchInt((*_2)[2 of 3]) -> [47_u8: bb10, 33_u8: bb10, otherwise: bb9]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
+          switchInt((*_2)[1 of 3]) -> [47_u8: bb9, otherwise: bb10]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
       }
   
       bb9: {
+-         switchInt((*_2)[2 of 3]) -> [47_u8: bb12, 33_u8: bb13, otherwise: bb10]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
++         switchInt((*_2)[2 of 3]) -> [47_u8: bb11, 33_u8: bb11, otherwise: bb10]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
+      }
+  
+      bb10: {
 -         _0 = const false;                // scope 0 at $DIR/deduplicate_blocks.rs:+5:14: +5:19
--         goto -> bb13;                    // scope 0 at $DIR/deduplicate_blocks.rs:+5:14: +5:19
+-         goto -> bb14;                    // scope 0 at $DIR/deduplicate_blocks.rs:+5:14: +5:19
 -     }
 - 
--     bb10: {
+-     bb11: {
           _0 = const false;                // scope 0 at $DIR/deduplicate_blocks.rs:+2:41: +2:46
--         goto -> bb13;                    // scope 0 at $DIR/deduplicate_blocks.rs:+2:41: +2:46
-+         goto -> bb11;                    // scope 0 at $DIR/deduplicate_blocks.rs:+2:41: +2:46
+-         goto -> bb14;                    // scope 0 at $DIR/deduplicate_blocks.rs:+2:41: +2:46
++         goto -> bb12;                    // scope 0 at $DIR/deduplicate_blocks.rs:+2:41: +2:46
       }
   
--     bb11: {
+-     bb12: {
 -         _0 = const true;                 // scope 0 at $DIR/deduplicate_blocks.rs:+3:35: +3:39
--         goto -> bb13;                    // scope 0 at $DIR/deduplicate_blocks.rs:+3:35: +3:39
+-         goto -> bb14;                    // scope 0 at $DIR/deduplicate_blocks.rs:+3:35: +3:39
 -     }
 - 
--     bb12: {
-+     bb10: {
-          _0 = const true;                 // scope 0 at $DIR/deduplicate_blocks.rs:+4:35: +4:39
--         goto -> bb13;                    // scope 0 at $DIR/deduplicate_blocks.rs:+4:35: +4:39
-+         goto -> bb11;                    // scope 0 at $DIR/deduplicate_blocks.rs:+4:35: +4:39
-      }
-  
 -     bb13: {
 +     bb11: {
-          StorageDead(_2);                 // scope 0 at $DIR/deduplicate_blocks.rs:+7:1: +7:2
-          return;                          // scope 0 at $DIR/deduplicate_blocks.rs:+7:2: +7:2
+          _0 = const true;                 // scope 0 at $DIR/deduplicate_blocks.rs:+4:35: +4:39
+-         goto -> bb14;                    // scope 0 at $DIR/deduplicate_blocks.rs:+4:35: +4:39
++         goto -> bb12;                    // scope 0 at $DIR/deduplicate_blocks.rs:+4:35: +4:39
       }
   
 -     bb14: {
 +     bb12: {
-          StorageDead(_8);                 // scope 2 at $SRC_DIR/core/src/str/mod.rs:LL:COL
-          StorageDead(_3);                 // scope 0 at $DIR/deduplicate_blocks.rs:+1:22: +1:23
-          _6 = Len((*_2));                 // scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37
-          _7 = Ge(move _6, const 4_usize); // scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37
-          switchInt(move _7) -> [false: bb5, otherwise: bb1]; // scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37
+          StorageDead(_2);                 // scope 0 at $DIR/deduplicate_blocks.rs:+7:1: +7:2
+          return;                          // scope 0 at $DIR/deduplicate_blocks.rs:+7:2: +7:2
       }
   }
   
index f8f7361dc0d0e56415cc3d7cc761a292d92e336a..2b9eed99ecdbf1c7d4c9f8ed374c576d6fddd466 100644 (file)
@@ -1,3 +1,5 @@
+// unit-test: DeduplicateBlocks
+
 // EMIT_MIR deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff
 pub const fn is_line_doc_comment_2(s: &str) -> bool {
     match s.as_bytes() {
index 548b94d17f566411e82d1099ef11f5cbd91ec593..abd6193fed95739568fc7437f95ec4b0201cb335 100644 (file)
           StorageLive(_2);                 // scope 0 at $DIR/derefer_complex_case.rs:+1:17: +1:26
           _14 = const main::promoted[0];   // scope 0 at $DIR/derefer_complex_case.rs:+1:17: +1:26
                                            // mir::Constant
-                                           // + span: $DIR/derefer_complex_case.rs:5:17: 5:26
+                                           // + span: $DIR/derefer_complex_case.rs:6:17: 6:26
                                            // + literal: Const { ty: &[i32; 2], val: Unevaluated(main, [], Some(promoted[0])) }
           _2 = &(*_14);                    // scope 0 at $DIR/derefer_complex_case.rs:+1:17: +1:26
           _1 = <&[i32; 2] as IntoIterator>::into_iter(move _2) -> bb1; // scope 0 at $DIR/derefer_complex_case.rs:+1:17: +1:26
                                            // mir::Constant
-                                           // + span: $DIR/derefer_complex_case.rs:5:17: 5:26
+                                           // + span: $DIR/derefer_complex_case.rs:6:17: 6:26
                                            // + literal: Const { ty: fn(&[i32; 2]) -> <&[i32; 2] as IntoIterator>::IntoIter {<&[i32; 2] as IntoIterator>::into_iter}, val: Value(<ZST>) }
       }
   
@@ -55,7 +55,7 @@
           _8 = &mut (*_9);                 // scope 1 at $DIR/derefer_complex_case.rs:+1:17: +1:26
           _7 = <std::slice::Iter<i32> as Iterator>::next(move _8) -> bb3; // scope 1 at $DIR/derefer_complex_case.rs:+1:17: +1:26
                                            // mir::Constant
-                                           // + span: $DIR/derefer_complex_case.rs:5:17: 5:26
+                                           // + span: $DIR/derefer_complex_case.rs:6:17: 6:26
                                            // + literal: Const { ty: for<'r> fn(&'r mut std::slice::Iter<i32>) -> Option<<std::slice::Iter<i32> as Iterator>::Item> {<std::slice::Iter<i32> as Iterator>::next}, val: Value(<ZST>) }
       }
   
@@ -76,7 +76,7 @@
           _13 = _12;                       // scope 2 at $DIR/derefer_complex_case.rs:+1:34: +1:37
           _6 = std::mem::drop::<i32>(move _13) -> bb7; // scope 2 at $DIR/derefer_complex_case.rs:+1:29: +1:38
                                            // mir::Constant
-                                           // + span: $DIR/derefer_complex_case.rs:5:29: 5:33
+                                           // + span: $DIR/derefer_complex_case.rs:6:29: 6:33
                                            // + literal: Const { ty: fn(i32) {std::mem::drop::<i32>}, val: Value(<ZST>) }
       }
   
           StorageDead(_6);                 // scope 1 at $DIR/derefer_complex_case.rs:+1:39: +1:40
           _5 = const ();                   // scope 1 at $DIR/derefer_complex_case.rs:+1:5: +1:40
           goto -> bb2;                     // scope 1 at $DIR/derefer_complex_case.rs:+1:5: +1:40
-+     }
-+ 
-+     bb8 (cleanup): {
-+         resume;                          // scope 0 at $DIR/derefer_complex_case.rs:+0:1: +2:2
       }
   }
   
index 48bec39074c899f0367bb221c9edc33aba52c86d..dc48cee950bc98021145ca525841a075cd791db6 100644 (file)
@@ -1,3 +1,4 @@
+// unit-test: Derefer
 // EMIT_MIR derefer_complex_case.main.Derefer.diff
 // ignore-wasm32
 
index ce6ffaa56413cadb216147f368ba6d7d0bfedac2..3540df308367093f2e0e8bafc00be66f70abdf0f 100644 (file)
@@ -17,7 +17,7 @@
           _3 = AlignOf(std::boxed::Box<u32>); // scope 1 at $DIR/derefer_inline_test.rs:+1:5: +1:12
           _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 1 at $DIR/derefer_inline_test.rs:+1:5: +1:12
                                            // mir::Constant
-                                           // + span: $DIR/derefer_inline_test.rs:10:5: 10:12
+                                           // + span: $DIR/derefer_inline_test.rs:11:5: 11:12
                                            // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) }
       }
   
@@ -26,7 +26,7 @@
           _5 = ShallowInitBox(move _4, std::boxed::Box<u32>); // scope 0 at $DIR/derefer_inline_test.rs:+1:5: +1:12
           (*_5) = f() -> [return: bb2, unwind: bb6]; // scope 0 at $DIR/derefer_inline_test.rs:+1:9: +1:12
                                            // mir::Constant
-                                           // + span: $DIR/derefer_inline_test.rs:10:9: 10:10
+                                           // + span: $DIR/derefer_inline_test.rs:11:9: 11:10
                                            // + literal: Const { ty: fn() -> Box<u32> {f}, val: Value(<ZST>) }
       }
   
index 191a8cbbef40a521955d12c538cbcf143fc26aa7..cc06a7dd8c40a12101b771d40bd9de199ea1388c 100644 (file)
@@ -1,3 +1,4 @@
+// unit-test: Derefer
 // EMIT_MIR derefer_inline_test.main.Derefer.diff
 // ignore-wasm32 compiled with panic=abort by default
 
index 51df13bdfd01d42453044eb2c79ca2df5be6b0b8..ed336208325fe5ae39bbab1b920399e4b9ef8f8f 100644 (file)
@@ -32,7 +32,7 @@
           StorageLive(_1);                 // scope 0 at $DIR/derefer_terminator_test.rs:+1:9: +1:10
           _1 = foo() -> bb1;               // scope 0 at $DIR/derefer_terminator_test.rs:+1:13: +1:18
                                            // mir::Constant
-                                           // + span: $DIR/derefer_terminator_test.rs:5:13: 5:16
+                                           // + span: $DIR/derefer_terminator_test.rs:6:13: 6:16
                                            // + literal: Const { ty: fn() -> bool {foo}, val: Value(<ZST>) }
       }
   
@@ -40,7 +40,7 @@
           StorageLive(_2);                 // scope 1 at $DIR/derefer_terminator_test.rs:+2:9: +2:10
           _2 = foo() -> bb2;               // scope 1 at $DIR/derefer_terminator_test.rs:+2:13: +2:18
                                            // mir::Constant
-                                           // + span: $DIR/derefer_terminator_test.rs:6:13: 6:16
+                                           // + span: $DIR/derefer_terminator_test.rs:7:13: 7:16
                                            // + literal: Const { ty: fn() -> bool {foo}, val: Value(<ZST>) }
       }
   
           StorageDead(_2);                 // scope 1 at $DIR/derefer_terminator_test.rs:+8:1: +8:2
           StorageDead(_1);                 // scope 0 at $DIR/derefer_terminator_test.rs:+8:1: +8:2
           return;                          // scope 0 at $DIR/derefer_terminator_test.rs:+8:2: +8:2
-+     }
-+ 
-+     bb6 (cleanup): {
-+         resume;                          // scope 0 at $DIR/derefer_terminator_test.rs:+0:1: +8:2
       }
   }
   
index 787b14ae735d5c5fa89dff6fed1f22d982204046..d6750c29dd98c98fe61cf3241e5cf4bfd67435c0 100644 (file)
@@ -1,3 +1,4 @@
+// unit-test: Derefer
 // EMIT_MIR derefer_terminator_test.main.Derefer.diff
 // ignore-wasm32
 
index cf8211c1ed0894b1556da734977c46efaf89a7a3..6c2047e216c05ff11557fd0126cf42a2db260e95 100644 (file)
           StorageDead(_2);                 // scope 1 at $DIR/derefer_test.rs:+5:1: +5:2
           StorageDead(_1);                 // scope 0 at $DIR/derefer_test.rs:+5:1: +5:2
           return;                          // scope 0 at $DIR/derefer_test.rs:+5:2: +5:2
-+     }
-+ 
-+     bb1 (cleanup): {
-+         resume;                          // scope 0 at $DIR/derefer_test.rs:+0:1: +5:2
       }
   }
   
index 2ebc0d343bd74123c3db5362f3ebeccd723c13e5..fad0fe8eb6fc315bd57a8c577ad59105f30b13bd 100644 (file)
@@ -1,3 +1,4 @@
+// unit-test: Derefer
 // EMIT_MIR derefer_test.main.Derefer.diff
 fn main() {
     let mut a = (42,43);
index 91c9d5512243c87e6c0cd00d7497e95b0fa27a82..e2dceecfd7c923ed8cd49a8be9cb1c11108f523d 100644 (file)
           StorageDead(_2);                 // scope 1 at $DIR/derefer_test_multiple.rs:+7:1: +7:2
           StorageDead(_1);                 // scope 0 at $DIR/derefer_test_multiple.rs:+7:1: +7:2
           return;                          // scope 0 at $DIR/derefer_test_multiple.rs:+7:2: +7:2
-+     }
-+ 
-+     bb1 (cleanup): {
-+         resume;                          // scope 0 at $DIR/derefer_test_multiple.rs:+0:1: +7:2
       }
   }
   
index a27363447fee590ebb8c287ec50cd6ce27d5aa3f..0b3888b07ab45735f77899475ddaf60baef4dff1 100644 (file)
@@ -1,3 +1,4 @@
+// unit-test: Derefer
 // EMIT_MIR derefer_test_multiple.main.Derefer.diff
 fn main () {
     let mut a = (42, 43);
index 994cd194a45e259934639a94135a8c88b9af9100..717d10c6d76276bcd506881dc409a6aae251fab9 100644 (file)
@@ -1,3 +1,5 @@
+// unit-test InstCombine
+
 // EMIT_MIR equal_true.opt.InstCombine.diff
 
 fn opt(x: bool) -> i32 {
index 49c91e956e72d31bbff12f51b17f78ae7eeeb74c..8eae04c4dd4a696386f53dddc2c4a2266594f758 100644 (file)
           StorageDead(_4);                 // scope 1 at $DIR/dyn-trait.rs:+2:24: +2:25
           StorageDead(_2);                 // scope 0 at $DIR/dyn-trait.rs:+3:1: +3:2
           return;                          // scope 0 at $DIR/dyn-trait.rs:+3:2: +3:2
-+     }
-+ 
-+     bb3 (cleanup): {
-+         resume;                          // scope 0 at $DIR/dyn-trait.rs:+0:1: +3:2
       }
   }
   
index 805354d2804a63eaa8d3ffc83a894014f46a2c2b..e7c5972f4291ffa380c93b93b2396f28c82283b4 100644 (file)
 +         StorageDead(_4);                 // scope 1 at $DIR/dyn-trait.rs:+0:21: +0:22
           StorageDead(_2);                 // scope 0 at $DIR/dyn-trait.rs:+1:15: +1:16
           return;                          // scope 0 at $DIR/dyn-trait.rs:+2:2: +2:2
-+     }
-+ 
-+     bb2 (cleanup): {
-+         resume;                          // scope 0 at $DIR/dyn-trait.rs:+0:1: +2:2
       }
   }
   
index 77b5df943a35366c27686a537e159601a45ff852..6302252581899a41f6d1ab28104954d238921926 100644 (file)
@@ -41,8 +41,4 @@ fn bar() -> bool {
         StorageDead(_1);                 // scope 0 at $DIR/inline-any-operand.rs:+3:1: +3:2
         return;                          // scope 0 at $DIR/inline-any-operand.rs:+3:2: +3:2
     }
-
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/inline-any-operand.rs:+0:1: +3:2
-    }
 }
index d746e1a093a9272d0b7f65bf622888060ff8d7b9..1fadd2464798d9114ccaf23b36b8e0cd6f5c8565 100644 (file)
@@ -46,8 +46,4 @@ fn foo(_1: T, _2: i32) -> i32 {
         StorageDead(_3);                 // scope 0 at $DIR/inline-closure.rs:+3:1: +3:2
         return;                          // scope 0 at $DIR/inline-closure.rs:+3:2: +3:2
     }
-
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/inline-closure.rs:+0:1: +3:2
-    }
 }
index 84b3fb92cd535cd001caf7aa76a999f3a6e06d3a..4069e9f89c8d8fc92f082d61b5c493c3b86fcc17 100644 (file)
@@ -53,8 +53,4 @@ fn foo(_1: T, _2: &i32) -> i32 {
         StorageDead(_3);                 // scope 0 at $DIR/inline-closure-borrows-arg.rs:+6:1: +6:2
         return;                          // scope 0 at $DIR/inline-closure-borrows-arg.rs:+6:2: +6:2
     }
-
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/inline-closure-borrows-arg.rs:+0:1: +6:2
-    }
 }
index 75693dc384b13581a9cf0cb68827453476e1bc65..d60b064600f566dd6a685ca3b8c97e3955bbd91a 100644 (file)
@@ -66,8 +66,4 @@ fn foo(_1: T, _2: i32) -> (i32, T) {
         StorageDead(_3);                 // scope 0 at $DIR/inline-closure-captures.rs:+3:1: +3:2
         return;                          // scope 0 at $DIR/inline-closure-captures.rs:+3:2: +3:2
     }
-
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/inline-closure-captures.rs:+0:1: +3:2
-    }
 }
index 556d587a47276197375048d17545fa8334a4b076..cf800ba112945aa1b5546d89b5986f1dd10d96da 100644 (file)
           StorageDead(_1);                 // scope 0 at $DIR/inline-compatibility.rs:+1:18: +1:19
           _0 = const ();                   // scope 0 at $DIR/inline-compatibility.rs:+0:37: +2:2
           return;                          // scope 0 at $DIR/inline-compatibility.rs:+2:2: +2:2
-+     }
-+ 
-+     bb1 (cleanup): {
-+         resume;                          // scope 0 at $DIR/inline-compatibility.rs:+0:1: +2:2
       }
   }
   
index b1ee4307358c4f9596c2faedbe135a2eb64b696c..a45f959026d1c88def26fc541ac2c52484d4787a 100644 (file)
           StorageDead(_1);                 // scope 0 at $DIR/inline-compatibility.rs:+1:21: +1:22
           _0 = const ();                   // scope 0 at $DIR/inline-compatibility.rs:+0:40: +2:2
           return;                          // scope 0 at $DIR/inline-compatibility.rs:+2:2: +2:2
-+     }
-+ 
-+     bb1 (cleanup): {
-+         resume;                          // scope 0 at $DIR/inline-compatibility.rs:+0:1: +2:2
       }
   }
   
index a6d65928da70831694f0248fd4502c948726621a..b1c476362de89c04a7403954ad96135cf76f1659 100644 (file)
           StorageDead(_1);                 // scope 0 at $DIR/inline-cycle.rs:+1:24: +1:25
           _0 = const ();                   // scope 0 at $DIR/inline-cycle.rs:+0:10: +2:2
           return;                          // scope 0 at $DIR/inline-cycle.rs:+2:2: +2:2
-+     }
-+ 
-+     bb2 (cleanup): {
-+         resume;                          // scope 0 at $DIR/inline-cycle.rs:+0:1: +2:2
       }
   }
   
index 0fea4121f8daeb95e787ab0eab45f152dfdba940..dc890a365113a5115074936e75f34b015f16cdd0 100644 (file)
           StorageDead(_1);                 // scope 0 at $DIR/inline-cycle.rs:+1:12: +1:13
           _0 = const ();                   // scope 0 at $DIR/inline-cycle.rs:+0:10: +2:2
           return;                          // scope 0 at $DIR/inline-cycle.rs:+2:2: +2:2
-+     }
-+ 
-+     bb2 (cleanup): {
-+         resume;                          // scope 0 at $DIR/inline-cycle.rs:+0:1: +2:2
       }
   }
   
index d5709f1b47a40465ecd0ecec789003967ab19a7c..082f57e59a0135253728d56c4e41eba8c106eb74 100644 (file)
           StorageDead(_1);                 // scope 0 at $DIR/inline-cycle-generic.rs:+1:24: +1:25
           _0 = const ();                   // scope 0 at $DIR/inline-cycle-generic.rs:+0:11: +2:2
           return;                          // scope 0 at $DIR/inline-cycle-generic.rs:+2:2: +2:2
-+     }
-+ 
-+     bb2 (cleanup): {
-+         resume;                          // scope 0 at $DIR/inline-cycle-generic.rs:+0:1: +2:2
       }
   }
   
index 7ebc2ff5c453154efdc68b70ffb21163ff87e84a..6b24b3e16979049d4f40f346d83221ef803366d9 100644 (file)
 + 
 +     bb1: {
 +         goto -> bb1;                     // scope 1 at $DIR/inline-diverging.rs:+32:5: +32:12
-+     }
-+ 
-+     bb2 (cleanup): {
-+         resume;                          // scope 0 at $DIR/inline-diverging.rs:+0:1: +2:2
       }
   }
   
index acdd0f87901d5a19fd67154b98fe600b8a7864f3..a25f1454fac612bb835a9896363c4113e9e76b16 100644 (file)
 +                                          // mir::Constant
 +                                          // + span: $SRC_DIR/std/src/panic.rs:LL:COL
 +                                          // + literal: Const { ty: &str, val: Value(Slice(..)) }
-+     }
-+ 
-+     bb3 (cleanup): {
-+         resume;                          // scope 0 at $DIR/inline-diverging.rs:+0:1: +6:2
       }
   }
   
index 8fda8673c9535f298fa6b401fa3c56277cbf0ef3..8759f3d02fc30742f6c9de0b16e297bc08aa9593 100644 (file)
 + 
 +     bb1: {
 +         goto -> bb1;                     // scope 5 at $DIR/inline-diverging.rs:+18:5: +18:12
-+     }
-+ 
-+     bb2 (cleanup): {
-+         resume;                          // scope 0 at $DIR/inline-diverging.rs:+0:1: +2:2
       }
   }
   
index e3375e9e15cb3dbec059f98aa19b2b4056bc9e5f..076509df34949f99f78616cdd738e51dd958109d 100644 (file)
           StorageDead(_3);                 // scope 0 at $DIR/inline-instruction-set.rs:+3:30: +3:31
           _0 = const ();                   // scope 0 at $DIR/inline-instruction-set.rs:+0:18: +4:2
           return;                          // scope 0 at $DIR/inline-instruction-set.rs:+4:2: +4:2
-+     }
-+ 
-+     bb3 (cleanup): {
-+         resume;                          // scope 0 at $DIR/inline-instruction-set.rs:+0:1: +4:2
       }
   }
   
index ce294db02fdd5e46acf2c6b26d7a8450f126e294..b275d08e05f92c3fc4b9c24ea17de3c589b2d6df 100644 (file)
           StorageDead(_3);                 // scope 0 at $DIR/inline-instruction-set.rs:+5:30: +5:31
           _0 = const ();                   // scope 0 at $DIR/inline-instruction-set.rs:+0:14: +6:2
           return;                          // scope 0 at $DIR/inline-instruction-set.rs:+6:2: +6:2
-+     }
-+ 
-+     bb3 (cleanup): {
-+         resume;                          // scope 0 at $DIR/inline-instruction-set.rs:+0:1: +6:2
       }
   }
   
index deaba70e082edfa8ec5de83861623b0338349b3d..5dfcd2d54ca27ae63bcc29fc656485dc91e0d5f4 100644 (file)
       let mut _5: std::boxed::Box<std::vec::Vec<u32>>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
       let mut _6: ();                      // in scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43
       let mut _7: *const std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-      let mut _8: *const std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-+     let mut _9: &mut std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
++     let mut _8: &mut std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
       scope 1 {
           debug _x => _1;                  // in scope 1 at $DIR/inline-into-box-place.rs:+1:9: +1:11
       }
       scope 2 {
       }
 +     scope 3 (inlined Vec::<u32>::new) {  // at $DIR/inline-into-box-place.rs:8:33: 8:43
-+         let mut _10: alloc::raw_vec::RawVec<u32>; // in scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         let mut _9: alloc::raw_vec::RawVec<u32>; // in scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
 +     }
   
       bb0: {
           StorageLive(_7);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
           _7 = (((_5.0: std::ptr::Unique<std::vec::Vec<u32>>).0: std::ptr::NonNull<std::vec::Vec<u32>>).0: *const std::vec::Vec<u32>); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
 -         (*_7) = Vec::<u32>::new() -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-+         StorageLive(_9);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-+         _9 = &mut (*_7);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-+         StorageLive(_10);                // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         _10 = const alloc::raw_vec::RawVec::<u32>::NEW; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         StorageLive(_8);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
++         _8 = &mut (*_7);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
++         StorageLive(_9);                 // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         _9 = const alloc::raw_vec::RawVec::<u32>::NEW; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
                                            // mir::Constant
 -                                          // + span: $DIR/inline-into-box-place.rs:8:33: 8:41
 -                                          // + user_ty: UserType(1)
 +                                          // + span: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
 +                                          // + user_ty: UserType(0)
 +                                          // + literal: Const { ty: alloc::raw_vec::RawVec<u32>, val: Unevaluated(alloc::raw_vec::RawVec::<T>::NEW, [u32], None) }
-+         Deinit((*_9));                   // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         ((*_9).0: alloc::raw_vec::RawVec<u32>) = move _10; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         ((*_9).1: usize) = const 0_usize; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         StorageDead(_10);                // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         StorageDead(_9);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
++         Deinit((*_8));                   // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         ((*_8).0: alloc::raw_vec::RawVec<u32>) = move _9; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         ((*_8).1: usize) = const 0_usize; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         StorageDead(_9);                 // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         StorageDead(_8);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
           StorageDead(_7);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
           _1 = move _5;                    // scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
           StorageDead(_5);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43
index deaba70e082edfa8ec5de83861623b0338349b3d..5dfcd2d54ca27ae63bcc29fc656485dc91e0d5f4 100644 (file)
       let mut _5: std::boxed::Box<std::vec::Vec<u32>>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
       let mut _6: ();                      // in scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43
       let mut _7: *const std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-      let mut _8: *const std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-+     let mut _9: &mut std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
++     let mut _8: &mut std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
       scope 1 {
           debug _x => _1;                  // in scope 1 at $DIR/inline-into-box-place.rs:+1:9: +1:11
       }
       scope 2 {
       }
 +     scope 3 (inlined Vec::<u32>::new) {  // at $DIR/inline-into-box-place.rs:8:33: 8:43
-+         let mut _10: alloc::raw_vec::RawVec<u32>; // in scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         let mut _9: alloc::raw_vec::RawVec<u32>; // in scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
 +     }
   
       bb0: {
           StorageLive(_7);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
           _7 = (((_5.0: std::ptr::Unique<std::vec::Vec<u32>>).0: std::ptr::NonNull<std::vec::Vec<u32>>).0: *const std::vec::Vec<u32>); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
 -         (*_7) = Vec::<u32>::new() -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-+         StorageLive(_9);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-+         _9 = &mut (*_7);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-+         StorageLive(_10);                // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         _10 = const alloc::raw_vec::RawVec::<u32>::NEW; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         StorageLive(_8);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
++         _8 = &mut (*_7);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
++         StorageLive(_9);                 // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         _9 = const alloc::raw_vec::RawVec::<u32>::NEW; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
                                            // mir::Constant
 -                                          // + span: $DIR/inline-into-box-place.rs:8:33: 8:41
 -                                          // + user_ty: UserType(1)
 +                                          // + span: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
 +                                          // + user_ty: UserType(0)
 +                                          // + literal: Const { ty: alloc::raw_vec::RawVec<u32>, val: Unevaluated(alloc::raw_vec::RawVec::<T>::NEW, [u32], None) }
-+         Deinit((*_9));                   // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         ((*_9).0: alloc::raw_vec::RawVec<u32>) = move _10; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         ((*_9).1: usize) = const 0_usize; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         StorageDead(_10);                // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         StorageDead(_9);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
++         Deinit((*_8));                   // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         ((*_8).0: alloc::raw_vec::RawVec<u32>) = move _9; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         ((*_8).1: usize) = const 0_usize; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         StorageDead(_9);                 // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         StorageDead(_8);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
           StorageDead(_7);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
           _1 = move _5;                    // scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
           StorageDead(_5);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43
index 49c72b7196c412b9159b358ff5f251f5b81132cd..275493066ee323349cc5f3fcf1cfdc7f0f0885e9 100644 (file)
@@ -52,8 +52,4 @@ fn main() -> () {
         _0 = const ();                   // scope 0 at $DIR/inline-options.rs:+0:11: +3:2
         return;                          // scope 0 at $DIR/inline-options.rs:+3:2: +3:2
     }
-
-    bb5 (cleanup): {
-        resume;                          // scope 0 at $DIR/inline-options.rs:+0:1: +3:2
-    }
 }
index 0ea8823156c1258aed050dab06294d2ede8c143a..768608564d666ab9efe022f1a0b65f6a49f24ead 100644 (file)
@@ -69,8 +69,4 @@ fn bar() -> bool {
         StorageDead(_4);                 // scope 0 at $DIR/inline-retag.rs:+3:1: +3:2
         return;                          // scope 0 at $DIR/inline-retag.rs:+3:2: +3:2
     }
-
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/inline-retag.rs:+0:1: +3:2
-    }
 }
index e69af791622640b247f4b2b6a2afb4ec9703b77a..25ca05893b2ee9b3662b8d27b129230b20ae368b 100644 (file)
 +         _0 = (*_2);                      // scope 1 at $SRC_DIR/core/src/clone.rs:LL:COL
           StorageDead(_2);                 // scope 0 at $DIR/inline-shims.rs:+1:13: +1:14
           return;                          // scope 0 at $DIR/inline-shims.rs:+2:2: +2:2
-+     }
-+ 
-+     bb1 (cleanup): {
-+         resume;                          // scope 0 at $DIR/inline-shims.rs:+0:1: +2:2
       }
   }
   
index 8c1c383ee25dc551c3cd33920cbada010b3714c5..f7b1cde80bdc743db99ae20cf6aa5b234ccda5fa 100644 (file)
 + 
 +     bb3: {
 +         drop((((*_5) as Some).0: B)) -> bb2; // scope 3 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-+     }
-+ 
-+     bb4 (cleanup): {
-+         resume;                          // scope 0 at $DIR/inline-shims.rs:+0:1: +3:2
       }
   }
   
index 6c71311c7d434e79be1955845bc1917953b562b5..106291b36e3973a5b84d613e3532f103db3c4987 100644 (file)
           _0 = const ();                   // scope 0 at $DIR/inline-specialization.rs:+0:11: +2:2
           StorageDead(_1);                 // scope 0 at $DIR/inline-specialization.rs:+2:1: +2:2
           return;                          // scope 0 at $DIR/inline-specialization.rs:+2:2: +2:2
-+     }
-+ 
-+     bb1 (cleanup): {
-+         resume;                          // scope 0 at $DIR/inline-specialization.rs:+0:1: +2:2
       }
   }
   
index 36875d07ca42952d770a8d98e9e998a3ee7b0914..116ae4e361be5afd8b92069f2fe3635071e05d1d 100644 (file)
@@ -29,8 +29,4 @@ fn test2(_1: &dyn X) -> bool {
         StorageDead(_2);                 // scope 0 at $DIR/inline-trait-method_2.rs:+1:11: +1:12
         return;                          // scope 0 at $DIR/inline-trait-method_2.rs:+2:2: +2:2
     }
-
-    bb2 (cleanup): {
-        resume;                          // scope 0 at $DIR/inline-trait-method_2.rs:+0:1: +2:2
-    }
 }
index e715ff83598f3da6331935dee2b954cf436a65d7..5168ae031f04c956c20610bb11aa93aa53c533cd 100644 (file)
@@ -27,8 +27,4 @@ fn a(_1: &mut [T]) -> &mut [T] {
         StorageDead(_2);                 // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:1: +2:2
         return;                          // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:2: +2:2
     }
-
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+0:1: +2:2
-    }
 }
index 8bacced23bd6b8b1a775d526beea41b9b4b756c0..4006dd15a42e94fe1ed65c8539513cf5639e6581 100644 (file)
@@ -39,8 +39,4 @@ fn b(_1: &mut Box<T>) -> &mut T {
         StorageDead(_2);                 // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:1: +2:2
         return;                          // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:2: +2:2
     }
-
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+0:1: +2:2
-    }
 }
index 233a1788288fa7c784d60391c62284d5ef3fbde5..c7f20ff98ff72204ecdc9d3d79244ab0f3295625 100644 (file)
@@ -19,8 +19,4 @@ fn c(_1: &[T]) -> &[T] {
         StorageDead(_2);                 // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:1: +2:2
         return;                          // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:2: +2:2
     }
-
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+0:1: +2:2
-    }
 }
index 5b4aeee9e2b5c5ec0e3dada6548f4a3b7a445001..e516269c1407a972cc4fc57ddd7adbfd478a5659 100644 (file)
@@ -27,8 +27,4 @@ fn d(_1: &Box<T>) -> &T {
         StorageDead(_2);                 // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:1: +2:2
         return;                          // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:2: +2:2
     }
-
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+0:1: +2:2
-    }
 }
index 769ff89fdb7add0e93dfb37d3b620b494d58a181..fca53a72f88209cf09fd23c92c0ab79861c19205 100644 (file)
@@ -39,8 +39,4 @@ fn main() -> () {
         StorageDead(_1);                 // scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:+3:1: +3:2
         return;                          // scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:+3:2: +3:2
     }
-
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:+0:1: +3:2
-    }
 }
index b78ef36eadd9808fefc8aa909ac9080a99444639..a3cee3ecf61cb4d82fafaba385f41bc8f818e432 100644 (file)
@@ -5,7 +5,7 @@
       let mut _0: bool;                    // return place in scope 0 at /the/src/instrument_coverage.rs:+0:13: +0:17
   
       bb0: {
-+         Coverage::Counter(1) for /the/src/instrument_coverage.rs:19:1 - 21:2; // scope 0 at /the/src/instrument_coverage.rs:+2:2: +2:2
++         Coverage::Counter(1) for /the/src/instrument_coverage.rs:20:1 - 22:2; // scope 0 at /the/src/instrument_coverage.rs:+2:2: +2:2
           _0 = const true;                 // scope 0 at /the/src/instrument_coverage.rs:+1:5: +1:9
           return;                          // scope 0 at /the/src/instrument_coverage.rs:+2:2: +2:2
       }
index 0490c0df2e6051930329f47630ebd36e451727ef..81d5528231db65fb0437724d99cde06f9dd27b0c 100644 (file)
@@ -8,12 +8,12 @@
       let mut _3: !;                       // in scope 0 at /the/src/instrument_coverage.rs:+2:18: +4:10
   
       bb0: {
-+         Coverage::Counter(1) for /the/src/instrument_coverage.rs:10:1 - 10:11; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6
++         Coverage::Counter(1) for /the/src/instrument_coverage.rs:11:1 - 11:11; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6
           goto -> bb1;                     // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6
       }
   
       bb1: {
-+         Coverage::Expression(4294967295) = 1 + 2 for /the/src/instrument_coverage.rs:11:5 - 12:17; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6
++         Coverage::Expression(4294967295) = 1 + 2 for /the/src/instrument_coverage.rs:12:5 - 13:17; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6
           falseUnwind -> [real: bb2, cleanup: bb6]; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6
       }
   
@@ -21,7 +21,7 @@
           StorageLive(_2);                 // scope 0 at /the/src/instrument_coverage.rs:+2:12: +2:17
           _2 = bar() -> [return: bb3, unwind: bb6]; // scope 0 at /the/src/instrument_coverage.rs:+2:12: +2:17
                                            // mir::Constant
-                                           // + span: /the/src/instrument_coverage.rs:12:12: 12:15
+                                           // + span: /the/src/instrument_coverage.rs:13:12: 13:15
                                            // + literal: Const { ty: fn() -> bool {bar}, val: Value(<ZST>) }
       }
   
       }
   
       bb4: {
-+         Coverage::Expression(4294967293) = 4294967294 + 0 for /the/src/instrument_coverage.rs:16:1 - 16:2; // scope 0 at /the/src/instrument_coverage.rs:+6:2: +6:2
-+         Coverage::Expression(4294967294) = 4294967295 - 2 for /the/src/instrument_coverage.rs:13:13 - 13:18; // scope 0 at /the/src/instrument_coverage.rs:+6:2: +6:2
++         Coverage::Expression(4294967293) = 4294967294 + 0 for /the/src/instrument_coverage.rs:17:1 - 17:2; // scope 0 at /the/src/instrument_coverage.rs:+6:2: +6:2
++         Coverage::Expression(4294967294) = 4294967295 - 2 for /the/src/instrument_coverage.rs:14:13 - 14:18; // scope 0 at /the/src/instrument_coverage.rs:+6:2: +6:2
           _0 = const ();                   // scope 0 at /the/src/instrument_coverage.rs:+3:13: +3:18
           StorageDead(_2);                 // scope 0 at /the/src/instrument_coverage.rs:+4:9: +4:10
           return;                          // scope 0 at /the/src/instrument_coverage.rs:+6:2: +6:2
       }
   
       bb5: {
-+         Coverage::Counter(2) for /the/src/instrument_coverage.rs:14:10 - 14:11; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6
++         Coverage::Counter(2) for /the/src/instrument_coverage.rs:15:10 - 15:11; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6
           _1 = const ();                   // scope 0 at /the/src/instrument_coverage.rs:+4:10: +4:10
           StorageDead(_2);                 // scope 0 at /the/src/instrument_coverage.rs:+4:9: +4:10
           goto -> bb1;                     // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6
index a748f2c5ccc9b54346df5557be2e3fe9658349f7..7f6a0a0eb094a0434e9f693efd741ea4c49aebb7 100644 (file)
@@ -1,6 +1,7 @@
 // Test that `-C instrument-coverage` injects Coverage statements. The Coverage Counter statements
 // are later converted into LLVM instrprof.increment intrinsics, during codegen.
 
+// unit-test: InstrumentCoverage
 // needs-profiler-support
 // ignore-windows
 // compile-flags: -C instrument-coverage --remap-path-prefix={{src-base}}=/the/src
index 6866bcf9b8a7f17da6c0bc65e80803e15bd7677b..5c635e2220ed707ce1de3fa180afae64e08f1413 100644 (file)
@@ -16,9 +16,5 @@
       bb1: {
           return;                          // scope 0 at $DIR/lower_intrinsics.rs:+2:2: +2:2
       }
-  
-      bb2 (cleanup): {
-          resume;                          // scope 0 at $DIR/lower_intrinsics.rs:+0:1: +2:2
-      }
   }
   
index 032a6a01b7fe2f9b93d966b05800e018452019bf..8a80de32f3ae36d4c7916cc1849c93b4abed061a 100644 (file)
       bb5: {
           return;                          // scope 0 at $DIR/lower_intrinsics.rs:+5:2: +5:2
       }
-  
-      bb6 (cleanup): {
-          resume;                          // scope 0 at $DIR/lower_intrinsics.rs:+0:1: +5:2
-      }
   }
   
index 50c86e61949dd52725b7ff638b078d7718afd514..e6a2f6512f55af51df45fa5cc4b7a7ae8ece4190 100644 (file)
@@ -25,9 +25,5 @@
       bb2: {
           return;                          // scope 0 at $DIR/lower_intrinsics.rs:+2:2: +2:2
       }
-  
-      bb3 (cleanup): {
-          resume;                          // scope 0 at $DIR/lower_intrinsics.rs:+0:1: +2:2
-      }
   }
   
index 01591e17624d785e091031f8536c737e072781fd..1ab2f2a0a046828c32577c7ce3721661dfa879bd 100644 (file)
@@ -27,9 +27,5 @@
           StorageDead(_1);                 // scope 0 at $DIR/lower_intrinsics.rs:+4:1: +4:2
           return;                          // scope 0 at $DIR/lower_intrinsics.rs:+4:2: +4:2
       }
-  
-      bb2 (cleanup): {
-          resume;                          // scope 0 at $DIR/lower_intrinsics.rs:+0:1: +4:2
-      }
   }
   
index 7bc24fe7d673fbec3e46a66970ffd744413646d6..11b27976b551c9f171e11cbe7f9b0a0edb3ce07f 100644 (file)
@@ -16,9 +16,5 @@
       bb1: {
           return;                          // scope 0 at $DIR/lower_intrinsics.rs:+2:2: +2:2
       }
-  
-      bb2 (cleanup): {
-          resume;                          // scope 0 at $DIR/lower_intrinsics.rs:+0:1: +2:2
-      }
   }
   
index 581926ab163e8276aff7a13674b2f6dc88c5cff3..ac077e85b04f357a3ed5eab40a6182c2ec3e63b9 100644 (file)
@@ -18,9 +18,5 @@
 -                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn() -> ! {std::intrinsics::unreachable}, val: Value(<ZST>) }
 +         unreachable;                     // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:45
       }
-  
-      bb1 (cleanup): {
-          resume;                          // scope 0 at $DIR/lower_intrinsics.rs:+0:1: +2:2
-      }
   }
   
index b0fa55bdd4c6db17de58bb24d8b531d1028447ac..e0a5416b22b5fbe431578dadf506d8c7fab940c9 100644 (file)
@@ -79,9 +79,5 @@
           StorageDead(_3);                 // scope 0 at $DIR/lower_intrinsics.rs:+4:1: +4:2
           return;                          // scope 0 at $DIR/lower_intrinsics.rs:+4:2: +4:2
       }
-  
-      bb4 (cleanup): {
-          resume;                          // scope 0 at $DIR/lower_intrinsics.rs:+0:1: +4:2
-      }
   }
   
index 5fbb848dcb58bb3ba35198dbfe5a7eacc8d925d8..2ae03da40f8a2b6bbf637eadb5c619f35cb9073f 100644 (file)
@@ -1,3 +1,4 @@
+// unit-test: InstCombine
 // EMIT_MIR not_equal_false.opt.InstCombine.diff
 
 fn opt(x: bool) -> u32 {
index a17a0776437d479339354a4e00813213efdba731..99667aabdaee27d68e8e13ccb62a94c85c0247cd 100644 (file)
               scope 3 {
                   debug i => _12;          // in scope 3 at $DIR/remove_storage_markers.rs:+2:9: +2:10
               }
-              scope 5 (inlined iter::range::<impl Iterator for std::ops::Range<i32>>::next) { // at $DIR/remove_storage_markers.rs:8:14: 8:19
-                  debug self => _8;        // in scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL
-                  let mut _14: &mut std::ops::Range<i32>; // in scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL
-              }
-          }
-          scope 4 (inlined <std::ops::Range<i32> as IntoIterator>::into_iter) { // at $DIR/remove_storage_markers.rs:8:14: 8:19
-              debug self => _3;            // in scope 4 at $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
           }
       }
   
           Deinit(_3);                      // scope 1 at $DIR/remove_storage_markers.rs:+2:14: +2:19
           (_3.0: i32) = const 0_i32;       // scope 1 at $DIR/remove_storage_markers.rs:+2:14: +2:19
           (_3.1: i32) = const 10_i32;      // scope 1 at $DIR/remove_storage_markers.rs:+2:14: +2:19
-          _2 = move _3;                    // scope 4 at $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
+          _2 = <std::ops::Range<i32> as IntoIterator>::into_iter(move _3) -> bb1; // scope 1 at $DIR/remove_storage_markers.rs:+2:14: +2:19
+                                           // mir::Constant
+                                           // + span: $DIR/remove_storage_markers.rs:10:14: 10:19
+                                           // + literal: Const { ty: fn(std::ops::Range<i32>) -> <std::ops::Range<i32> as IntoIterator>::IntoIter {<std::ops::Range<i32> as IntoIterator>::into_iter}, val: Value(<ZST>) }
+      }
+  
+      bb1: {
 -         StorageDead(_3);                 // scope 1 at $DIR/remove_storage_markers.rs:+2:18: +2:19
 -         StorageLive(_4);                 // scope 1 at $DIR/remove_storage_markers.rs:+2:14: +2:19
           _4 = move _2;                    // scope 1 at $DIR/remove_storage_markers.rs:+2:14: +2:19
-          goto -> bb1;                     // scope 2 at $DIR/remove_storage_markers.rs:+2:5: +4:6
+          goto -> bb2;                     // scope 2 at $DIR/remove_storage_markers.rs:+2:5: +4:6
       }
   
-      bb1: {
+      bb2: {
 -         StorageLive(_6);                 // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
 -         StorageLive(_7);                 // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
 -         StorageLive(_8);                 // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
 -         StorageLive(_9);                 // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
           _9 = &mut _4;                    // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
           _8 = &mut (*_9);                 // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
--         StorageLive(_14);                // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL
-          _14 = &mut (*_8);                // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL
-          _7 = <std::ops::Range<i32> as iter::range::RangeIteratorImpl>::spec_next(move _14) -> bb4; // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL
+          _7 = <std::ops::Range<i32> as Iterator>::next(move _8) -> bb3; // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
                                            // mir::Constant
-                                           // + span: $SRC_DIR/core/src/iter/range.rs:LL:COL
-                                           // + literal: Const { ty: for<'r> fn(&'r mut std::ops::Range<i32>) -> Option<<std::ops::Range<i32> as iter::range::RangeIteratorImpl>::Item> {<std::ops::Range<i32> as iter::range::RangeIteratorImpl>::spec_next}, val: Value(<ZST>) }
+                                           // + span: $DIR/remove_storage_markers.rs:10:14: 10:19
+                                           // + literal: Const { ty: for<'r> fn(&'r mut std::ops::Range<i32>) -> Option<<std::ops::Range<i32> as Iterator>::Item> {<std::ops::Range<i32> as Iterator>::next}, val: Value(<ZST>) }
       }
   
-      bb2: {
+      bb3: {
+-         StorageDead(_8);                 // scope 2 at $DIR/remove_storage_markers.rs:+2:18: +2:19
+          _10 = discriminant(_7);          // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
+          switchInt(move _10) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
+      }
+  
+      bb4: {
 -         StorageLive(_12);                // scope 2 at $DIR/remove_storage_markers.rs:+2:9: +2:10
           _12 = ((_7 as Some).0: i32);     // scope 2 at $DIR/remove_storage_markers.rs:+2:9: +2:10
 -         StorageLive(_13);                // scope 3 at $DIR/remove_storage_markers.rs:+3:16: +3:17
 -         StorageDead(_7);                 // scope 2 at $DIR/remove_storage_markers.rs:+4:5: +4:6
 -         StorageDead(_6);                 // scope 2 at $DIR/remove_storage_markers.rs:+4:5: +4:6
           _5 = const ();                   // scope 2 at $DIR/remove_storage_markers.rs:+2:5: +4:6
-          goto -> bb1;                     // scope 2 at $DIR/remove_storage_markers.rs:+2:5: +4:6
+          goto -> bb2;                     // scope 2 at $DIR/remove_storage_markers.rs:+2:5: +4:6
       }
   
-      bb3: {
+      bb5: {
+          unreachable;                     // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
+      }
+  
+      bb6: {
           _0 = const ();                   // scope 2 at $DIR/remove_storage_markers.rs:+2:5: +4:6
 -         StorageDead(_9);                 // scope 2 at $DIR/remove_storage_markers.rs:+4:5: +4:6
 -         StorageDead(_7);                 // scope 2 at $DIR/remove_storage_markers.rs:+4:5: +4:6
 -         StorageDead(_1);                 // scope 0 at $DIR/remove_storage_markers.rs:+5:1: +5:2
           return;                          // scope 0 at $DIR/remove_storage_markers.rs:+5:2: +5:2
       }
-  
-      bb4: {
--         StorageDead(_14);                // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL
--         StorageDead(_8);                 // scope 2 at $DIR/remove_storage_markers.rs:+2:18: +2:19
-          _10 = discriminant(_7);          // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
-          switchInt(move _10) -> [0_isize: bb3, otherwise: bb2]; // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
-      }
-  
-      bb5 (cleanup): {
-          resume;                          // scope 0 at $DIR/remove_storage_markers.rs:+0:1: +5:2
-      }
   }
   
index c144d3ff7950815b1e668ef5cf3ae0c54f796fa1..f00b826911c6a09770d112ad4dccad2ddde56d6e 100644 (file)
@@ -1,3 +1,5 @@
+// unit-test: RemoveStorageMarkers
+
 // Checks that storage markers are removed at opt-level=0.
 //
 // compile-flags: -C opt-level=0 -Coverflow-checks=off
index b29b08f836d33ecd413d6edd52b0319ee943d824..087f76dbda83b42787018a3e445d7b43c9d5a0f2 100644 (file)
           StorageDead(_2);                 // scope 0 at $DIR/remove_unneeded_drops.rs:+1:12: +1:13
 -         nop;                             // scope 0 at $DIR/remove_unneeded_drops.rs:+0:17: +2:2
           return;                          // scope 0 at $DIR/remove_unneeded_drops.rs:+2:2: +2:2
--     }
-- 
--     bb2 (cleanup): {
--         resume;                          // scope 0 at $DIR/remove_unneeded_drops.rs:+0:1: +2:2
       }
   }
   
index 9058ddbd7ec7975f81c21293562dcedecec82e1d..933d6895f45946ef5293ee87167b43f68f258623 100644 (file)
           StorageDead(_2);                 // scope 0 at $DIR/remove_unneeded_drops.rs:+1:12: +1:13
 -         nop;                             // scope 0 at $DIR/remove_unneeded_drops.rs:+0:36: +2:2
           return;                          // scope 0 at $DIR/remove_unneeded_drops.rs:+2:2: +2:2
--     }
-- 
--     bb2 (cleanup): {
--         resume;                          // scope 0 at $DIR/remove_unneeded_drops.rs:+0:1: +2:2
       }
   }
   
index 7a6f86b808509dbccafe35136d4eeaf0cfada5f1..8b9de9b4d65a66fd987f2357d44fc0cecf038e42 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -Zmir-opt-level=3
+// unit-test: RemoveZsts
 
 // Ensure RemoveZsts doesn't remove ZST assignments to union fields,
 // which causes problems in Miri.
index 451d0fe4c02dcdb51a9f844f5e6a6f1ccfb54608..05554174ae2c78aa6dd13da4083ee1f82ba18564 100644 (file)
@@ -80,7 +80,7 @@ fn array_casts() -> () {
         _7 = _2;                         // scope 3 at $DIR/retag.rs:+3:15: +3:16
         _6 = ptr::mut_ptr::<impl *mut usize>::add(move _7, const 1_usize) -> bb1; // scope 3 at $DIR/retag.rs:+3:15: +3:23
                                          // mir::Constant
-                                         // + span: $DIR/retag.rs:60:17: 60:20
+                                         // + span: $DIR/retag.rs:61:17: 61:20
                                          // + literal: Const { ty: unsafe fn(*mut usize, usize) -> *mut usize {ptr::mut_ptr::<impl *mut usize>::add}, val: Value(<ZST>) }
     }
 
@@ -111,7 +111,7 @@ fn array_casts() -> () {
         _17 = _9;                        // scope 6 at $DIR/retag.rs:+7:26: +7:27
         _16 = ptr::const_ptr::<impl *const usize>::add(move _17, const 1_usize) -> bb2; // scope 6 at $DIR/retag.rs:+7:26: +7:34
                                          // mir::Constant
-                                         // + span: $DIR/retag.rs:64:28: 64:31
+                                         // + span: $DIR/retag.rs:65:28: 65:31
                                          // + literal: Const { ty: unsafe fn(*const usize, usize) -> *const usize {ptr::const_ptr::<impl *const usize>::add}, val: Value(<ZST>) }
     }
 
index ae6b5cfe21ebb32a3e74d7eb16437576838f27e1..8802f3b295851a4aaa4d9e9bf34b968dbd6b61c9 100644 (file)
@@ -73,7 +73,7 @@ fn main() -> () {
         Retag([2phase] _6);              // scope 1 at $DIR/retag.rs:+3:29: +3:35
         _3 = Test::foo(move _4, move _6) -> [return: bb1, unwind: bb8]; // scope 1 at $DIR/retag.rs:+3:17: +3:36
                                          // mir::Constant
-                                         // + span: $DIR/retag.rs:32:25: 32:28
+                                         // + span: $DIR/retag.rs:33:25: 33:28
                                          // + literal: Const { ty: for<'r, 'x> fn(&'r Test, &'x mut i32) -> &'x mut i32 {Test::foo}, val: Value(<ZST>) }
     }
 
@@ -149,7 +149,7 @@ fn main() -> () {
         StorageLive(_23);                // scope 7 at $DIR/retag.rs:+18:21: +18:23
         _28 = const main::promoted[0];   // scope 7 at $DIR/retag.rs:+18:21: +18:23
                                          // mir::Constant
-                                         // + span: $DIR/retag.rs:47:21: 47:23
+                                         // + span: $DIR/retag.rs:48:21: 48:23
                                          // + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) }
         Retag(_28);                      // scope 7 at $DIR/retag.rs:+18:21: +18:23
         _23 = &(*_28);                   // scope 7 at $DIR/retag.rs:+18:21: +18:23
@@ -158,7 +158,7 @@ fn main() -> () {
         Retag(_22);                      // scope 7 at $DIR/retag.rs:+18:21: +18:23
         _19 = Test::foo_shr(move _20, move _22) -> [return: bb4, unwind: bb7]; // scope 7 at $DIR/retag.rs:+18:5: +18:24
                                          // mir::Constant
-                                         // + span: $DIR/retag.rs:47:13: 47:20
+                                         // + span: $DIR/retag.rs:48:13: 48:20
                                          // + literal: Const { ty: for<'r, 'x> fn(&'r Test, &'x i32) -> &'x i32 {Test::foo_shr}, val: Value(<ZST>) }
     }
 
@@ -182,7 +182,7 @@ fn main() -> () {
         StorageLive(_27);                // scope 8 at $DIR/retag.rs:+23:5: +23:18
         _27 = array_casts() -> bb6;      // scope 8 at $DIR/retag.rs:+23:5: +23:18
                                          // mir::Constant
-                                         // + span: $DIR/retag.rs:52:5: 52:16
+                                         // + span: $DIR/retag.rs:53:5: 53:16
                                          // + literal: Const { ty: fn() {array_casts}, val: Value(<ZST>) }
     }
 
index 13568b822d4f3c6f1afe163e0d291a2c518288ab..86deb0e7ccdedbf0e935d2cd515f2545749e0f5b 100644 (file)
@@ -1,3 +1,4 @@
+// unit-test: AddRetag
 // ignore-wasm32-bare compiled with panic=abort by default
 // ignore-tidy-linelength
 // compile-flags: -Z mir-emit-retag -Z mir-opt-level=0 -Z span_free_formats
index e395fdb274f371428523f04d78077e32b5b87510..25d400f0c9fb20220c1eec60e7277f2276fdba7f 100644 (file)
@@ -1,6 +1,6 @@
-// MIR for `<impl at $DIR/retag.rs:11:1: 11:10>::foo` after SimplifyCfg-elaborate-drops
+// MIR for `<impl at $DIR/retag.rs:12:1: 12:10>::foo` after SimplifyCfg-elaborate-drops
 
-fn <impl at $DIR/retag.rs:11:1: 11:10>::foo(_1: &Test, _2: &mut i32) -> &mut i32 {
+fn <impl at $DIR/retag.rs:12:1: 12:10>::foo(_1: &Test, _2: &mut i32) -> &mut i32 {
     debug self => _1;                    // in scope 0 at $DIR/retag.rs:+0:16: +0:21
     debug x => _2;                       // in scope 0 at $DIR/retag.rs:+0:23: +0:24
     let mut _0: &mut i32;                // return place in scope 0 at $DIR/retag.rs:+0:42: +0:53
index e609166dec892a87b6e71107e76aa74c5ce8ab6d..84ad8afc357604ac362dd54b410d8141a2383ec8 100644 (file)
@@ -1,6 +1,6 @@
-// MIR for `<impl at $DIR/retag.rs:11:1: 11:10>::foo_shr` after SimplifyCfg-elaborate-drops
+// MIR for `<impl at $DIR/retag.rs:12:1: 12:10>::foo_shr` after SimplifyCfg-elaborate-drops
 
-fn <impl at $DIR/retag.rs:11:1: 11:10>::foo_shr(_1: &Test, _2: &i32) -> &i32 {
+fn <impl at $DIR/retag.rs:12:1: 12:10>::foo_shr(_1: &Test, _2: &i32) -> &i32 {
     debug self => _1;                    // in scope 0 at $DIR/retag.rs:+0:20: +0:25
     debug x => _2;                       // in scope 0 at $DIR/retag.rs:+0:27: +0:28
     let mut _0: &i32;                    // return place in scope 0 at $DIR/retag.rs:+0:42: +0:49
index 179994544723f25fc87b606032cbbd860b9d0921..39b7911d4aedbcfafd6fd3a4c38ed43f92a189f9 100644 (file)
@@ -1,3 +1,4 @@
+// unit-test: SimplifyLocals
 // compile-flags: -C overflow-checks=no
 
 fn use_zst(_: ((), ())) {}
index f6bf396cd05152f3571049e6cd9c87828f40aed8..89d9391f832dc3e5290eeab56719aca61c268f72 100644 (file)
@@ -1,6 +1,6 @@
 // unit-test: SimplifyLocals
 
-#![feature(box_syntax)]
+
 #![feature(thread_local)]
 
 #[derive(Copy, Clone)]
index 229046b51fcd50312d4eac6a9bcd68a9bffd1d0d..452cc8a9c26a7f35235e08eca58ba71ce0aabfae 100644 (file)
@@ -85,9 +85,5 @@
       bb4: {
           return;                          // scope 0 at $DIR/simplify-arm.rs:+6:2: +6:2
       }
-  
-      bb5 (cleanup): {
-          resume;                          // scope 0 at $DIR/simplify-arm.rs:+0:1: +6:2
-      }
   }
   
index 22a2f85c09ae5e0c9c14893946e545ec869fa469..5d7d4ba7c3d8bcd3f0cfd806ce98a8d59632aed9 100644 (file)
@@ -85,9 +85,5 @@
       bb4: {
           return;                          // scope 0 at $DIR/simplify-arm.rs:+6:2: +6:2
       }
-  
-      bb5 (cleanup): {
-          resume;                          // scope 0 at $DIR/simplify-arm.rs:+0:1: +6:2
-      }
   }
   
index da2f6fc440aa26464051cc9a82c6b509050d7269..b41527ba02de5cc3dd92d78456e536a7cd541595 100644 (file)
 -     let mut _11: Temp;                   // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28
 +     let _1: ();                          // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+2:5: +2:22
 +     let mut _2: ((), ());                // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21
-+     let _3: ();                          // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35
++     let mut _3: ();                      // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+2:14: +2:16
++     let mut _4: ();                      // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+2:18: +2:20
++     let _5: ();                          // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35
++     let mut _6: u8;                      // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:34
++     let mut _7: u8;                      // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:30
++     let mut _8: Temp;                    // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28
       scope 1 {
       }
   
       bb0: {
 -         StorageLive(_1);                 // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:20: +1:28
 -         StorageLive(_2);                 // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:21: +1:23
+-         Deinit(_2);                      // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:21: +1:23
 -         StorageLive(_3);                 // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:25: +1:27
+-         Deinit(_3);                      // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:25: +1:27
+-         Deinit(_1);                      // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:20: +1:28
+-         (_1.0: ()) = move _2;            // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:20: +1:28
+-         (_1.1: ()) = move _3;            // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:20: +1:28
 -         StorageDead(_3);                 // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:27: +1:28
 -         StorageDead(_2);                 // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:27: +1:28
 -         StorageDead(_1);                 // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:28: +1:29
 -         StorageLive(_4);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:5: +2:22
 -         StorageLive(_5);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21
 -         StorageLive(_6);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:14: +2:16
+-         Deinit(_6);                      // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:14: +2:16
 -         StorageLive(_7);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:18: +2:20
+-         Deinit(_7);                      // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:18: +2:20
+-         Deinit(_5);                      // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21
+-         (_5.0: ()) = move _6;            // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21
+-         (_5.1: ()) = move _7;            // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21
 -         StorageDead(_7);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:20: +2:21
 -         StorageDead(_6);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:20: +2:21
 -         _4 = use_zst(move _5) -> bb1;    // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:5: +2:22
 +         StorageLive(_1);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:5: +2:22
 +         StorageLive(_2);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21
++         StorageLive(_3);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:14: +2:16
++         Deinit(_3);                      // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:14: +2:16
++         StorageLive(_4);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:18: +2:20
++         Deinit(_4);                      // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:18: +2:20
++         Deinit(_2);                      // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21
++         (_2.0: ()) = move _3;            // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21
++         (_2.1: ()) = move _4;            // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21
++         StorageDead(_4);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:20: +2:21
++         StorageDead(_3);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:20: +2:21
 +         _1 = use_zst(move _2) -> bb1;    // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:5: +2:22
                                            // mir::Constant
-                                           // + span: $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:12
+                                           // + span: $DIR/simplify-locals-removes-unused-consts.rs:15:5: 15:12
                                            // + literal: Const { ty: fn(((), ())) {use_zst}, val: Value(<ZST>) }
       }
   
 -         StorageLive(_9);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:34
 -         StorageLive(_10);                // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:30
 -         StorageLive(_11);                // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28
+-         Deinit(_11);                     // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28
+-         (_11.0: u8) = const 40_u8;       // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28
+-         _10 = (_11.0: u8);               // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:30
+-         _9 = Add(move _10, const 2_u8);  // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:34
 -         StorageDead(_10);                // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:33: +4:34
--         _8 = use_u8(const 42_u8) -> bb2; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35
+-         _8 = use_u8(move _9) -> bb2;     // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35
 +         StorageDead(_2);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:21: +2:22
 +         StorageDead(_1);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:22: +2:23
-+         StorageLive(_3);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35
-+         _3 = use_u8(const 42_u8) -> bb2; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35
++         StorageLive(_5);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35
++         StorageLive(_6);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:34
++         StorageLive(_7);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:30
++         StorageLive(_8);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28
++         Deinit(_8);                      // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28
++         (_8.0: u8) = const 40_u8;        // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28
++         _7 = (_8.0: u8);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:30
++         _6 = Add(move _7, const 2_u8);   // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:34
++         StorageDead(_7);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:33: +4:34
++         _5 = use_u8(move _6) -> bb2;     // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35
                                            // mir::Constant
-                                           // + span: $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:11
+                                           // + span: $DIR/simplify-locals-removes-unused-consts.rs:17:5: 17:11
                                            // + literal: Const { ty: fn(u8) {use_u8}, val: Value(<ZST>) }
       }
   
       bb2: {
 -         StorageDead(_9);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:34: +4:35
 -         StorageDead(_11);                // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:35: +4:36
--         StorageDead(_8);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:35: +4:36
-+         StorageDead(_3);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:35: +4:36
++         StorageDead(_6);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:34: +4:35
+          StorageDead(_8);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:35: +4:36
++         StorageDead(_5);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:35: +4:36
+          _0 = const ();                   // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+0:11: +5:2
           return;                          // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+5:2: +5:2
       }
   }
index 2f740dc4fac38ae74ad6010782f00bac4fea77c7..a2c7a31b7c329b7654e806575805d70ec24eb9d8 100644 (file)
@@ -1,6 +1,5 @@
 // run-pass
 
-#![feature(backtrace)]
 #[derive(Clone, Copy)]
 struct Foo {
     array: [u64; 10240],
index fd67221144a38bfe77f88b73acb4ed088937c353..b072235b5bc5ad21f87ed52d5ca24bd4362ebd3e 100644 (file)
@@ -1,5 +1,5 @@
 #![crate_type = "lib"]
-pub struct V<S>(S);
+pub struct V<S>(#[allow(unused_tuple_struct_fields)] S);
 pub trait An {
     type U;
 }
index 94879c2a6ed663ea3753b35209e93fd9462726cd..c5a70605e04cb2c9a6839d060947cec8c6182f2c 100644 (file)
@@ -1,5 +1,4 @@
 #![crate_name = "test"]
-#![feature(box_syntax)]
 #![feature(rustc_private)]
 
 extern crate rustc_graphviz;
@@ -261,9 +260,9 @@ fn hello<X: SomeTrait>((z, a): (u32, String), ex: X) {
     let x = 32.0f32;
     let _ = (x + ((x * x) + 1.0).sqrt()).ln();
 
-    let s: Box<SomeTrait> = box some_fields { field1: 43 };
-    let s2: Box<some_fields> = box some_fields { field1: 43 };
-    let s3 = box nofields;
+    let s: Box<SomeTrait> = Box::new(some_fields { field1: 43 });
+    let s2: Box<some_fields> = Box::new(some_fields { field1: 43 });
+    let s3 = Box::new(nofields);
 
     s.Method(43);
     s3.Method(43);
@@ -317,7 +316,7 @@ macro_rules! internal_vars {
 
 fn main() {
     // foo
-    let s = box some_fields { field1: 43 };
+    let s = Box::new(some_fields { field1: 43 });
     hello((43, "a".to_string()), *s);
     sub::sub2::hello();
     sub2::sub3::hello();
@@ -345,17 +344,17 @@ macro_rules! variable_str(($name:expr) => (
     let s4: msalias::nested_struct = sub::sub2::nested_struct { field2: 55 };
     let s4: msalias::nested_struct = sub2::nested_struct { field2: 55 };
     println(&s2.field1.to_string());
-    let s5: MyType = box some_fields { field1: 55 };
+    let s5: MyType = Box::new(some_fields { field1: 55 });
     let s = SameDir::SameStruct { name: "Bob".to_string() };
     let s = SubDir::SubStruct { name: "Bob".to_string() };
-    let s6: SomeEnum = SomeEnum::MyTypes(box s2.clone(), s5);
+    let s6: SomeEnum = SomeEnum::MyTypes(Box::new(s2.clone()), s5);
     let s7: SomeEnum = SomeEnum::Strings("one", "two", "three");
     matchSomeEnum(s6);
     matchSomeEnum(s7);
     let s8: SomeOtherEnum = SomeOtherEnum::SomeConst2;
     matchSomeOtherEnum(s8);
     let s9: SomeStructEnum =
-        SomeStructEnum::EnumStruct2 { f1: box some_fields { field1: 10 }, f2: box s2 };
+        SomeStructEnum::EnumStruct2 { f1: Box::new(some_fields { field1: 10 }), f2: Box::new(s2) };
     matchSomeStructEnum(s9);
 
     for x in &vec![1, 2, 3] {
index dd70675032f77748e56dab0617dcaa42b301677a..74aaabfbf1b4b5416f4f331c0d1da05b088fb0ec 100644 (file)
@@ -1,5 +1,4 @@
 #![crate_name = "test"]
-#![feature(box_syntax)]
 #![feature(rustc_private)]
 #![feature(associated_type_defaults)]
 
@@ -255,9 +254,9 @@ fn hello<X: SomeTrait>((z, a): (u32, String), ex: X) {
     let x = 32.0f32;
     let _ = (x + ((x * x) + 1.0).sqrt()).ln();
 
-    let s: Box<SomeTrait> = box some_fields { field1: 43 };
-    let s2: Box<some_fields> = box some_fields { field1: 43 };
-    let s3 = box nofields;
+    let s: Box<SomeTrait> = Box::new(some_fields { field1: 43 });
+    let s2: Box<some_fields> = Box::new(some_fields { field1: 43 });
+    let s3 = Box::new(nofields);
 
     s.Method(43);
     s3.Method(43);
@@ -311,7 +310,7 @@ macro_rules! internal_vars {
 
 fn main() {
     // foo
-    let s = box some_fields { field1: 43 };
+    let s = Box::new(some_fields { field1: 43 });
     hello((43, "a".to_string()), *s);
     sub::sub2::hello();
     sub2::sub3::hello();
@@ -339,17 +338,17 @@ macro_rules! variable_str(($name:expr) => (
     let s4: msalias::nested_struct = sub::sub2::nested_struct { field2: 55 };
     let s4: msalias::nested_struct = sub2::nested_struct { field2: 55 };
     println(&s2.field1.to_string());
-    let s5: MyType = box some_fields { field1: 55 };
+    let s5: MyType = Box::new(some_fields { field1: 55 });
     let s = SameDir::SameStruct { name: "Bob".to_string() };
     let s = SubDir::SubStruct { name: "Bob".to_string() };
-    let s6: SomeEnum = SomeEnum::MyTypes(box s2.clone(), s5);
+    let s6: SomeEnum = SomeEnum::MyTypes(Box::new(s2.clone()), s5);
     let s7: SomeEnum = SomeEnum::Strings("one", "two", "three");
     matchSomeEnum(s6);
     matchSomeEnum(s7);
     let s8: SomeOtherEnum = SomeOtherEnum::SomeConst2;
     matchSomeOtherEnum(s8);
     let s9: SomeStructEnum =
-        SomeStructEnum::EnumStruct2 { f1: box some_fields { field1: 10 }, f2: box s2 };
+        SomeStructEnum::EnumStruct2 { f1: Box::new(some_fields { field1: 10 }), f2: Box::new(s2) };
     matchSomeStructEnum(s9);
 
     for x in &vec![1, 2, 3] {
index 7a5f21922770196bd837f44cdc4a055c2e010a5e..c943261d799c4b608d659a5cece75f60b62cfbeb 100644 (file)
@@ -9,7 +9,7 @@ CHECK-SAME:   section "[[INSTR_PROF_COVFUN]]"[[COMDAT_IF_SUPPORTED]], align 8
 CHECK:        @__llvm_coverage_mapping = private constant
 CHECK-SAME:   section "[[INSTR_PROF_COVMAP]]", align 8
 
-WINDOWS:      @__llvm_profile_runtime = external global i32
+WINDOWS:      @__llvm_profile_runtime = external{{.*}}global i32
 
 CHECK:        @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called = {{private|internal}} global
 CHECK-SAME:   section "[[INSTR_PROF_CNTS]]"{{.*}}, align 8
index 3b49d1188ae6bda93ef2b57dae9993f27b2b3768..967cb065cad1aaeae17d0d20c31911b665b296ea 100644 (file)
@@ -1,7 +1,7 @@
 # ignore-cross-compile -- compiling C++ code does not work well when cross-compiling
 
-# This test case makes sure that native libraries are linked with --whole-archive semantics
-# when the `-bundle,+whole-archive` modifiers are applied to them.
+# This test case makes sure that native libraries are linked with appropriate semantics
+# when the `[+-]bundle,[+-]whole-archive` modifiers are applied to them.
 #
 # The test works by checking that the resulting executables produce the expected output,
 # part of which is emitted by otherwise unreferenced C code. If +whole-archive didn't work
 
 -include ../../run-make-fulldeps/tools.mk
 
-all: $(TMPDIR)/$(call BIN,directly_linked) $(TMPDIR)/$(call BIN,indirectly_linked) $(TMPDIR)/$(call BIN,indirectly_linked_via_attr)
+all: $(TMPDIR)/$(call BIN,directly_linked) \
+     $(TMPDIR)/$(call BIN,directly_linked_test_plus_whole_archive) \
+     $(TMPDIR)/$(call BIN,directly_linked_test_minus_whole_archive) \
+     $(TMPDIR)/$(call BIN,indirectly_linked) \
+     $(TMPDIR)/$(call BIN,indirectly_linked_via_attr)
        $(call RUN,directly_linked) | $(CGREP) 'static-initializer.directly_linked.'
+       $(call RUN,directly_linked_test_plus_whole_archive) --nocapture | $(CGREP) 'static-initializer.'
+       $(call RUN,directly_linked_test_minus_whole_archive) --nocapture | $(CGREP) -v 'static-initializer.'
        $(call RUN,indirectly_linked) | $(CGREP) 'static-initializer.indirectly_linked.'
        $(call RUN,indirectly_linked_via_attr) | $(CGREP) 'static-initializer.native_lib_in_src.'
 
@@ -19,6 +25,13 @@ all: $(TMPDIR)/$(call BIN,directly_linked) $(TMPDIR)/$(call BIN,indirectly_linke
 $(TMPDIR)/$(call BIN,directly_linked): $(call NATIVE_STATICLIB,c_static_lib_with_constructor)
        $(RUSTC) directly_linked.rs -l static:+whole-archive=c_static_lib_with_constructor
 
+# Native lib linked into test executable, +whole-archive
+$(TMPDIR)/$(call BIN,directly_linked_test_plus_whole_archive): $(call NATIVE_STATICLIB,c_static_lib_with_constructor)
+       $(RUSTC) directly_linked_test_plus_whole_archive.rs --test -l static:+whole-archive=c_static_lib_with_constructor
+# Native lib linked into test executable, -whole-archive
+$(TMPDIR)/$(call BIN,directly_linked_test_minus_whole_archive): $(call NATIVE_STATICLIB,c_static_lib_with_constructor)
+       $(RUSTC) directly_linked_test_minus_whole_archive.rs --test -l static:-whole-archive=c_static_lib_with_constructor
+
 # Native lib linked into RLIB via `-l static:-bundle,+whole-archive`, RLIB linked into executable
 $(TMPDIR)/$(call BIN,indirectly_linked): $(TMPDIR)/librlib_with_cmdline_native_lib.rlib
        $(RUSTC) indirectly_linked.rs
diff --git a/src/test/run-make/native-link-modifier-whole-archive/directly_linked_test_minus_whole_archive.rs b/src/test/run-make/native-link-modifier-whole-archive/directly_linked_test_minus_whole_archive.rs
new file mode 100644 (file)
index 0000000..20ed8d9
--- /dev/null
@@ -0,0 +1,7 @@
+use std::io::Write;
+
+#[test]
+fn test_thing() {
+    print!("ran the test");
+    std::io::stdout().flush().unwrap();
+}
diff --git a/src/test/run-make/native-link-modifier-whole-archive/directly_linked_test_plus_whole_archive.rs b/src/test/run-make/native-link-modifier-whole-archive/directly_linked_test_plus_whole_archive.rs
new file mode 100644 (file)
index 0000000..20ed8d9
--- /dev/null
@@ -0,0 +1,7 @@
+use std::io::Write;
+
+#[test]
+fn test_thing() {
+    print!("ran the test");
+    std::io::stdout().flush().unwrap();
+}
index 1badde541128df48928fc69b19f217999fca9939..a254285ab76ce7709fdb8e7a423aa1893e174735 100644 (file)
@@ -14,10 +14,19 @@ ifdef IS_MSVC
 else
        $(CC) "$(TMPDIR)"/extern.obj -shared -o "$(TMPDIR)"/extern.dll
 endif
-       "$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt
 
+       "$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt
 ifdef RUSTC_BLESS_TEST
        cp "$(TMPDIR)"/output.txt output.txt
 else
        $(DIFF) output.txt "$(TMPDIR)"/output.txt
 endif
+
+ifdef IS_MSVC
+       "$(TMPDIR)"/driver true > "$(TMPDIR)"/output.msvc.txt
+ifdef RUSTC_BLESS_TEST
+       cp "$(TMPDIR)"/output.msvc.txt output.msvc.txt
+else
+       $(DIFF) output.msvc.txt "$(TMPDIR)"/output.msvc.txt
+endif
+endif
index 3710507f5e44e5bed528d6aaaa590985e88d5b93..b7f372c6b2b2b500f7684c5e38b9a62f57bc7444 100644 (file)
@@ -1,5 +1,8 @@
 extern crate raw_dylib_alt_calling_convention_test;
 
 fn main() {
-    raw_dylib_alt_calling_convention_test::library_function();
+    raw_dylib_alt_calling_convention_test::library_function(
+        std::env::args().skip(1).next().map_or(
+            false,
+            |s| std::str::FromStr::from_str(&s).unwrap()));
 }
index 8f64abf2fb505cfc4a4018bc66c5ab83b8a54681..0c4d12af9b2ca62a3fa10d407408211a2c9a7c0a 100644 (file)
@@ -121,3 +121,58 @@ __declspec(dllexport) void __fastcall fastcall_fn_9(uint8_t x, double y) {
     printf("fastcall_fn_9(%d, %.1f)\n", x, y);
     fflush(stdout);
 }
+
+// GCC doesn't support vectorcall: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89485
+#ifdef _MSC_VER
+__declspec(dllexport) void __vectorcall vectorcall_fn_1(int i) {
+    printf("vectorcall_fn_1(%d)\n", i);
+    fflush(stdout);
+}
+
+__declspec(dllexport) void __vectorcall vectorcall_fn_2(uint8_t i, float f) {
+    printf("vectorcall_fn_2(%d, %.1f)\n", i, f);
+    fflush(stdout);
+}
+
+__declspec(dllexport) void __vectorcall vectorcall_fn_3(double d) {
+    printf("vectorcall_fn_3(%.1f)\n", d);
+    fflush(stdout);
+}
+
+__declspec(dllexport) void __vectorcall vectorcall_fn_4(uint8_t i, uint8_t j, float f) {
+    printf("vectorcall_fn_4(%d, %d, %.1f)\n", i, j, f);
+    fflush(stdout);
+}
+
+__declspec(dllexport) void __vectorcall vectorcall_fn_5(struct S s, int i) {
+    printf("vectorcall_fn_5(S { x: %d, y: %d }, %d)\n", s.x, s.y, i);
+    fflush(stdout);
+}
+
+__declspec(dllexport) void __vectorcall vectorcall_fn_6(struct S* s) {
+    if (s) {
+        printf("vectorcall_fn_6(S { x: %d, y: %d })\n", s->x, s->y);
+    } else {
+        printf("vectorcall_fn_6(null)\n");
+    }
+    fflush(stdout);
+}
+
+__declspec(dllexport) void __vectorcall vectorcall_fn_7(struct S2 s, int i) {
+    printf("vectorcall_fn_7(S2 { x: %d, y: %d }, %d)\n", s.x, s.y, i);
+    fflush(stdout);
+}
+
+__declspec(dllexport) void __vectorcall vectorcall_fn_8(struct S3 s, struct S3 t) {
+    printf("vectorcall_fn_8(S3 { x: [%d, %d, %d, %d, %d] }, S3 { x: [%d, %d, %d, %d, %d] })\n",
+           s.x[0], s.x[1], s.x[2], s.x[3], s.x[4],
+           t.x[0], t.x[1], t.x[2], t.x[3], t.x[4]
+        );
+    fflush(stdout);
+}
+
+__declspec(dllexport) void __vectorcall vectorcall_fn_9(uint8_t x, double y) {
+    printf("vectorcall_fn_9(%d, %.1f)\n", x, y);
+    fflush(stdout);
+}
+#endif
index 165792b0490156848568a1a3e8beca39dc241bba..b5e9415b2bec312ba2b31effabdbea0bf3ce1e98 100644 (file)
@@ -1,4 +1,5 @@
 #![feature(raw_dylib)]
+#![feature(abi_vectorcall)]
 
 #[repr(C)]
 #[derive(Clone)]
@@ -46,29 +47,60 @@ struct S3 {
     fn fastcall_fn_9(x: u8, y: f64);
 }
 
-pub fn library_function() {
+#[cfg(target_env = "msvc")]
+#[link(name = "extern", kind = "raw-dylib")]
+extern "vectorcall" {
+    fn vectorcall_fn_1(i: i32);
+    fn vectorcall_fn_2(c: u8, f: f32);
+    fn vectorcall_fn_3(d: f64);
+    fn vectorcall_fn_4(i: u8, j: u8, f: f32);
+    fn vectorcall_fn_5(a: S, b: i32);
+    fn vectorcall_fn_6(a: Option<&S>);
+    fn vectorcall_fn_7(a: S2, b: i32);
+    fn vectorcall_fn_8(a: S3, b: S3);
+    fn vectorcall_fn_9(x: u8, y: f64);
+}
+
+pub fn library_function(run_msvc_only: bool) {
     unsafe {
-        stdcall_fn_1(14);
-        stdcall_fn_2(16, 3.5);
-        stdcall_fn_3(3.5);
-        stdcall_fn_4(1, 2, 3.0);
-        stdcall_fn_5(S { x: 1, y: 2 }, 16);
-        stdcall_fn_6(Some(&S { x: 10, y: 12 }));
-        stdcall_fn_7(S2 { x: 15, y: 16 }, 3);
-        stdcall_fn_8(S3 { x: [1, 2, 3, 4, 5] }, S3 { x: [6, 7, 8, 9, 10] });
-        stdcall_fn_9(1, 3.0);
+        if !run_msvc_only {
+            stdcall_fn_1(14);
+            stdcall_fn_2(16, 3.5);
+            stdcall_fn_3(3.5);
+            stdcall_fn_4(1, 2, 3.0);
+            stdcall_fn_5(S { x: 1, y: 2 }, 16);
+            stdcall_fn_6(Some(&S { x: 10, y: 12 }));
+            stdcall_fn_7(S2 { x: 15, y: 16 }, 3);
+            stdcall_fn_8(S3 { x: [1, 2, 3, 4, 5] }, S3 { x: [6, 7, 8, 9, 10] });
+            stdcall_fn_9(1, 3.0);
+
+            fastcall_fn_1(14);
+            fastcall_fn_2(16, 3.5);
+            fastcall_fn_3(3.5);
+            fastcall_fn_4(1, 2, 3.0);
+            fastcall_fn_6(Some(&S { x: 10, y: 12 }));
+            fastcall_fn_8(S3 { x: [1, 2, 3, 4, 5] }, S3 { x: [6, 7, 8, 9, 10] });
+            fastcall_fn_9(1, 3.0);
+        } else {
+            // FIXME: 91167
+            // rustc generates incorrect code for the calls to fastcall_fn_5 and fastcall_fn_7
+            // on i686-pc-windows-gnu; disabling these until the indicated issue is fixed.
+            fastcall_fn_5(S { x: 1, y: 2 }, 16);
+            fastcall_fn_7(S2 { x: 15, y: 16 }, 3);
 
-        fastcall_fn_1(14);
-        fastcall_fn_2(16, 3.5);
-        fastcall_fn_3(3.5);
-        fastcall_fn_4(1, 2, 3.0);
-        // FIXME: 91167
-        // rustc generates incorrect code for the calls to fastcall_fn_5 and fastcall_fn_7
-        // on i686-pc-windows-gnu; commenting these out until the indicated issue is fixed.
-        //fastcall_fn_5(S { x: 1, y: 2 }, 16);
-        fastcall_fn_6(Some(&S { x: 10, y: 12 }));
-        //fastcall_fn_7(S2 { x: 15, y: 16 }, 3);
-        fastcall_fn_8(S3 { x: [1, 2, 3, 4, 5] }, S3 { x: [6, 7, 8, 9, 10] });
-        fastcall_fn_9(1, 3.0);
+            // GCC doesn't support vectorcall: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89485
+            #[cfg(target_env = "msvc")]
+            {
+                vectorcall_fn_1(14);
+                vectorcall_fn_2(16, 3.5);
+                vectorcall_fn_3(3.5);
+                vectorcall_fn_4(1, 2, 3.0);
+                vectorcall_fn_5(S { x: 1, y: 2 }, 16);
+                vectorcall_fn_6(Some(&S { x: 10, y: 12 }));
+                vectorcall_fn_7(S2 { x: 15, y: 16 }, 3);
+                vectorcall_fn_8(S3 { x: [1, 2, 3, 4, 5] }, S3 { x: [6, 7, 8, 9, 10] });
+                vectorcall_fn_9(1, 3.0);
+            }
+        }
     }
 }
diff --git a/src/test/run-make/raw-dylib-alt-calling-convention/output.msvc.txt b/src/test/run-make/raw-dylib-alt-calling-convention/output.msvc.txt
new file mode 100644 (file)
index 0000000..9ddd1b1
--- /dev/null
@@ -0,0 +1,11 @@
+fastcall_fn_5(S { x: 1, y: 2 }, 16)
+fastcall_fn_7(S2 { x: 15, y: 16 }, 3)
+vectorcall_fn_1(14)
+vectorcall_fn_2(16, 3.5)
+vectorcall_fn_3(3.5)
+vectorcall_fn_4(1, 2, 3.0)
+vectorcall_fn_5(S { x: 1, y: 2 }, 16)
+vectorcall_fn_6(S { x: 10, y: 12 })
+vectorcall_fn_7(S2 { x: 15, y: 16 }, 3)
+vectorcall_fn_8(S3 { x: [1, 2, 3, 4, 5] }, S3 { x: [6, 7, 8, 9, 10] })
+vectorcall_fn_9(1, 3.0)
index 72737c086ebe292b9622bd778f4dd0c91f448f7a..ab1dc3a4105b7af70e61558c6c8d325d81af3ddf 100644 (file)
@@ -1,5 +1,7 @@
 #include <stdio.h>
 
+__declspec(dllexport) int extern_variable = 0;
+
 __declspec(dllexport) void extern_fn_1() {
     printf("extern_fn_1\n");
     fflush(stdout);
@@ -10,6 +12,11 @@ __declspec(dllexport) void extern_fn_2() {
     fflush(stdout);
 }
 
+__declspec(dllexport) void print_extern_variable() {
+    printf("extern_variable value: %d\n", extern_variable);
+    fflush(stdout);
+}
+
 __declspec(dllexport) void extern_fn_with_long_name() {
     printf("extern_fn_with_long_name; got the rename\n");
     fflush(stdout);
index 58f7ccb38ce4a35ebf57f72557721cf1efc3769e..74e0d3813d9462dad366b341911f5b07058ace55 100644 (file)
 
 pub fn library_function() {
     #[link(name = "extern_1", kind = "raw-dylib")]
-    extern { fn extern_fn_2(); }
+    extern {
+        fn extern_fn_2();
+        fn print_extern_variable();
+        static mut extern_variable: i32;
+    }
 
     unsafe {
         extern_fn_1();
         extern_fn_2();
         extern_fn_3();
+        extern_variable = 42;
+        print_extern_variable();
+        extern_variable = -42;
+        print_extern_variable();
     }
 }
 
index 7800cba18729023478fbc5c90c98e5bd079963bb..cd9fe47bee473f0a8a41311c38f93a27d2c32def 100644 (file)
@@ -1,3 +1,5 @@
 extern_fn_1
 extern_fn_2; didn't get the rename
 extern_fn_3
+extern_variable value: 42
+extern_variable value: -42
index a9dd6da6616f9ac078294e295a7924f4617d118a..aabf32ff19f0fda0176272649c65bd0278ff4b52 100644 (file)
@@ -3,3 +3,10 @@
 void exported_function() {
     printf("exported_function\n");
 }
+
+int exported_variable = 0;
+
+void print_exported_variable() {
+    printf("exported_variable value: %d\n", exported_variable);
+    fflush(stdout);
+}
index 1a4b4c941b65d05f6d3c693d0a7dada240403d05..5d87c580a54d58cf06740fdaa15c97e014e5dc22 100644 (file)
@@ -1,3 +1,5 @@
 LIBRARY exporter
 EXPORTS
     exported_function @13 NONAME
+    exported_variable @5 NONAME
+    print_exported_variable @9 NONAME
index 20609caa5be21129353c77f56d2a7f6915783247..5efce4e938c8ff6b7f4f808f98d41b54ee1564fa 100644 (file)
@@ -4,10 +4,18 @@
 extern {
     #[link_ordinal(13)]
     fn imported_function();
+    #[link_ordinal(5)]
+    static mut imported_variable: i32;
+    #[link_ordinal(9)]
+    fn print_imported_variable();
 }
 
 pub fn library_function() {
     unsafe {
         imported_function();
+        imported_variable = 42;
+        print_imported_variable();
+        imported_variable = -42;
+        print_imported_variable();
     }
 }
index 2d0ed60f2166788133ef9ec72e76c831c34b8ead..a4b2031d98b486a2a38145605606be4476af7363 100644 (file)
@@ -1 +1,3 @@
 exported_function
+exported_variable value: 42
+exported_variable value: -42
index fb2b4d476355e1dbe7ca21bee6ce5c471a26cb03..dfc094abeb9b4cab0d710946a2cc58f2b9893bd9 100644 (file)
@@ -2,8 +2,6 @@
 // schedule cleanups when auto borrowing trait objects.
 // This program should be valgrind clean.
 
-#![feature(box_syntax)]
-
 static mut DROP_RAN: bool = false;
 
 struct Foo;
@@ -19,7 +17,7 @@ impl Trait for Foo {}
 
 pub fn main() {
     {
-        let _x: &Trait = &*(box Foo as Box<Trait>);
+        let _x: &Trait = &*(Box::new(Foo) as Box<Trait>);
     }
     unsafe {
         assert!(DROP_RAN);
index a4ba5427d4b04d7b5a7cbec44db91bca19509000..5b78f1ec77c54d514c37b18ef180368715e4351d 100644 (file)
@@ -2,15 +2,18 @@
 
 // pretty-expanded FIXME #23616
 
-#![feature(box_syntax)]
-
 pub fn main() {
-    let _: Box<[isize]> =
-        if true { let b: Box<_> = box [1, 2, 3]; b } else { let b: Box<_> = box [1]; b };
+    let _: Box<[isize]> = if true {
+        let b: Box<_> = Box::new([1, 2, 3]);
+        b
+    } else {
+        let b: Box<_> = Box::new([1]);
+        b
+    };
 
     let _: Box<[isize]> = match true {
-        true => { let b: Box<_> = box [1, 2, 3]; b }
-        false => { let b: Box<_> = box [1]; b }
+        true => { let b: Box<_> = Box::new([1, 2, 3]); b }
+        false => { let b: Box<_> = Box::new([1]); b }
     };
 
     // Check we don't get over-keen at propagating coercions in the case of casts.
diff --git a/src/test/rustdoc-gui/item-info-width.goml b/src/test/rustdoc-gui/item-info-width.goml
deleted file mode 100644 (file)
index 8b6d355..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-// This test ensures that the item information don't take 100% of the width if unnecessary.
-goto: file://|DOC_PATH|/lib2/struct.Foo.html
-// We set a fixed size so there is no chance of "random" resize.
-size: (1100, 800)
-// We check that ".item-info" is bigger than its content.
-assert-css: (".item-info", {"width": "790px"})
-assert-css: (".item-info .stab", {"width": "289px"})
-assert-position: (".item-info .stab", {"x": 295})
diff --git a/src/test/rustdoc-gui/item-info.goml b/src/test/rustdoc-gui/item-info.goml
new file mode 100644 (file)
index 0000000..50c45b7
--- /dev/null
@@ -0,0 +1,32 @@
+// This test ensures a few things for item info elements.
+goto: file://|DOC_PATH|/lib2/struct.Foo.html
+// Ensuring that the item information don't take 100% of the width if unnecessary.
+// We set a fixed size so there is no chance of "random" resize.
+size: (1100, 800)
+// We check that ".item-info" is bigger than its content.
+assert-css: (".item-info", {"width": "790px"})
+assert-css: (".item-info .stab", {"width": "289px"})
+assert-position: (".item-info .stab", {"x": 295})
+
+// Now we ensure that they're not rendered on the same line.
+goto: file://|DOC_PATH|/lib2/trait.Trait.html
+// We first ensure that there are two item info on the trait.
+assert-count: ("#main-content > .item-info .stab", 2)
+// They should not have the same `y` position!
+compare-elements-position-false: (
+    "#main-content > .item-info .stab:nth-of-type(1)",
+    "#main-content > .item-info .stab:nth-of-type(2)",
+    ("y"),
+)
+// But they should have the same `x` position.
+compare-elements-position: (
+    "#main-content > .item-info .stab:nth-of-type(1)",
+    "#main-content > .item-info .stab:nth-of-type(2)",
+    ("x"),
+)
+// They are supposed to have the same height too.
+compare-elements-css: (
+    "#main-content > .item-info .stab:nth-of-type(1)",
+    "#main-content > .item-info .stab:nth-of-type(2)",
+    ["height"],
+)
index ca3994a08b269deac3346dfbabf3d410fa521598..f9081189a86005182258302d7bab9481c92c2048 100644 (file)
@@ -7,14 +7,14 @@ size: (1080, 600)
 assert: (".stab.deprecated")
 assert: (".stab.portability")
 
-// make sure that deprecated and portability are different colours
+// make sure that deprecated and portability have the right colors
 assert-css: (
     ".item-table .item-left .stab.deprecated",
-    { "background-color": "rgb(255, 196, 196)" },
+    { "background-color": "rgb(255, 245, 214)" },
 )
 assert-css: (
     ".item-table .item-left .stab.portability",
-    { "background-color": "rgb(243, 223, 255)" },
+    { "background-color": "rgb(255, 245, 214)" },
 )
 
 // table like view
@@ -51,7 +51,7 @@ assert-css: (".item-right.docblock-short", { "padding-left": "32px" })
 compare-elements-position-near: (
     "//*[@class='item-left module-item']//a[text()='replaced_function']",
     ".item-left .stab.deprecated",
-    {"y": 1},
+    {"y": 2},
 )
 compare-elements-position: (
     ".item-left .stab.deprecated",
index 54f3790a7652198942d963d2bc8778c7a1db89d4..782526e29f45e5a7e1484addf630d69514796d47 100644 (file)
@@ -71,7 +71,7 @@ reload:
 click: "#help-button"
 assert-css: (
     "#help-button .popover",
-    {"display": "block", "border-color": "rgb(221, 221, 221)"},
+    {"display": "block", "border-color": "rgb(224, 224, 224)"},
 )
 compare-elements-css: ("#help-button .popover", "#help-button .top", ["border-color"])
 compare-elements-css: ("#help-button .popover", "#help-button .bottom", ["border-color"])
index d645e2370616144c4acc4f5680e1b08be3f3575d..b12eddfd12ad9d1fbf87eab3eba03a40acee9a4b 100644 (file)
@@ -40,7 +40,7 @@ press-key: "ArrowUp"
 press-key: "Enter"
 // Waiting for the search results to appear...
 wait-for: "#titles"
-assert-property: ("#crate-search", {"value": "All crates"})
+assert-property: ("#crate-search", {"value": "all crates"})
 
 // Checking that the URL parameter is taken into account for crate filtering.
 goto: file://|DOC_PATH|/test_docs/index.html?search=test&filter-crate=lib2
@@ -48,8 +48,8 @@ wait-for: "#crate-search"
 assert-property: ("#crate-search", {"value": "lib2"})
 assert-false: "#results .externcrate"
 
-// Checking that the text for the "title" is correct (the "All" comes from the "<select>").
-assert-text: ("#search-settings", "Results for test in All", STARTS_WITH)
+// Checking that the text for the "title" is correct (the "all crates" comes from the "<select>").
+assert-text: (".search-results-title", "Results in all crates", STARTS_WITH)
 
 // Checking the display of the crate filter.
 // We start with the light theme.
@@ -69,15 +69,15 @@ click: "#settings-menu"
 wait-for: "#settings"
 click: "#theme-dark"
 wait-for-css: ("#crate-search", {
-    "border": "1px solid rgb(240, 240, 240)",
-    "color": "rgb(17, 17, 17)",
-    "background-color": "rgb(240, 240, 240)",
+    "border": "1px solid rgb(210, 210, 210)",
+    "color": "rgb(221, 221, 221)",
+    "background-color": "rgb(53, 53, 53)",
 })
 
 // And finally we check the ayu theme.
 click: "#theme-ayu"
 wait-for-css: ("#crate-search", {
-    "border": "1px solid rgb(66, 76, 87)",
-    "color": "rgb(197, 197, 197)",
-    "background-color": "rgb(20, 25, 32)",
+    "border": "1px solid rgb(92, 103, 115)",
+    "color": "rgb(255, 255, 255)",
+    "background-color": "rgb(15, 20, 25)",
 })
index 8464ba7c23cfe8a6cc3e7a5d8c9e5052c769d160..db4907924faf351827c37824d805c92a93d20649 100644 (file)
@@ -4,7 +4,7 @@ size: (900, 1000)
 write: (".search-input", "test")
 // To be SURE that the search will be run.
 press-key: 'Enter'
-wait-for: "#search-settings"
+wait-for: "#crate-search"
 // The width is returned by "getComputedStyle" which returns the exact number instead of the
 // CSS rule which is "50%"...
 assert-css: (".search-results div.desc", {"width": "295px"})
@@ -17,13 +17,9 @@ assert-css: (".search-results div.desc", {"width": "570px"})
 // To do so we need to update the length of one of its `<option>`.
 size: (900, 900)
 
-// First we check the current width and position.
-assert-css: ("#crate-search", {"width": "218px"})
-compare-elements-position-near: (
-    "#crate-search",
-    "#search-settings .search-results-title",
-    {"y": 5},
-)
+// First we check the current width, height and position.
+assert-css: ("#crate-search", {"width": "223px"})
+assert-css: (".search-results-title", {"height": "44px", "width": "336px"})
 
 // Then we update the text of one of the `<option>`.
 text: (
@@ -31,12 +27,8 @@ text: (
     "sdjfaksdjfaksjdbfkadsbfkjsadbfkdsbkfbsadkjfbkdsabfkadsfkjdsafa",
 )
 
-// Then we compare again.
-assert-css: ("#crate-search", {"width": "640px"})
-compare-elements-position-near-false: (
-    "#crate-search",
-    "#search-settings .search-results-title",
-    {"y": 5},
-)
-// And we check that the `<select>` isn't bigger than its container.
+// Then we compare again to confirm the height didn't change.
+assert-css: ("#crate-search", {"width": "527px"})
+assert-css: (".search-results-title", {"height": "44px", "width": "640px"})
+// And we check that the `<select>` isn't bigger than its container (".search-results-title").
 assert-css: ("#search", {"width": "640px"})
diff --git a/src/test/rustdoc-gui/sidebar-mobile-scroll.goml b/src/test/rustdoc-gui/sidebar-mobile-scroll.goml
new file mode 100644 (file)
index 0000000..b3bcea2
--- /dev/null
@@ -0,0 +1,31 @@
+// This test ensures that the mobile sidebar preserves scroll position.
+goto: file://|DOC_PATH|/test_docs/struct.Foo.html
+// Switching to "mobile view" by reducing the width to 600px.
+size: (600, 600)
+assert-css: (".sidebar", {"display": "block", "left": "-1000px"})
+
+// Scroll down.
+scroll-to: "//h2[@id='blanket-implementations']"
+assert-window-property: {"pageYOffset": "702"}
+
+// Open the sidebar menu.
+click: ".sidebar-menu-toggle"
+wait-for-css: (".sidebar", {"left": "0px"})
+
+// We are no longer "scrolled". It's important that the user can't
+// scroll the body at all, but these test scripts are run only in Chrome,
+// and we need to use a more complicated solution to this problem because
+// of Mobile Safari...
+assert-window-property: {"pageYOffset": "0"}
+
+// Close the sidebar menu. Make sure the scroll position gets restored.
+click: ".sidebar-menu-toggle"
+wait-for-css: (".sidebar", {"left": "-1000px"})
+assert-window-property: {"pageYOffset": "702"}
+
+// Now test that scrollability returns when the browser window is just resized.
+click: ".sidebar-menu-toggle"
+wait-for-css: (".sidebar", {"left": "0px"})
+assert-window-property: {"pageYOffset": "0"}
+size: (900, 900)
+assert-window-property: {"pageYOffset": "702"}
index fa322574fdec7bd7140a1c2d32f238d1b565c385..e4662a10ed5da5c4c5c5789eda530d7cf808489a 100644 (file)
@@ -233,6 +233,17 @@ wait-for-css: (".sidebar", {"width": "0px"})
 // The "scrollTop" property should be the same.
 assert-window-property: {"pageYOffset": "2519"}
 
+// We now check that the scroll position is restored if the window is resized.
+size: (500, 700)
+click: "#sidebar-toggle"
+wait-for-css: ("#source-sidebar", {"visibility": "visible"})
+assert-window-property: {"pageYOffset": "0"}
+size: (900, 900)
+assert-window-property: {"pageYOffset": "2519"}
+size: (500, 700)
+click: "#sidebar-toggle"
+wait-for-css: ("#source-sidebar", {"visibility": "hidden"})
+
 // We now check that opening the sidebar and clicking a link will close it.
 // The behavior here on mobile is different than the behavior on desktop,
 // but common sense dictates that if you have a list of files that fills the entire screen, and
index 4546449e102916eb08242cc9040bfaf94f012b36..87f91be3ac82cec26d87785a1afe2debd038aed8 100644 (file)
@@ -30,10 +30,13 @@ impl Foo {
     pub fn a_method(&self) {}
 }
 
+#[doc(cfg(feature = "foo-method"))]
+#[deprecated = "Whatever [`Foo::a_method`](#method.a_method)"]
 pub trait Trait {
     type X;
     const Y: u32;
 
+    #[deprecated = "Whatever [`Foo`](#tadam)"]
     fn foo() {}
 }
 
index b84c2f7c6ac39e440090cfb83ebbe7e2ed9c4147..8d1141b58648d39102cdaf9ea9a3d0be1878dd88 100644 (file)
@@ -7,8 +7,14 @@ mod usize {}
 
 // @set local_crate_id = primitive.json "$.index[*][?(@.name=='primitive')].crate_id"
 
-// @has - "$.index[*][?(@.name=='log10')]"
-// @!is - "$.index[*][?(@.name=='log10')].crate_id" $local_crate_id
+// @has - "$.index[*][?(@.name=='ilog10')]"
+// @!is - "$.index[*][?(@.name=='ilog10')].crate_id" $local_crate_id
 // @has - "$.index[*][?(@.name=='checked_add')]"
 // @!is - "$.index[*][?(@.name=='checked_add')]" $local_crate_id
 // @!has - "$.index[*][?(@.name=='is_ascii_uppercase')]"
+
+// @is - "$.index[*][?(@.kind=='import' && @.inner.name=='my_i32')].inner.id" null
+pub use i32 as my_i32;
+
+// @is - "$.index[*][?(@.kind=='import' && @.inner.name=='u32')].inner.id" null
+pub use u32;
index f53dc03f4b47fad5e7fed37d995578ac4c3dba72..c18b54d1fdf0ed18bba992190874850bed4e7a16 100644 (file)
@@ -1,8 +1,13 @@
 // ignore-tidy-linelength
+use std::fmt::Debug;
 
-// @count dyn.json "$.index[*][?(@.name=='dyn')].inner.items" 1
+// @count dyn.json "$.index[*][?(@.name=='dyn')].inner.items[*]" 3
 // @set sync_int_gen = - "$.index[*][?(@.name=='SyncIntGen')].id"
-// @is - "$.index[*][?(@.name=='dyn')].inner.items[0]" $sync_int_gen
+// @set ref_fn       = - "$.index[*][?(@.name=='RefFn')].id"
+// @set weird_order  = - "$.index[*][?(@.name=='WeirdOrder')].id"
+// @has - "$.index[*][?(@.name=='dyn')].inner.items[*]" $sync_int_gen
+// @has - "$.index[*][?(@.name=='dyn')].inner.items[*]" $ref_fn
+// @has - "$.index[*][?(@.name=='dyn')].inner.items[*]" $weird_order
 
 // @is    - "$.index[*][?(@.name=='SyncIntGen')].kind" \"typedef\"
 // @is    - "$.index[*][?(@.name=='SyncIntGen')].inner.generics" '{"params": [], "where_predicates": []}'
 // @is    - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.name" \"Box\"
 // @is    - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.bindings" []
 // @count - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args" 1
-// @is    - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.kind" \"resolved_path\"
-// @is    - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.kind" \"resolved_path\"
-// @is    - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.name" \"Fn\"
-// @count - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[*]" 3
-// @is    - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[0].trait_bound.trait.inner.name" \"Send\"
-// @is    - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[1].trait_bound.trait.inner.name" \"Sync\"
-// @is    - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[2]" "{\"outlives\": \"'static\"}"
-// @is    - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.args" '{"parenthesized": {"inputs": [],"output": {"inner": "i32","kind": "primitive"}}}'
+// @is    - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.kind" \"dyn_trait\"
+// @is    - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.lifetime" \"\'static\"
+// @count - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[*]" 3
+// @is    - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[0].generic_params" []
+// @is    - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[1].generic_params" []
+// @is    - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[2].generic_params" []
+// @is    - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[0].trait.inner.name" '"Fn"'
+// @is    - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[1].trait.inner.name" '"Send"'
+// @is    - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[2].trait.inner.name" '"Sync"'
+// @is    - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[0].trait.inner.args" '{"parenthesized": {"inputs": [],"output": {"inner": "i32","kind": "primitive"}}}'
 pub type SyncIntGen = Box<dyn Fn() -> i32 + Send + Sync + 'static>;
+
+// @is - "$.index[*][?(@.name=='RefFn')].kind" \"typedef\"
+// @is - "$.index[*][?(@.name=='RefFn')].inner.generics" '{"params": [{"kind": {"lifetime": {"outlives": []}},"name": "'\''a"}],"where_predicates": []}'
+// @is - "$.index[*][?(@.name=='RefFn')].inner.type.kind" '"borrowed_ref"'
+// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.mutable" 'false'
+// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.lifetime" "\"'a\""
+// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.kind" '"dyn_trait"'
+// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.lifetime" null
+// @count - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[*]" 1
+// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].generic_params" '[{"kind": {"lifetime": {"outlives": []}},"name": "'\''b"}]'
+// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].trait.kind" '"resolved_path"'
+// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].trait.inner.name" '"Fn"'
+// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].trait.inner.args.parenthesized.inputs[0].kind" '"borrowed_ref"'
+// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].trait.inner.args.parenthesized.inputs[0].inner.lifetime" "\"'b\""
+// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].trait.inner.args.parenthesized.output.kind" '"borrowed_ref"'
+// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].trait.inner.args.parenthesized.output.inner.lifetime" "\"'b\""
+pub type RefFn<'a> = &'a dyn for<'b> Fn(&'b i32) -> &'b i32;
+
+// @is    - "$.index[*][?(@.name=='WeirdOrder')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[0].trait.inner.name" '"Send"'
+// @is    - "$.index[*][?(@.name=='WeirdOrder')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[1].trait.inner.name" '"Debug"'
+pub type WeirdOrder = Box<dyn Send + Debug>;
diff --git a/src/test/rustdoc-json/type/hrtb.rs b/src/test/rustdoc-json/type/hrtb.rs
new file mode 100644 (file)
index 0000000..9311737
--- /dev/null
@@ -0,0 +1,26 @@
+// ignore-tidy-linelength
+
+// @has hrtb.json
+
+// @is - "$.index[*][?(@.name=='genfn')].inner.generics.where_predicates[0].bound_predicate.type" '{"inner": "F","kind": "generic"}'
+// @is - "$.index[*][?(@.name=='genfn')].inner.generics.where_predicates[0].bound_predicate.generic_params" '[{"kind": {"lifetime": {"outlives": []}},"name": "'\''a"},{"kind": {"lifetime": {"outlives": []}},"name": "'\''b"}]'
+pub fn genfn<F>(f: F)
+where
+    for<'a, 'b> F: Fn(&'a i32, &'b i32),
+{
+    let zero = 0;
+    f(&zero, &zero);
+}
+
+// @is - "$.index[*][?(@.name=='dynfn')].inner.generics" '{"params": [], "where_predicates": []}'
+// @is - "$.index[*][?(@.name=='dynfn')].inner.generics" '{"params": [], "where_predicates": []}'
+// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].kind" '"borrowed_ref"'
+// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.kind" '"dyn_trait"'
+// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.inner.lifetime" null
+// @count - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.inner.traits[*]" 1
+// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.inner.traits[0].generic_params" '[{"kind": {"lifetime": {"outlives": []}},"name": "'\''a"},{"kind": {"lifetime": {"outlives": []}},"name": "'\''b"}]'
+// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.inner.traits[0].trait.inner.name" '"Fn"'
+pub fn dynfn(f: &dyn for<'a, 'b> Fn(&'a i32, &'b i32)) {
+    let zero = 0;
+    f(&zero, &zero);
+}
index 175626f49dcac74bd2758d1179df2087a1ebe56e..85c9516236c94484872270dff3059572432e9d62 100644 (file)
@@ -1,4 +1,4 @@
-error: `#[doc(alias = "...")]` isn't allowed on extern block
+error: `#[doc(alias = "...")]` isn't allowed on foreign module
   --> $DIR/check-doc-alias-attr-location.rs:7:7
    |
 LL | #[doc(alias = "foo")]
index 731cc8ba61750873417cdf2edc06b7450538c876..56d59164d68f1d880135b8344f6167a2a7501f77 100644 (file)
@@ -1,4 +1,4 @@
-#![feature(box_syntax)]
-#![feature(box_syntax)] //~ ERROR
+#![feature(rustdoc_internals)]
+#![feature(rustdoc_internals)] //~ ERROR
 
 pub fn foo() {}
index 9707895ff3dfe9edcea5ede5b23d71f53e512e5b..83f4e87c6edebad29ce5a586186c2d43b6b4686b 100644 (file)
@@ -1,8 +1,8 @@
-error[E0636]: the feature `box_syntax` has already been declared
+error[E0636]: the feature `rustdoc_internals` has already been declared
   --> $DIR/rustc-check-passes.rs:2:12
    |
-LL | #![feature(box_syntax)]
-   |            ^^^^^^^^^^
+LL | #![feature(rustdoc_internals)]
+   |            ^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/rustdoc-ui/scrape-examples-fail-if-type-error.rs b/src/test/rustdoc-ui/scrape-examples-fail-if-type-error.rs
new file mode 100644 (file)
index 0000000..8f4fde9
--- /dev/null
@@ -0,0 +1,7 @@
+// check-fail
+// compile-flags: -Z unstable-options --scrape-examples-output-path {{build-base}}/t.calls --scrape-examples-target-crate foobar
+
+pub fn foo() {
+  INVALID_FUNC();
+  //~^ ERROR could not resolve path
+}
diff --git a/src/test/rustdoc-ui/scrape-examples-fail-if-type-error.stderr b/src/test/rustdoc-ui/scrape-examples-fail-if-type-error.stderr
new file mode 100644 (file)
index 0000000..750aa32
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0433]: failed to resolve: could not resolve path `INVALID_FUNC`
+  --> $DIR/scrape-examples-fail-if-type-error.rs:5:3
+   |
+LL |   INVALID_FUNC();
+   |   ^^^^^^^^^^^^ could not resolve path `INVALID_FUNC`
+   |
+   = note: this error was originally ignored because you are running `rustdoc`
+   = note: try running again with `rustc` or `cargo check` and you may get a more detailed error
+
+error: Compilation failed, aborting rustdoc
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/rustdoc/auxiliary/issue-100204-aux.rs b/src/test/rustdoc/auxiliary/issue-100204-aux.rs
new file mode 100644 (file)
index 0000000..df1b590
--- /dev/null
@@ -0,0 +1,13 @@
+#![crate_name="first"]
+
+pub mod prelude {
+    pub use crate::Bot;
+}
+
+pub struct Bot;
+
+impl Bot {
+    pub fn new() -> Bot {
+        Bot
+    }
+}
diff --git a/src/test/rustdoc/auxiliary/issue-99734-aux.rs b/src/test/rustdoc/auxiliary/issue-99734-aux.rs
new file mode 100644 (file)
index 0000000..234d55e
--- /dev/null
@@ -0,0 +1,11 @@
+pub struct Option;
+impl Option {
+    pub fn unwrap(self) {}
+}
+
+/// [`Option::unwrap`]
+pub mod task {}
+
+extern "C" {
+    pub fn main() -> std::ffi::c_int;
+}
diff --git a/src/test/rustdoc/empty-impl-block-private-with-doc.rs b/src/test/rustdoc/empty-impl-block-private-with-doc.rs
new file mode 100644 (file)
index 0000000..4397199
--- /dev/null
@@ -0,0 +1,44 @@
+// compile-flags: --document-private-items
+
+#![feature(inherent_associated_types)]
+#![allow(incomplete_features)]
+#![crate_name = "foo"]
+
+// @has 'foo/struct.Foo.html'
+pub struct Foo;
+
+// There are 3 impl blocks with public item and one that should not be displayed
+// by default because it only contains private items (but not in this case because
+// we used `--document-private-items`).
+// @count - '//*[@class="impl has-srclink"]' 'impl Foo' 4
+
+// Impl block only containing private items should not be displayed unless the
+// `--document-private-items` flag is used.
+/// Private
+impl Foo {
+    const BAR: u32 = 0;
+    type FOO = i32;
+    fn hello() {}
+}
+
+// But if any element of the impl block is public, it should be displayed.
+/// Not private
+impl Foo {
+    pub const BAR: u32 = 0;
+    type FOO = i32;
+    fn hello() {}
+}
+
+/// Not private
+impl Foo {
+    const BAR: u32 = 0;
+    pub type FOO = i32;
+    fn hello() {}
+}
+
+/// Not private
+impl Foo {
+    const BAR: u32 = 0;
+    type FOO = i32;
+    pub fn hello() {}
+}
diff --git a/src/test/rustdoc/empty-impl-block-private.rs b/src/test/rustdoc/empty-impl-block-private.rs
new file mode 100644 (file)
index 0000000..5caf020
--- /dev/null
@@ -0,0 +1,40 @@
+#![feature(inherent_associated_types)]
+#![allow(incomplete_features)]
+#![crate_name = "foo"]
+
+// @has 'foo/struct.Foo.html'
+pub struct Foo;
+
+// There are 3 impl blocks with public item and one that should not be displayed
+// because it only contains private items.
+// @count - '//*[@class="impl has-srclink"]' 'impl Foo' 3
+
+// Impl block only containing private items should not be displayed.
+/// Private
+impl Foo {
+    const BAR: u32 = 0;
+    type FOO = i32;
+    fn hello() {}
+}
+
+// But if any element of the impl block is public, it should be displayed.
+/// Not private
+impl Foo {
+    pub const BAR: u32 = 0;
+    type FOO = i32;
+    fn hello() {}
+}
+
+/// Not private
+impl Foo {
+    const BAR: u32 = 0;
+    pub type FOO = i32;
+    fn hello() {}
+}
+
+/// Not private
+impl Foo {
+    const BAR: u32 = 0;
+    type FOO = i32;
+    pub fn hello() {}
+}
diff --git a/src/test/rustdoc/fn-bound.rs b/src/test/rustdoc/fn-bound.rs
new file mode 100644 (file)
index 0000000..4c4ffdd
--- /dev/null
@@ -0,0 +1,21 @@
+// Regression test for #100143
+
+use std::iter::Peekable;
+
+pub struct Span<F: Fn(&i32)> {
+    inner: Peekable<ConditionalIterator<F>>,
+}
+
+pub struct ConditionalIterator<F> {
+    f: F,
+}
+
+
+// @has 'fn_bound/struct.ConditionalIterator.html' '//h3[@class="code-header in-band"]' 'impl<F: Fn(&i32)> Iterator for ConditionalIterator<F>'
+impl<F: Fn(&i32)> Iterator for ConditionalIterator<F> {
+    type Item = ();
+
+    fn next(&mut self) -> Option<Self::Item> {
+        todo!()
+    }
+}
diff --git a/src/test/rustdoc/impossible-default.rs b/src/test/rustdoc/impossible-default.rs
new file mode 100644 (file)
index 0000000..24d6e3b
--- /dev/null
@@ -0,0 +1,20 @@
+#![crate_name = "foo"]
+
+// Check that default trait items that are impossible to satisfy
+
+pub trait Foo {
+    fn needs_sized(&self)
+    where
+        Self: Sized,
+    {}
+
+    fn no_needs_sized(&self) {}
+}
+
+// @!has foo/struct.Bar.html '//*[@id="method.needs_sized"]//h4[@class="code-header"]' \
+// "fn needs_sized"
+// @has foo/struct.Bar.html '//*[@id="method.no_needs_sized"]//h4[@class="code-header"]' \
+// "fn no_needs_sized"
+pub struct Bar([u8]);
+
+impl Foo for Bar {}
diff --git a/src/test/rustdoc/intra-doc/assoc-reexport-super.rs b/src/test/rustdoc/intra-doc/assoc-reexport-super.rs
new file mode 100644 (file)
index 0000000..a7bc1c6
--- /dev/null
@@ -0,0 +1,20 @@
+// Regression test for #93205
+
+#![crate_name = "foo"]
+
+mod generated {
+    pub struct MyNewType;
+    impl MyNewType {
+        pub const FOO: Self = Self;
+    }
+}
+
+pub use generated::MyNewType;
+
+mod prelude {
+    impl super::MyNewType {
+        /// An alias for [`Self::FOO`].
+        // @has 'foo/struct.MyNewType.html' '//a[@href="struct.MyNewType.html#associatedconstant.FOO"]' 'Self::FOO'
+        pub const FOO2: Self = Self::FOO;
+    }
+}
diff --git a/src/test/rustdoc/issue-100204-inline-impl-through-glob-import.rs b/src/test/rustdoc/issue-100204-inline-impl-through-glob-import.rs
new file mode 100644 (file)
index 0000000..3e20c5c
--- /dev/null
@@ -0,0 +1,14 @@
+// aux-build:issue-100204-aux.rs
+// build-aux-docs
+// ignore-cross-compile
+
+#![crate_name="second"]
+
+extern crate first;
+
+pub mod prelude {}
+
+// @has first/struct.Bot.html '//h4[@class="code-header"]' 'pub fn new() -> Bot'
+// @has second/struct.Bot.html '//h4[@class="code-header"]' 'pub fn new() -> Bot'
+#[doc(inline)]
+pub use first::*;
diff --git a/src/test/rustdoc/issue-99734-multiple-foreigns-w-same-name.rs b/src/test/rustdoc/issue-99734-multiple-foreigns-w-same-name.rs
new file mode 100644 (file)
index 0000000..3208fea
--- /dev/null
@@ -0,0 +1,16 @@
+// aux-build:issue-99734-aux.rs
+// build-aux-docs
+// ignore-cross-compile
+
+#![crate_name = "foo"]
+
+#[macro_use]
+extern crate issue_99734_aux;
+
+pub use issue_99734_aux::*;
+
+// @count foo/index.html '//a[@class="fn"][@title="foo::main fn"]' 1
+
+extern "C" {
+    pub fn main() -> std::ffi::c_int;
+}
diff --git a/src/test/rustdoc/issue-99734-multiple-mods-w-same-name.rs b/src/test/rustdoc/issue-99734-multiple-mods-w-same-name.rs
new file mode 100644 (file)
index 0000000..b2f9b8b
--- /dev/null
@@ -0,0 +1,14 @@
+// aux-build:issue-99734-aux.rs
+// build-aux-docs
+// ignore-cross-compile
+
+#![crate_name = "foo"]
+
+#[macro_use]
+extern crate issue_99734_aux;
+
+pub use issue_99734_aux::*;
+
+// @count foo/index.html '//a[@class="mod"][@title="foo::task mod"]' 1
+
+pub mod task {}
index a679b7b4e191329ada37b4588c47d33ca257931b..0d9c9350efca4a0bbf7cb7bd93328e9bf509be9f 100644 (file)
@@ -74,10 +74,10 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) {
             2 => {
                 let seg = PathSegment::from_ident(Ident::from_str("x"));
                 iter_exprs(depth - 1, &mut |e| {
-                    g(ExprKind::MethodCall(seg.clone(), vec![e, make_x()], DUMMY_SP))
+                    g(ExprKind::MethodCall(seg.clone(), e, vec![make_x()], DUMMY_SP))
                 });
                 iter_exprs(depth - 1, &mut |e| {
-                    g(ExprKind::MethodCall(seg.clone(), vec![make_x(), e], DUMMY_SP))
+                    g(ExprKind::MethodCall(seg.clone(), make_x(), vec![e], DUMMY_SP))
                 });
             }
             3..=8 => {
index f77f40998de012ec0abdf81e11e41e59d453da54..9e490e27ad17df34a21c18ac29ceae61d154b9e6 100644 (file)
@@ -8,7 +8,7 @@
 #![feature(repr_align)]
 
 #[repr(align(16))]
-pub struct A(i64);
+pub struct A(#[allow(unused_tuple_struct_fields)] i64);
 
 #[allow(improper_ctypes_definitions)]
 pub extern "C" fn foo(x: A) {}
index c9b4abbfd3fd3da70de7d7755909adcb979bb5a4..54b7c8bb9c6f81af6fa62276202c17c1c53e73de 100644 (file)
@@ -92,7 +92,7 @@ fn panic(panic_info: &core::panic::PanicInfo) -> ! {
 extern fn rust_eh_personality() {}
 
 #[derive(Debug)]
-struct Page([[u64; 32]; 16]);
+struct Page(#[allow(unused_tuple_struct_fields)] [[u64; 32]; 16]);
 
 #[start]
 pub fn main(_argc: isize, _argv: *const *const u8) -> isize {
index d6cd4a6af855fecd6b44f6dc5e600364303c1beb..ffa331a992c8b42265769f2763721fd1a9c498ff 100644 (file)
@@ -79,7 +79,7 @@ fn panic(panic_info: &core::panic::PanicInfo) -> ! {
 extern fn rust_eh_personality() {}
 
 #[derive(Debug)]
-struct Page([[u64; 32]; 16]);
+struct Page(#[allow(unused_tuple_struct_fields)] [[u64; 32]; 16]);
 
 #[start]
 pub fn main(_argc: isize, _argv: *const *const u8) -> isize {
diff --git a/src/test/ui/argument-suggestions/issue-100154.rs b/src/test/ui/argument-suggestions/issue-100154.rs
new file mode 100644 (file)
index 0000000..4446b4b
--- /dev/null
@@ -0,0 +1,7 @@
+fn foo(i: impl std::fmt::Display) {}
+
+fn main() {
+    foo::<()>(());
+    //~^ ERROR this function takes 0 generic arguments but 1 generic argument was supplied
+    //~| ERROR `()` doesn't implement `std::fmt::Display`
+}
diff --git a/src/test/ui/argument-suggestions/issue-100154.stderr b/src/test/ui/argument-suggestions/issue-100154.stderr
new file mode 100644 (file)
index 0000000..1499229
--- /dev/null
@@ -0,0 +1,35 @@
+error[E0107]: this function takes 0 generic arguments but 1 generic argument was supplied
+  --> $DIR/issue-100154.rs:4:5
+   |
+LL |     foo::<()>(());
+   |     ^^^------ help: remove these generics
+   |     |
+   |     expected 0 generic arguments
+   |
+note: function defined here, with 0 generic parameters
+  --> $DIR/issue-100154.rs:1:4
+   |
+LL | fn foo(i: impl std::fmt::Display) {}
+   |    ^^^
+   = note: `impl Trait` cannot be explicitly specified as a generic argument
+
+error[E0277]: `()` doesn't implement `std::fmt::Display`
+  --> $DIR/issue-100154.rs:4:15
+   |
+LL |     foo::<()>(());
+   |     --------- ^^ `()` cannot be formatted with the default formatter
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `std::fmt::Display` is not implemented for `()`
+   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
+note: required by a bound in `foo`
+  --> $DIR/issue-100154.rs:1:16
+   |
+LL | fn foo(i: impl std::fmt::Display) {}
+   |                ^^^^^^^^^^^^^^^^^ required by this bound in `foo`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0107, E0277.
+For more information about an error, try `rustc --explain E0107`.
index dfa4c720bb09aeaf0aa13b3ef9f5a7375a1b22a7..c10f779b1f6172f3dd543756c99cf65c46ff3839 100644 (file)
@@ -1,7 +1,7 @@
 // run-pass
 
 #[derive(Debug)]
-struct Foo(Box<[u8]>);
+struct Foo(#[allow(unused_tuple_struct_fields)] Box<[u8]>);
 
 pub fn main() {
     println!("{:?}", Foo(Box::new([0, 1, 2])));
index 867e0433eae1bece783672fd52c8dcf4c2ebac31..21bcc4a9c7badd4ddbc01351734661187eb6d68a 100644 (file)
@@ -36,41 +36,41 @@ LL |         asm!("{}", out(reg) foo, clobber_abi("C"));
    |                    |
    |                    generic outputs
 
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nomem`
+error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
   --> $DIR/bad-options.rs:28:25
    |
 LL | global_asm!("", options(nomem));
-   |                         ^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+   |                         ^^^^^ expected one of `)`, `att_syntax`, or `raw`
 
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `readonly`
+error: expected one of `)`, `att_syntax`, or `raw`, found `readonly`
   --> $DIR/bad-options.rs:30:25
    |
 LL | global_asm!("", options(readonly));
-   |                         ^^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+   |                         ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
 
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `noreturn`
+error: expected one of `)`, `att_syntax`, or `raw`, found `noreturn`
   --> $DIR/bad-options.rs:32:25
    |
 LL | global_asm!("", options(noreturn));
-   |                         ^^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+   |                         ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
 
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `pure`
+error: expected one of `)`, `att_syntax`, or `raw`, found `pure`
   --> $DIR/bad-options.rs:34:25
    |
 LL | global_asm!("", options(pure));
-   |                         ^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+   |                         ^^^^ expected one of `)`, `att_syntax`, or `raw`
 
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nostack`
+error: expected one of `)`, `att_syntax`, or `raw`, found `nostack`
   --> $DIR/bad-options.rs:36:25
    |
 LL | global_asm!("", options(nostack));
-   |                         ^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+   |                         ^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
 
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `preserves_flags`
+error: expected one of `)`, `att_syntax`, or `raw`, found `preserves_flags`
   --> $DIR/bad-options.rs:38:25
    |
 LL | global_asm!("", options(preserves_flags));
-   |                         ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+   |                         ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
 
 error: invalid ABI for `clobber_abi`
   --> $DIR/bad-options.rs:20:18
index f2013046cda4207043b3e2f6fd5146a170d39528..804966b06ba7dfdf1f19b368bc5c85f4fb61dcb2 100644 (file)
@@ -260,23 +260,23 @@ error: expected one of `,`, `.`, `?`, or an operator, found `FOO`
 LL | global_asm!("{}", const(reg) FOO);
    |                              ^^^ expected one of `,`, `.`, `?`, or an operator
 
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `FOO`
+error: expected one of `)`, `att_syntax`, or `raw`, found `FOO`
   --> $DIR/parse-error.rs:102:25
    |
 LL | global_asm!("", options(FOO));
-   |                         ^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+   |                         ^^^ expected one of `)`, `att_syntax`, or `raw`
 
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nomem`
+error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
   --> $DIR/parse-error.rs:104:25
    |
 LL | global_asm!("", options(nomem FOO));
-   |                         ^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+   |                         ^^^^^ expected one of `)`, `att_syntax`, or `raw`
 
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nomem`
+error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
   --> $DIR/parse-error.rs:106:25
    |
 LL | global_asm!("", options(nomem, FOO));
-   |                         ^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+   |                         ^^^^^ expected one of `)`, `att_syntax`, or `raw`
 
 error: arguments are not allowed after options
   --> $DIR/parse-error.rs:108:30
index 1828066b692a4a840e99d4b3c8b7c4edd87163b2..f90967fbe6e43ae65e6776da071f80d0fca8da84 100644 (file)
@@ -57,13 +57,11 @@ LL |     a + 1
 error[E0787]: naked functions must contain a single asm block
   --> $DIR/naked-functions.rs:33:1
    |
-LL | / pub unsafe extern "C" fn inc(a: u32) -> u32 {
-LL | |
-LL | |     a + 1
-   | |     ----- non-asm is unsupported in naked functions
-LL | |
-LL | | }
-   | |_^
+LL | pub unsafe extern "C" fn inc(a: u32) -> u32 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL |     a + 1
+   |     ----- non-asm is unsupported in naked functions
 
 error: referencing function parameters is not allowed in naked functions
   --> $DIR/naked-functions.rs:42:31
@@ -82,12 +80,11 @@ LL |     asm!("/* {0} */", in(reg) a, options(noreturn));
 error[E0787]: naked functions must contain a single asm block
   --> $DIR/naked-functions.rs:48:1
    |
-LL | / pub unsafe extern "C" fn inc_closure(a: u32) -> u32 {
-LL | |
-LL | |     (|| a + 1)()
-   | |     ------------ non-asm is unsupported in naked functions
-LL | | }
-   | |_^
+LL | pub unsafe extern "C" fn inc_closure(a: u32) -> u32 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL |     (|| a + 1)()
+   |     ------------ non-asm is unsupported in naked functions
 
 error[E0787]: only `const` and `sym` operands are supported in naked functions
   --> $DIR/naked-functions.rs:65:10
@@ -124,30 +121,25 @@ LL |          sym G, options(noreturn),
 error[E0787]: naked functions must contain a single asm block
   --> $DIR/naked-functions.rs:54:1
    |
-LL | / pub unsafe extern "C" fn unsupported_operands() {
-LL | |
-LL | |     let mut a = 0usize;
-   | |     ------------------- non-asm is unsupported in naked functions
-LL | |     let mut b = 0usize;
-   | |     ------------------- non-asm is unsupported in naked functions
-LL | |     let mut c = 0usize;
-   | |     ------------------- non-asm is unsupported in naked functions
-LL | |     let mut d = 0usize;
-   | |     ------------------- non-asm is unsupported in naked functions
-LL | |     let mut e = 0usize;
-   | |     ------------------- non-asm is unsupported in naked functions
-...  |
-LL | |     );
-LL | | }
-   | |_^
+LL | pub unsafe extern "C" fn unsupported_operands() {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL |     let mut a = 0usize;
+   |     ------------------- non-asm is unsupported in naked functions
+LL |     let mut b = 0usize;
+   |     ------------------- non-asm is unsupported in naked functions
+LL |     let mut c = 0usize;
+   |     ------------------- non-asm is unsupported in naked functions
+LL |     let mut d = 0usize;
+   |     ------------------- non-asm is unsupported in naked functions
+LL |     let mut e = 0usize;
+   |     ------------------- non-asm is unsupported in naked functions
 
 error[E0787]: naked functions must contain a single asm block
   --> $DIR/naked-functions.rs:77:1
    |
-LL | / pub extern "C" fn missing_assembly() {
-LL | |
-LL | | }
-   | |_^
+LL | pub extern "C" fn missing_assembly() {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0787]: asm in naked functions must use `noreturn` option
   --> $DIR/naked-functions.rs:84:5
@@ -185,20 +177,17 @@ LL |     asm!("", options(noreturn));
 error[E0787]: naked functions must contain a single asm block
   --> $DIR/naked-functions.rs:82:1
    |
-LL | / pub extern "C" fn too_many_asm_blocks() {
-LL | |
-LL | |     asm!("");
-LL | |
-LL | |     asm!("");
-   | |     -------- multiple asm blocks are unsupported in naked functions
-LL | |
-LL | |     asm!("");
-   | |     -------- multiple asm blocks are unsupported in naked functions
-LL | |
-LL | |     asm!("", options(noreturn));
-   | |     --------------------------- multiple asm blocks are unsupported in naked functions
-LL | | }
-   | |_^
+LL | pub extern "C" fn too_many_asm_blocks() {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL |     asm!("");
+   |     -------- multiple asm blocks are unsupported in naked functions
+LL |
+LL |     asm!("");
+   |     -------- multiple asm blocks are unsupported in naked functions
+LL |
+LL |     asm!("", options(noreturn));
+   |     --------------------------- multiple asm blocks are unsupported in naked functions
 
 error: referencing function parameters is not allowed in naked functions
   --> $DIR/naked-functions.rs:97:11
@@ -211,13 +200,11 @@ LL |         *&y
 error[E0787]: naked functions must contain a single asm block
   --> $DIR/naked-functions.rs:95:5
    |
-LL | /     pub extern "C" fn inner(y: usize) -> usize {
-LL | |
-LL | |         *&y
-   | |         --- non-asm is unsupported in naked functions
-LL | |
-LL | |     }
-   | |_____^
+LL |     pub extern "C" fn inner(y: usize) -> usize {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL |         *&y
+   |         --- non-asm is unsupported in naked functions
 
 error[E0787]: asm options unsupported in naked functions: `nomem`, `preserves_flags`
   --> $DIR/naked-functions.rs:105:5
@@ -249,18 +236,18 @@ LL |     asm!("", options(noreturn, may_unwind));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: Rust ABI is unsupported in naked functions
-  --> $DIR/naked-functions.rs:124:15
+  --> $DIR/naked-functions.rs:124:1
    |
 LL | pub unsafe fn default_abi() {
-   |               ^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `#[warn(undefined_naked_function_abi)]` on by default
 
 warning: Rust ABI is unsupported in naked functions
-  --> $DIR/naked-functions.rs:130:15
+  --> $DIR/naked-functions.rs:130:1
    |
 LL | pub unsafe fn rust_abi() {
-   |               ^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: naked functions cannot be inlined
   --> $DIR/naked-functions.rs:170:1
index a63c42aac27377d543b3385867ea922774c2036b..e2351840eef211612b880b82ec4c538f50e3cfeb 100644 (file)
@@ -45,41 +45,41 @@ LL |         asm!("{}", out(reg) foo, clobber_abi("C"), clobber_abi("C"));
    |                    |             clobber_abi
    |                    generic outputs
 
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nomem`
+error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
   --> $DIR/bad-options.rs:31:25
    |
 LL | global_asm!("", options(nomem));
-   |                         ^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+   |                         ^^^^^ expected one of `)`, `att_syntax`, or `raw`
 
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `readonly`
+error: expected one of `)`, `att_syntax`, or `raw`, found `readonly`
   --> $DIR/bad-options.rs:33:25
    |
 LL | global_asm!("", options(readonly));
-   |                         ^^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+   |                         ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
 
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `noreturn`
+error: expected one of `)`, `att_syntax`, or `raw`, found `noreturn`
   --> $DIR/bad-options.rs:35:25
    |
 LL | global_asm!("", options(noreturn));
-   |                         ^^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+   |                         ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
 
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `pure`
+error: expected one of `)`, `att_syntax`, or `raw`, found `pure`
   --> $DIR/bad-options.rs:37:25
    |
 LL | global_asm!("", options(pure));
-   |                         ^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+   |                         ^^^^ expected one of `)`, `att_syntax`, or `raw`
 
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nostack`
+error: expected one of `)`, `att_syntax`, or `raw`, found `nostack`
   --> $DIR/bad-options.rs:39:25
    |
 LL | global_asm!("", options(nostack));
-   |                         ^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+   |                         ^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
 
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `preserves_flags`
+error: expected one of `)`, `att_syntax`, or `raw`, found `preserves_flags`
   --> $DIR/bad-options.rs:41:25
    |
 LL | global_asm!("", options(preserves_flags));
-   |                         ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+   |                         ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
 
 error: invalid ABI for `clobber_abi`
   --> $DIR/bad-options.rs:20:18
index 1fd317a96a8a6c09f5ab3c44e959f0ba4a497ba6..57702c37b7ce2ff29554eb5bc166d5b66fbca13d 100644 (file)
@@ -266,23 +266,23 @@ error: expected one of `,`, `.`, `?`, or an operator, found `FOO`
 LL | global_asm!("{}", const(reg) FOO);
    |                              ^^^ expected one of `,`, `.`, `?`, or an operator
 
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `FOO`
+error: expected one of `)`, `att_syntax`, or `raw`, found `FOO`
   --> $DIR/parse-error.rs:104:25
    |
 LL | global_asm!("", options(FOO));
-   |                         ^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+   |                         ^^^ expected one of `)`, `att_syntax`, or `raw`
 
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nomem`
+error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
   --> $DIR/parse-error.rs:106:25
    |
 LL | global_asm!("", options(nomem FOO));
-   |                         ^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+   |                         ^^^^^ expected one of `)`, `att_syntax`, or `raw`
 
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nomem`
+error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
   --> $DIR/parse-error.rs:108:25
    |
 LL | global_asm!("", options(nomem, FOO));
-   |                         ^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+   |                         ^^^^^ expected one of `)`, `att_syntax`, or `raw`
 
 error: arguments are not allowed after options
   --> $DIR/parse-error.rs:110:30
index 47c3313ec28471bc831ca1524802698b1ed9cb83..e7ead1045e6369682c5f1744ff40d72f7b72564e 100644 (file)
@@ -17,7 +17,7 @@ impl Foo for Def {
     const X: i32 = 97;
 }
 
-struct Proxy<T>(T);
+struct Proxy<T>(#[allow(unused_tuple_struct_fields)] T);
 
 impl<T: Foo> Foo for Proxy<T> {
     const X: i32 = T::X;
index a6b0bb7070b7a4d6a765441bc164ceec0929af9b..193f2efe19929f0a6d15e7eae819ab5db28fec9d 100644 (file)
@@ -1,6 +1,7 @@
 // run-pass
 
 #![feature(associated_type_bounds)]
+#![allow(dead_code)]
 
 trait Tr1 { type As1; }
 trait Tr2 { type As2; }
index 64132cfeed7d2a3019ac4eff95c497d2bf2eac01..45df3ac20c2ea8350cedee545f860adfa6d136bd 100644 (file)
@@ -5,6 +5,7 @@
 trait Device {
     type Resources;
 }
+#[allow(unused_tuple_struct_fields)]
 struct Foo<D, R>(D, R);
 
 trait Tr {
index 109feb8e969a5f55de76f6b8cc85670124cf6cf8..26b9f4b3a92660ea78b923adb3884545ea4eb81a 100644 (file)
@@ -4,5 +4,5 @@
 
 fn main() {
     let _: &dyn I32Iterator<Item = u32> = &vec![42].into_iter();
-    //~^ ERROR type mismatch
+    //~^ ERROR expected `std::vec::IntoIter<u32>` to be an iterator that yields `i32`, but it yields `u32`
 }
index dbd9a44ed97743769c32d37bb19b086f0be6ecb6..2d25f68de44ad1c34a7c36976ce21a9300699deb 100644 (file)
@@ -1,4 +1,4 @@
-error[E0271]: type mismatch resolving `<std::vec::IntoIter<u32> as Iterator>::Item == i32`
+error[E0271]: expected `std::vec::IntoIter<u32>` to be an iterator that yields `i32`, but it yields `u32`
   --> $DIR/associated-types-overridden-binding-2.rs:6:43
    |
 LL |     let _: &dyn I32Iterator<Item = u32> = &vec![42].into_iter();
index fa59060629ddf55a6be47e59a76fc35182be5f07..8612911d8f809a78a29452333ee2b7db28684801 100644 (file)
@@ -9,7 +9,7 @@ pub trait UnifyKey {
     fn dummy(&self) { }
 }
 
-pub struct Node<K:UnifyKey>(K, K::Value);
+pub struct Node<K:UnifyKey>(#[allow(unused_tuple_struct_fields)] K, K::Value);
 
 fn foo<K : UnifyKey<Value=Option<V>>,V : Clone>(node: &Node<K>) -> Option<V> {
     node.1.clone()
index 162f9e00edd81a369cfe739569cd28af4c81afe1..9e68e9e77515bc6633b0ad3e8a603f98c765d587 100644 (file)
@@ -15,9 +15,9 @@ pub trait ThriftService<Bug: NotFoo>:
 {
     fn get_service(
     //~^ ERROR the trait bound `Bug: Foo` is not satisfied
+    //~| ERROR the trait bound `Bug: Foo` is not satisfied
         &self,
     ) -> Self::AssocType;
-    //~^ the trait bound `Bug: Foo` is not satisfied
 }
 
 fn with_factory<H>(factory: dyn ThriftService<()>) {}
index a84b599b52b68d2c28913dfdb70c5d08f8714bf6..dd5ec7175b5f1aa47ac07db08a3786875027cf4b 100644 (file)
@@ -20,7 +20,7 @@ LL | |
 LL | |
 LL | |     Service<AssocType = <Bug as Foo>::OnlyFoo>
 ...  |
-LL | |
+LL | |     ) -> Self::AssocType;
 LL | | }
    | |_^ the trait `Foo` is not implemented for `Bug`
    |
@@ -34,6 +34,7 @@ error[E0277]: the trait bound `Bug: Foo` is not satisfied
    |
 LL | /     fn get_service(
 LL | |
+LL | |
 LL | |         &self,
 LL | |     ) -> Self::AssocType;
    | |_________________________^ the trait `Foo` is not implemented for `Bug`
@@ -50,10 +51,10 @@ LL | fn with_factory<H>(factory: dyn ThriftService<()>) {}
    |                             ^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()`
 
 error[E0277]: the trait bound `Bug: Foo` is not satisfied
-  --> $DIR/issue-59324.rs:19:10
+  --> $DIR/issue-59324.rs:16:8
    |
-LL |     ) -> Self::AssocType;
-   |          ^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `Bug`
+LL |     fn get_service(
+   |        ^^^^^^^^^^^ the trait `Foo` is not implemented for `Bug`
    |
 help: consider further restricting this bound
    |
index b831d6102327759d499e6480ff85a44cb0b51e77..446212ca767c430206b8609e1526925a35f06c35 100644 (file)
@@ -15,7 +15,7 @@ fn return_targets_async_block_not_fn() -> u8 {
         return 0u8;
     };
     let _: &dyn Future<Output = ()> = &block;
-    //~^ ERROR type mismatch
+    //~^ ERROR expected `impl Future<Output = u8>` to be a future that resolves to `()`, but it resolves to `u8`
 }
 
 async fn return_targets_async_block_not_async_fn() -> u8 {
@@ -24,7 +24,7 @@ async fn return_targets_async_block_not_async_fn() -> u8 {
         return 0u8;
     };
     let _: &dyn Future<Output = ()> = &block;
-    //~^ ERROR type mismatch resolving `<impl Future<Output = u8> as Future>::Output == ()`
+    //~^ ERROR expected `impl Future<Output = u8>` to be a future that resolves to `()`, but it resolves to `u8`
 }
 
 fn no_break_in_async_block() {
@@ -42,7 +42,9 @@ fn no_break_in_async_block_even_with_outer_loop() {
 }
 
 struct MyErr;
-fn err() -> Result<u8, MyErr> { Err(MyErr) }
+fn err() -> Result<u8, MyErr> {
+    Err(MyErr)
+}
 
 fn rethrow_targets_async_block_not_fn() -> Result<u8, MyErr> {
     //~^ ERROR mismatched types
index e5887689690e76fd5066d2193ae5613782cfe0b2..2a08d5d6ce5f8305aa24a50bb95f9445e7d00701 100644 (file)
@@ -31,7 +31,7 @@ LL | |
 LL | | }
    | |_^ expected `u8`, found `()`
 
-error[E0271]: type mismatch resolving `<impl Future<Output = u8> as Future>::Output == ()`
+error[E0271]: expected `impl Future<Output = u8>` to be a future that resolves to `()`, but it resolves to `u8`
   --> $DIR/async-block-control-flow-static-semantics.rs:26:39
    |
 LL |     let _: &dyn Future<Output = ()> = &block;
@@ -47,7 +47,7 @@ LL | fn return_targets_async_block_not_fn() -> u8 {
    |    |
    |    implicitly returns `()` as its body has no tail or `return` expression
 
-error[E0271]: type mismatch resolving `<impl Future<Output = u8> as Future>::Output == ()`
+error[E0271]: expected `impl Future<Output = u8>` to be a future that resolves to `()`, but it resolves to `u8`
   --> $DIR/async-block-control-flow-static-semantics.rs:17:39
    |
 LL |     let _: &dyn Future<Output = ()> = &block;
@@ -56,7 +56,7 @@ LL |     let _: &dyn Future<Output = ()> = &block;
    = note: required for the cast from `impl Future<Output = u8>` to the object type `dyn Future<Output = ()>`
 
 error[E0308]: mismatched types
-  --> $DIR/async-block-control-flow-static-semantics.rs:47:44
+  --> $DIR/async-block-control-flow-static-semantics.rs:49:44
    |
 LL | fn rethrow_targets_async_block_not_fn() -> Result<u8, MyErr> {
    |    ----------------------------------      ^^^^^^^^^^^^^^^^^ expected enum `Result`, found `()`
@@ -67,7 +67,7 @@ LL | fn rethrow_targets_async_block_not_fn() -> Result<u8, MyErr> {
            found unit type `()`
 
 error[E0308]: mismatched types
-  --> $DIR/async-block-control-flow-static-semantics.rs:56:50
+  --> $DIR/async-block-control-flow-static-semantics.rs:58:50
    |
 LL | fn rethrow_targets_async_block_not_async_fn() -> Result<u8, MyErr> {
    |    ----------------------------------------      ^^^^^^^^^^^^^^^^^ expected enum `Result`, found `()`
index a603ebd6e8547727824440b4828cae0730fe8962..15566256600df828844d397679cc46afd8018dc3 100644 (file)
@@ -17,7 +17,7 @@
 use std::task::{Context, Poll};
 
 const BIG_FUT_SIZE: usize = 1024;
-struct BigFut([u8; BIG_FUT_SIZE]);
+struct BigFut(#[allow(unused_tuple_struct_fields)] [u8; BIG_FUT_SIZE]);
 
 impl BigFut {
     fn new() -> Self {
index d5d7b3fc3f0bd10c7438002ba5f0a391f962c929..31a086ba975696010c7f1336bff90ef0b75d8a4f 100644 (file)
@@ -16,7 +16,7 @@
 use std::task::{Context, Poll};
 
 const BIG_FUT_SIZE: usize = 1024;
-struct Big([u8; BIG_FUT_SIZE]);
+struct Big(#[allow(unused_tuple_struct_fields)] [u8; BIG_FUT_SIZE]);
 
 impl Big {
     fn new() -> Self {
index fd76c282f9629c475253bc0197f6cd699999489b..e6f6e9e9f653fcfe659c2795822845a16b2d2aa2 100644 (file)
@@ -35,7 +35,7 @@ note: cycle used when checking item types in top-level module
   --> $DIR/no-const-async.rs:4:1
    |
 LL | pub const async fn x() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
index 0852bb7ca8b928db11114910212bd64357bbeeb8..894ec8341f8e0aac35a4806c4b3b9da05fb0fbcd 100644 (file)
@@ -34,10 +34,10 @@ LL | #![a={impl std::ops::Neg for i8 {}}]
    |                                     ^ consider adding a `main` function to `$DIR/issue-90873.rs`
 
 error: missing type for `static` item
-  --> $DIR/issue-90873.rs:1:16
+  --> $DIR/issue-90873.rs:1:17
    |
 LL | #![u=||{static d=||1;}]
-   |                ^ help: provide a type for the item: `d: <type>`
+   |                 ^ help: provide a type for the item: `: <type>`
 
 error: aborting due to 6 previous errors
 
index 567b86c276274dfc4610dd90e388f99780ba1139..7b52d9c176e88704e8fd623179e97666b03c798f 100644 (file)
@@ -9,7 +9,7 @@
 impl !Auto for bool {}
 impl !AutoUnsafe for bool {}
 
-struct AutoBool(bool);
+struct AutoBool(#[allow(unused_tuple_struct_fields)] bool);
 
 impl Auto for AutoBool {}
 unsafe impl AutoUnsafe for AutoBool {}
index d32ad11a122df215aab23727fd1899911016ad80..3844ebcfd30d71a5e56b4f1ca4f24d1d557e122d 100644 (file)
@@ -4,8 +4,6 @@
 // compile-flags:-g -Csplit-debuginfo=unpacked
 // only-macos
 
-#![feature(backtrace)]
-
 use std::process::Command;
 use std::str;
 
index dc45061da5b50217e98e7bb908111a1095284118..7eb52196e16e773bf0718192e86153783362e51e 100644 (file)
@@ -15,7 +15,7 @@ fn chain<P>(self, p: P) -> Chain<Self, P> where Self: Sized {
     }
 }
 
-struct Token<T>(T::Item) where T: Iterator;
+struct Token<T>(#[allow(unused_tuple_struct_fields)] T::Item) where T: Iterator;
 
 impl<T> Parser for Token<T> where T: Iterator {
     type Input = T;
@@ -25,7 +25,7 @@ fn parse(self, _input: Self::Input) -> Result<(Self::Output, Self::Input), ()> {
     }
 }
 
-struct Chain<L, R>(L, R);
+struct Chain<L, R>(#[allow(unused_tuple_struct_fields)] L, #[allow(unused_tuple_struct_fields)] R);
 
 impl<L, R> Parser for Chain<L, R> where L: Parser, R: Parser<Input = L::Input> {
     type Input = L::Input;
index eceb646778493e1deed59c61949ba78d46851971..407716aa28af9a0f7520a773dac9f03974fd1dd5 100644 (file)
@@ -3,7 +3,7 @@
 #![allow(non_camel_case_types)]
 
 
-
+#[allow(unused_tuple_struct_fields)]
 enum color {
     rgb(isize, isize, isize),
     rgba(isize, isize, isize, isize),
index 2ab44a96c3a4b4ac6a5072422377a3be1a54a826..47623a3d72263671d2f7405988e334a8b75258f8 100644 (file)
@@ -1,7 +1,7 @@
 // run-pass
 #![allow(non_camel_case_types)]
 
-enum blah { a(isize, isize, usize), b(isize, isize), c, }
+enum blah { a(isize, isize, #[allow(unused_tuple_struct_fields)] usize), b(isize, isize), c, }
 
 fn or_alt(q: blah) -> isize {
     match q { blah::a(x, y, _) | blah::b(x, y) => { return x + y; } blah::c => { return 0; } }
index 50cfe19fef48d58e2424393eeaad57e849ffe0c5..2cf050d011daebdcd487dee7b215a106f4ae88de 100644 (file)
@@ -3,6 +3,6 @@
 
 // pretty-expanded FIXME #23616
 
-enum clam<T> { a(T), }
+enum clam<T> { a(#[allow(unused_tuple_struct_fields)] T), }
 
 pub fn main() { let c = clam::a(2); match c { clam::a::<isize>(_) => { } } }
index c32e944afe36c0a30ad47af96784181c0b6dbf51..13a6277da14c0898b95ab55ef527e3b4fe8fa72e 100644 (file)
@@ -1,4 +1,4 @@
-error[E0507]: cannot move out of `s.0` which is behind a shared reference
+error[E0507]: cannot move out of `s` which is behind a shared reference
   --> $DIR/access-mode-in-closures.rs:8:15
    |
 LL |         match *s { S(v) => v }
index c08c93f361726e5a9096df112438dfc7e3ab68b9..fc1a44c3ca04ef4baf5a4757dfc94ce93b8589b9 100644 (file)
@@ -4,7 +4,7 @@ error[E0381]: used binding `x` is possibly-uninitialized
 LL |     let mut x: isize;
    |         ----- binding declared here but left uninitialized
 LL |     for _ in 0..0 { x = 10; }
-   |              ---- if the `for` loop runs 0 times, `x` is not initialized 
+   |              ---- if the `for` loop runs 0 times, `x` is not initialized
 LL |     return x;
    |            ^ `x` used here but it is possibly-uninitialized
 
index ead02414a622b065345e7c26a3ada83bffbe28ec..96246d9ae1a8909ce949a36ce288f00f3821828b 100644 (file)
@@ -1,4 +1,4 @@
-error[E0507]: cannot move out of `f.0` which is behind a shared reference
+error[E0507]: cannot move out of `f` as enum variant `Foo1` which is behind a shared reference
   --> $DIR/borrowck-move-error-with-note.rs:11:11
    |
 LL |     match *f {
index 117014b44ee117ca8892aedfab66ac4824751f1e..cdde48871ea905378c242c14a02202a3c929eb5b 100644 (file)
@@ -12,7 +12,7 @@
 use std::marker;
 
 #[derive(Copy, Clone)]
-struct X<T>(T);
+struct X<T>(#[allow(unused_tuple_struct_fields)] T);
 
 impl<T:Sync> RequiresShare for X<T> { }
 
diff --git a/src/test/ui/cfg/cfg-method-receiver.rs b/src/test/ui/cfg/cfg-method-receiver.rs
new file mode 100644 (file)
index 0000000..78a072f
--- /dev/null
@@ -0,0 +1,12 @@
+macro_rules! cbor_map {
+    ($key:expr) => {
+        $key.signum();
+        //~^ ERROR can't call method `signum` on ambiguous numeric type `{integer}` [E0689]
+    };
+}
+
+fn main() {
+    cbor_map! { #[cfg(test)] 4};
+    //~^ ERROR attributes on expressions are experimental
+    //~| ERROR removing an expression is not supported in this position
+}
diff --git a/src/test/ui/cfg/cfg-method-receiver.stderr b/src/test/ui/cfg/cfg-method-receiver.stderr
new file mode 100644 (file)
index 0000000..517fc81
--- /dev/null
@@ -0,0 +1,34 @@
+error[E0658]: attributes on expressions are experimental
+  --> $DIR/cfg-method-receiver.rs:9:17
+   |
+LL |     cbor_map! { #[cfg(test)] 4};
+   |                 ^^^^^^^^^^^^
+   |
+   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+
+error: removing an expression is not supported in this position
+  --> $DIR/cfg-method-receiver.rs:9:17
+   |
+LL |     cbor_map! { #[cfg(test)] 4};
+   |                 ^^^^^^^^^^^^
+
+error[E0689]: can't call method `signum` on ambiguous numeric type `{integer}`
+  --> $DIR/cfg-method-receiver.rs:3:14
+   |
+LL |         $key.signum();
+   |              ^^^^^^
+...
+LL |     cbor_map! { #[cfg(test)] 4};
+   |     --------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `cbor_map` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: you must specify a concrete type for this numeric value, like `i32`
+   |
+LL |     cbor_map! { #[cfg(test)] 4_i32};
+   |                              ~~~~~
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0658, E0689.
+For more information about an error, try `rustc --explain E0658`.
index 4323e87b08de78e6b261c53c7fc0d653b816fbb4..7712e9465424b46534009e5f6248b1acf893bbd5 100644 (file)
@@ -4,7 +4,7 @@
 // Test that `Clone` is correctly implemented for builtin types.
 
 #[derive(Copy, Clone)]
-struct S(i32);
+struct S(#[allow(unused_tuple_struct_fields)] i32);
 
 fn test_clone<T: Clone>(arg: T) {
     let _ = arg.clone();
index 2b86b0ddade2367196e542f83ac91b65cfc2b2b7..173dd2e2cff2ee3f630982a3ee2bc5c43d600b7f 100644 (file)
@@ -18,10 +18,10 @@ impl Foo {
     }
 }
 
-struct S(Foo);
+struct S(#[allow(unused_tuple_struct_fields)] Foo);
 
 #[derive(Clone)]
-struct T(i32);
+struct T(#[allow(unused_tuple_struct_fields)] i32);
 
 struct U(S, T);
 
index 3cac4abfad7c2a5def2e614517d6d30684481719..cfc4555ca03a0b91d8e9d46b0719d9ad14f47df5 100644 (file)
@@ -18,10 +18,10 @@ fn from(s: &str) -> Self {
     }
 }
 
-struct S(Foo);
+struct S(#[allow(unused_tuple_struct_fields)] Foo);
 
 #[derive(Clone)]
-struct T(i32);
+struct T(#[allow(unused_tuple_struct_fields)] i32);
 
 struct U(S, T);
 
index 63e4000e833eb584424d8d52fec54b0f638d0906..e99dbb5ab3a4aae0fd91495bc571d7a77f284a04 100644 (file)
@@ -13,7 +13,7 @@ impl Drop for Foo {
 }
 
 #[derive(Debug)]
-struct ConstainsDropField(Foo, Foo);
+struct ConstainsDropField(Foo, #[allow(unused_tuple_struct_fields)] Foo);
 
 // `t` needs Drop because one of its elements needs drop,
 // therefore precise capture might affect drop ordering
index 9d9c54298cf112ccb9c838a934fe33320380fa46..62a984c9eebdd81430f1eed07f7ec49f99b134e3 100644 (file)
@@ -13,7 +13,7 @@ fn drop(&mut self) {
 }
 
 #[derive(Debug)]
-struct ConstainsDropField(Foo, Foo);
+struct ConstainsDropField(Foo, #[allow(unused_tuple_struct_fields)] Foo);
 
 // `t` needs Drop because one of its elements needs drop,
 // therefore precise capture might affect drop ordering
index 0405b2d01e2cc75949ffafc8d7ff2765388eb33b..f76d09cd0b2ae60c1cf496a1ca58061a8cf2a148 100644 (file)
@@ -1,7 +1,5 @@
-#![feature(box_syntax)]
-
 fn main() {
-    let x: Box<_> = box 1;
+    let x: Box<_> = Box::new(1);
     let f = move|| {
         let _a = x;
         drop(x);
index 8d9faf324e82a36d83f15b44b9caf0446f414de0..423b79dafcc97ddfe43dc0f8af9de8c8173f9de2 100644 (file)
@@ -1,5 +1,5 @@
 error[E0382]: use of moved value: `x`
-  --> $DIR/issue-10398.rs:7:14
+  --> $DIR/issue-10398.rs:5:14
    |
 LL |         let _a = x;
    |                  - value moved here
index 694d86feb5a34cc39526d96fa4f61e4d58ebf080..cecb08f006fde2d439ff8fef2d41b27cfc9ba4a7 100644 (file)
@@ -2,7 +2,7 @@
 // transferring ownership of the box before invoking the stack
 // closure results in a crash.
 
-#![feature(box_syntax)]
+
 
 fn twice(x: Box<usize>) -> usize {
      *x * 2
@@ -13,7 +13,7 @@ fn invoke<F>(f: F) where F: FnOnce() -> usize {
 }
 
 fn main() {
-      let x  : Box<usize>  = box 9;
+      let x  : Box<usize>  = Box::new(9);
       let sq =  || { *x * *x };
 
       twice(x); //~ ERROR: cannot move out of
index 09c44d261af0c449f373aeef4850a883f9d5761c..59607afec8f8da20f901af644eba78a8afe679c3 100644 (file)
@@ -6,11 +6,6 @@ LL |         Foo(())
    |         |
    |         arguments to this struct are incorrect
    |
-note: return type inferred to be `{integer}` here
-  --> $DIR/issue-84128.rs:10:20
-   |
-LL |             return Foo(0);
-   |                    ^^^^^^
 note: tuple struct defined here
   --> $DIR/issue-84128.rs:5:8
    |
diff --git a/src/test/ui/closures/issue-90871.rs b/src/test/ui/closures/issue-90871.rs
new file mode 100644 (file)
index 0000000..9c70bbc
--- /dev/null
@@ -0,0 +1,5 @@
+fn main() {
+    2: n([u8; || 1])
+    //~^ ERROR cannot find type `n` in this scope
+    //~| ERROR mismatched types
+}
diff --git a/src/test/ui/closures/issue-90871.stderr b/src/test/ui/closures/issue-90871.stderr
new file mode 100644 (file)
index 0000000..1e102cc
--- /dev/null
@@ -0,0 +1,23 @@
+error[E0412]: cannot find type `n` in this scope
+  --> $DIR/issue-90871.rs:2:8
+   |
+LL |     2: n([u8; || 1])
+   |        ^ expecting a type here because of type ascription
+
+error[E0308]: mismatched types
+  --> $DIR/issue-90871.rs:2:15
+   |
+LL |     2: n([u8; || 1])
+   |               ^^^^ expected `usize`, found closure
+   |
+   = note: expected type `usize`
+           found closure `[closure@$DIR/issue-90871.rs:2:15: 2:17]`
+help: use parentheses to call this closure
+   |
+LL |     2: n([u8; (|| 1)()])
+   |               +    +++
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0308, E0412.
+For more information about an error, try `rustc --explain E0308`.
index dbfeef053daa1e93364ee485de2ca3925cb45c24..ca1ab3cc7feb909e62258fa12260e2ab3fec7daa 100644 (file)
@@ -2,6 +2,7 @@
 #![allow(unused_variables)]
 #![allow(unused_assignments)]
 #[derive(Debug)]
+#[allow(unused_tuple_struct_fields)]
 enum Foo {
     Bar(u32, u32),
     Baz(&'static u32, &'static u32)
index 5d8aab2ce74ce532fde522ebda3a3989ff44c6cd..d35ee5c731ecf0bc30b057a882c5f0720acebeaf 100644 (file)
@@ -20,5 +20,5 @@ fn send(&self, _: T) {}
 }
 
 trait Foo { fn dummy(&self) { }}
-struct Output(isize);
+struct Output(#[allow(unused_tuple_struct_fields)] isize);
 impl Foo for Output {}
index aa0f9131aa7f5e42abc3a924ac28625136b094ea..c9e26c302bf576c82f39779d8339e759cc99ca1d 100644 (file)
@@ -9,6 +9,7 @@ trait Foo {
     const ASSOC: usize = 1;
 }
 
+#[allow(unused_tuple_struct_fields)]
 struct Iced<T: Foo>(T, [(); T::ASSOC])
 where
     [(); T::ASSOC]: ;
index d0864414cc1fd3cbff46e4591fad9a4b823bd631..3017920fc98c392ed5a80e57630cf897c6801540 100644 (file)
@@ -9,6 +9,7 @@ trait Foo {
     const ASSOC: usize = 1;
 }
 
+#[allow(unused_tuple_struct_fields)]
 struct Iced<T: Foo>(T, [(); T::ASSOC])
 where
     [(); T::ASSOC]: ;
index fda3ec3eef7995bff4068af30e5cbd2dd2ef7847..5693409e99205c8ce45ee9c2b55993c438110d33 100644 (file)
@@ -4,7 +4,7 @@
 
 extern crate const_generic_lib;
 
-struct Container(const_generic_lib::Alias);
+struct Container(#[allow(unused_tuple_struct_fields)] const_generic_lib::Alias);
 
 fn main() {
     let res = const_generic_lib::function(const_generic_lib::Struct([14u8, 1u8, 2u8]));
index 4d89f188ad777a90c7eab170d62ee0986f40f7b3..b839008d424e9c382284527ee74057c20b856c2b 100644 (file)
@@ -16,7 +16,7 @@ impl BlockCipher for BarCipher {
     const BLOCK_SIZE: usize = 32;
 }
 
-pub struct Block<C>(C);
+pub struct Block<C>(#[allow(unused_tuple_struct_fields)] C);
 
 pub fn test<C: BlockCipher, const M: usize>()
 where
diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-100217.rs b/src/test/ui/const-generics/generic_const_exprs/issue-100217.rs
new file mode 100644 (file)
index 0000000..acdc348
--- /dev/null
@@ -0,0 +1,42 @@
+// build-pass
+
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+
+trait TraitOne {
+    const MY_NUM: usize;
+    type MyErr: std::fmt::Debug;
+
+    fn do_one_stuff(arr: [u8; Self::MY_NUM]) -> Result<(), Self::MyErr>;
+}
+
+trait TraitTwo {
+    fn do_two_stuff();
+}
+
+impl<O: TraitOne> TraitTwo for O
+where
+    [(); Self::MY_NUM]:,
+{
+    fn do_two_stuff() {
+        O::do_one_stuff([5; Self::MY_NUM]).unwrap()
+    }
+}
+
+struct Blargotron;
+
+#[derive(Debug)]
+struct ErrTy<const N: usize>([(); N]);
+
+impl TraitOne for Blargotron {
+    const MY_NUM: usize = 3;
+    type MyErr = ErrTy<{ Self::MY_NUM }>;
+
+    fn do_one_stuff(_arr: [u8; Self::MY_NUM]) -> Result<(), Self::MyErr> {
+        Ok(())
+    }
+}
+
+fn main() {
+    Blargotron::do_two_stuff();
+}
diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-73298.rs b/src/test/ui/const-generics/generic_const_exprs/issue-73298.rs
new file mode 100644 (file)
index 0000000..3c59e1b
--- /dev/null
@@ -0,0 +1,23 @@
+// build-pass
+
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+
+use std::convert::AsMut;
+use std::default::Default;
+
+trait Foo: Sized {
+    type Baz: Default + AsMut<[u8]>;
+    fn bar() {
+        Self::Baz::default().as_mut();
+    }
+}
+
+impl Foo for () {
+    type Baz = [u8; 1 * 1];
+    //type Baz = [u8; 1];
+}
+
+fn main() {
+    <() as Foo>::bar();
+}
diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-82268.rs b/src/test/ui/const-generics/generic_const_exprs/issue-82268.rs
new file mode 100644 (file)
index 0000000..d08fc5b
--- /dev/null
@@ -0,0 +1,73 @@
+// build-pass
+
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+
+trait Collate<Op> {
+    type Pass;
+    type Fail;
+
+    fn collate(self) -> (Self::Pass, Self::Fail);
+}
+
+impl<Op> Collate<Op> for () {
+    type Pass = ();
+    type Fail = ();
+
+    fn collate(self) -> ((), ()) {
+        ((), ())
+    }
+}
+
+trait CollateStep<X, Prev> {
+    type Pass;
+    type Fail;
+    fn collate_step(x: X, prev: Prev) -> (Self::Pass, Self::Fail);
+}
+
+impl<X, P, F> CollateStep<X, (P, F)> for () {
+    type Pass = (X, P);
+    type Fail = F;
+
+    fn collate_step(x: X, (p, f): (P, F)) -> ((X, P), F) {
+        ((x, p), f)
+    }
+}
+
+struct CollateOpImpl<const MASK: u32>;
+trait CollateOpStep {
+    type NextOp;
+    type Apply;
+}
+
+impl<const MASK: u32> CollateOpStep for CollateOpImpl<MASK>
+where
+    CollateOpImpl<{ MASK >> 1 }>: Sized,
+{
+    type NextOp = CollateOpImpl<{ MASK >> 1 }>;
+    type Apply = ();
+}
+
+impl<H, T, Op: CollateOpStep> Collate<Op> for (H, T)
+where
+    T: Collate<Op::NextOp>,
+    Op::Apply: CollateStep<H, (T::Pass, T::Fail)>,
+{
+    type Pass = <Op::Apply as CollateStep<H, (T::Pass, T::Fail)>>::Pass;
+    type Fail = <Op::Apply as CollateStep<H, (T::Pass, T::Fail)>>::Fail;
+
+    fn collate(self) -> (Self::Pass, Self::Fail) {
+        <Op::Apply as CollateStep<H, (T::Pass, T::Fail)>>::collate_step(self.0, self.1.collate())
+    }
+}
+
+fn collate<X, const MASK: u32>(x: X) -> (X::Pass, X::Fail)
+where
+    X: Collate<CollateOpImpl<MASK>>,
+{
+    x.collate()
+}
+
+fn main() {
+    dbg!(collate::<_, 5>(("Hello", (42, ('!', ())))));
+}
diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-83972.rs b/src/test/ui/const-generics/generic_const_exprs/issue-83972.rs
new file mode 100644 (file)
index 0000000..0063719
--- /dev/null
@@ -0,0 +1,38 @@
+// build-pass
+
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+
+pub trait Foo {
+    fn foo(&self);
+}
+
+pub struct FooImpl<const N: usize>;
+impl<const N: usize> Foo for FooImpl<N> {
+    fn foo(&self) {}
+}
+
+pub trait Bar: 'static {
+    type Foo: Foo;
+    fn get() -> &'static Self::Foo;
+}
+
+struct BarImpl;
+impl Bar for BarImpl {
+    type Foo = FooImpl<
+        {
+            { 4 }
+        },
+    >;
+    fn get() -> &'static Self::Foo {
+        &FooImpl
+    }
+}
+
+pub fn boom<B: Bar>() {
+    B::get().foo();
+}
+
+fn main() {
+    boom::<BarImpl>();
+}
diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-84669.rs b/src/test/ui/const-generics/generic_const_exprs/issue-84669.rs
new file mode 100644 (file)
index 0000000..3933ff2
--- /dev/null
@@ -0,0 +1,30 @@
+// build-pass
+
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+trait Foo {
+    type Output;
+
+    fn foo() -> Self::Output;
+}
+
+impl Foo for [u8; 3] {
+    type Output = [u8; 1 + 2];
+
+    fn foo() -> [u8; 3] {
+        [1u8; 3]
+    }
+}
+
+fn bug<const N: usize>()
+where
+    [u8; N]: Foo,
+    <[u8; N] as Foo>::Output: AsRef<[u8]>,
+{
+    <[u8; N]>::foo().as_ref();
+}
+
+fn main() {
+    bug::<3>();
+}
diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-86710.rs b/src/test/ui/const-generics/generic_const_exprs/issue-86710.rs
new file mode 100644 (file)
index 0000000..bdd8a21
--- /dev/null
@@ -0,0 +1,73 @@
+// build-pass
+
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+
+use std::marker::PhantomData;
+
+fn main() {
+    let x = FooImpl::<BarImpl<1>> { phantom: PhantomData };
+    let _ = x.foo::<BarImpl<1>>();
+}
+
+trait Foo<T>
+where
+    T: Bar,
+{
+    fn foo<U>(&self)
+    where
+        T: Operation<U>,
+        <T as Operation<U>>::Output: Bar;
+}
+
+struct FooImpl<T>
+where
+    T: Bar,
+{
+    phantom: PhantomData<T>,
+}
+
+impl<T> Foo<T> for FooImpl<T>
+where
+    T: Bar,
+{
+    fn foo<U>(&self)
+    where
+        T: Operation<U>,
+        <T as Operation<U>>::Output: Bar,
+    {
+        <<T as Operation<U>>::Output as Bar>::error_occurs_here();
+    }
+}
+
+trait Bar {
+    fn error_occurs_here();
+}
+
+struct BarImpl<const N: usize>;
+
+impl<const N: usize> Bar for BarImpl<N> {
+    fn error_occurs_here() {}
+}
+
+trait Operation<Rhs> {
+    type Output;
+}
+
+//// Part-A: This causes error.
+impl<const M: usize, const N: usize> Operation<BarImpl<M>> for BarImpl<N>
+where
+    BarImpl<{ N + M }>: Sized,
+{
+    type Output = BarImpl<{ N + M }>;
+}
+
+//// Part-B: This doesn't cause error.
+// impl<const M: usize, const N: usize> Operation<BarImpl<M>> for BarImpl<N> {
+//     type Output = BarImpl<M>;
+// }
+
+//// Part-C: This also doesn't cause error.
+// impl<const M: usize, const N: usize> Operation<BarImpl<M>> for BarImpl<N> {
+//     type Output = BarImpl<{ M }>;
+// }
diff --git a/src/test/ui/const-generics/issues/issue-100313.rs b/src/test/ui/const-generics/issues/issue-100313.rs
new file mode 100644 (file)
index 0000000..4e9d362
--- /dev/null
@@ -0,0 +1,21 @@
+#![allow(incomplete_features)]
+#![feature(const_mut_refs)]
+#![feature(adt_const_params)]
+
+struct T<const B: &'static bool>;
+
+impl <const B: &'static bool> T<B> {
+    const fn set_false(&self) {
+        unsafe {
+            *(B as *const bool as *mut bool) = false;
+            //~^ ERROR evaluation of constant value failed [E0080]
+        }
+    }
+}
+
+const _: () = {
+    let x = T::<{&true}>;
+    x.set_false();
+};
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-100313.stderr b/src/test/ui/const-generics/issues/issue-100313.stderr
new file mode 100644 (file)
index 0000000..f3ce357
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0080]: evaluation of constant value failed
+  --> $DIR/issue-100313.rs:10:13
+   |
+LL |             *(B as *const bool as *mut bool) = false;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |             |
+   |             writing to alloc7 which is read-only
+   |             inside `T::<&true>::set_false` at $DIR/issue-100313.rs:10:13
+...
+LL |     x.set_false();
+   |     ------------- inside `_` at $DIR/issue-100313.rs:18:5
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
index b70479d255b5ff26ee3f144f563bf2dc6d5110f4..f542f2dcb523f5e662b40f76d9113440eea458ac 100644 (file)
@@ -6,7 +6,7 @@ trait Nat {
 }
 
 struct Zero;
-struct Succ<N>(N);
+struct Succ<N>(#[allow(unused_tuple_struct_fields)] N);
 
 impl Nat for Zero {
     const VALUE: usize = 0;
index 58e801164428f68de70ece0efa8a9479158a2cba..11ee7084ce88b8ef58ae1ea6b94f76b9013aefa1 100644 (file)
@@ -2,8 +2,10 @@
 
 use std::mem;
 
+#[allow(unused_tuple_struct_fields)]
 struct Trivial(u8, f32);
 
+#[allow(unused_tuple_struct_fields)]
 struct NonTrivial(u8, String);
 
 const CONST_U8: bool = mem::needs_drop::<u8>();
index c3de6dc2075f8aaa4dffdbc1d1234742e5f03174..e8323e4ae60031f24d3ff8ce666d6928172aee67 100644 (file)
@@ -5,7 +5,7 @@
 
 use std::{mem, ptr};
 
-struct Foo(u32);
+struct Foo(#[allow(unused_tuple_struct_fields)] u32);
 
 #[derive(Clone, Copy)]
 struct Bar {
diff --git a/src/test/ui/consts/const_in_pattern/incomplete-slice.rs b/src/test/ui/consts/const_in_pattern/incomplete-slice.rs
new file mode 100644 (file)
index 0000000..e1ccda7
--- /dev/null
@@ -0,0 +1,15 @@
+#[derive(PartialEq)]
+enum E {
+    A,
+}
+
+const E_SL: &[E] = &[E::A];
+
+fn main() {
+    match &[][..] {
+        //~^ ERROR non-exhaustive patterns: `&_` not covered [E0004]
+        E_SL => {}
+        //~^ WARN to use a constant of type `E` in a pattern, `E` must be annotated with `#[derive(PartialEq, Eq)]`
+        //~| WARN this was previously accepted by the compiler but is being phased out
+    }
+}
diff --git a/src/test/ui/consts/const_in_pattern/incomplete-slice.stderr b/src/test/ui/consts/const_in_pattern/incomplete-slice.stderr
new file mode 100644 (file)
index 0000000..0ff7083
--- /dev/null
@@ -0,0 +1,26 @@
+warning: to use a constant of type `E` in a pattern, `E` must be annotated with `#[derive(PartialEq, Eq)]`
+  --> $DIR/incomplete-slice.rs:11:9
+   |
+LL |         E_SL => {}
+   |         ^^^^
+   |
+   = note: `#[warn(indirect_structural_match)]` 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 #62411 <https://github.com/rust-lang/rust/issues/62411>
+
+error[E0004]: non-exhaustive patterns: `&_` not covered
+  --> $DIR/incomplete-slice.rs:9:11
+   |
+LL |     match &[][..] {
+   |           ^^^^^^^ pattern `&_` not covered
+   |
+   = note: the matched value is of type `&[E]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         E_SL => {}
+LL +         &_ => todo!()
+   |
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0004`.
index 51e1af359cdcc6d42839b57679f671b40681d1d4..15cf3c84d85f9b1ec3c1a5ee6cd48bc0350789bc 100644 (file)
@@ -15,7 +15,7 @@
 #![warn(indirect_structural_match)]
 
 #[derive(Copy, Clone, Debug)]
-struct NoDerive(u32);
+struct NoDerive(#[allow(unused_tuple_struct_fields)] u32);
 
 // This impl makes `NoDerive` irreflexive.
 impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
index c085beb0ea5256a2a3a3d4fd9bbda3eb0ea2bba3..57f94f8c6ab52d04dbcad0223d5a98a1b40865d9 100644 (file)
@@ -2,18 +2,18 @@ error[E0391]: cycle detected when evaluating type-level constant
   --> $DIR/issue-44415.rs:6:17
    |
 LL |     bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
-   |                 ^^^^^^
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`...
   --> $DIR/issue-44415.rs:6:17
    |
 LL |     bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
-   |                 ^^^^^^
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`...
   --> $DIR/issue-44415.rs:6:17
    |
 LL |     bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
-   |                 ^^^^^^
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: ...which requires computing layout of `Foo`...
    = note: ...which requires computing layout of `[u8; _]`...
    = note: ...which requires normalizing `[u8; _]`...
index 9d44aa1361cfc53223d221f3e6b093c153e5c2f4..dd56faa318570698d0c8f63ec63dba2c51c400e9 100644 (file)
@@ -1,7 +1,7 @@
 // run-pass
 
 const HASH_LEN: usize = 20;
-struct Hash([u8; HASH_LEN]);
+struct Hash(#[allow(unused_tuple_struct_fields)] [u8; HASH_LEN]);
 fn init_hash(_: &mut [u8; HASH_LEN]) {}
 
 fn foo<'a>() -> &'a () {
index 2d7e4ab39893d21da6c1809a22cd429d66af4749..c48d9eae92879fc7e1da1588cf76e1c16d5face3 100644 (file)
@@ -4,7 +4,7 @@
 
 const NONE_CELL_STRING: Option<Cell<String>> = None;
 
-struct Foo<T>(T);
+struct Foo<T>(#[allow(unused_tuple_struct_fields)] T);
 impl<T> Foo<T> {
     const FOO: Option<Box<T>> = None;
 }
index 5044d99ec51834b55437d303ba207b5af3ad95eb..c5c3dfc4cc7bda06fed3c71c41b2289b60d3833f 100644 (file)
@@ -3,7 +3,7 @@
 use std::mem;
 
 #[repr(transparent)]
-struct Foo(u32);
+struct Foo(#[allow(unused_tuple_struct_fields)] u32);
 
 const TRANSMUTED_U32: u32 = unsafe { mem::transmute(Foo(3)) };
 
index 128087f1e375522297267296a093509774bb30e1..b92449c6e0aff6776e77d51a8efcc9a96e22b265 100644 (file)
@@ -10,6 +10,10 @@ LL |     let _y = x.clone();
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `clone`, perhaps you need to implement it:
            candidate #1: `Clone`
+help: one of the expressions' fields has a method of the same name
+   |
+LL |     let _y = x.i.clone();
+   |                ++
 
 error: aborting due to previous error
 
index fc842fada5a0d9892ef026ce080385844e3627de..d4976a0f9c9cd1c61bd52b2bc62d4728179b66bb 100644 (file)
@@ -8,8 +8,13 @@ LL | trait Foo<X = Box<dyn Foo>> {
 note: cycle used when collecting item types in top-level module
   --> $DIR/cycle-trait-default-type-trait.rs:4:1
    |
-LL | trait Foo<X = Box<dyn Foo>> {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | / trait Foo<X = Box<dyn Foo>> {
+LL | |
+LL | |
+LL | | }
+LL | |
+LL | | fn main() { }
+   | |_____________^
 
 error[E0391]: cycle detected when computing type of `Foo::X`
   --> $DIR/cycle-trait-default-type-trait.rs:4:23
@@ -21,8 +26,13 @@ LL | trait Foo<X = Box<dyn Foo>> {
 note: cycle used when collecting item types in top-level module
   --> $DIR/cycle-trait-default-type-trait.rs:4:1
    |
-LL | trait Foo<X = Box<dyn Foo>> {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | / trait Foo<X = Box<dyn Foo>> {
+LL | |
+LL | |
+LL | | }
+LL | |
+LL | | fn main() { }
+   | |_____________^
 
 error: aborting due to 2 previous errors
 
index ee54b2fd151d79294e90dd36764709b5340af359..f6ffcc4b5aadcf8a5458ffe2b94fa13411ecab8f 100644 (file)
@@ -13,8 +13,10 @@ LL | trait Chromosome: Chromosome {
 note: cycle used when collecting item types in top-level module
   --> $DIR/cycle-trait-supertrait-direct.rs:3:1
    |
-LL | trait Chromosome: Chromosome {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | / trait Chromosome: Chromosome {
+LL | |
+LL | | }
+   | |_^
 
 error: aborting due to previous error
 
index 8b9840de172da5521879e0bf79e206758291fabb..3480ccc10899e8848c8923f01223b9da75716a64 100644 (file)
@@ -2,6 +2,7 @@
 // pretty-expanded FIXME #23616
 
 #[derive(Clone)]
+#[allow(unused_tuple_struct_fields)]
 struct S<T>(T, ());
 
 pub fn main() {
index 78d74a11ffc8b4e96fd19d75ed87664b20e2ccf2..f8403b1feacbd0ff21d02fdf9974476249217e1e 100644 (file)
@@ -23,7 +23,7 @@ fn clone(&self) -> Self {
 
 /// This struct is actually Copy... at least, it thinks it is!
 #[derive(Copy, Clone)]
-struct Innocent(Liar);
+struct Innocent(#[allow(unused_tuple_struct_fields)] Liar);
 
 impl Innocent {
     fn new() -> Self {
index 757307d944f1806d629cb9fc869ec1bf658d6cd0..8041bd5bb3c652d06302b5adfb56ca7812761fed 100644 (file)
@@ -3,6 +3,7 @@ fn main() {}
 #[derive(Clone)]
 pub struct Little;
 #[derive(Clone)]
+#[allow(unused_tuple_struct_fields)]
 pub struct Big(
     Little,
     Little,
index 87d453e1565c5249a967abf95c59e1c1cac5b5e3..a8aae76f4fcb3775a04dcee6970ef4e1e0b03272 100644 (file)
@@ -6,10 +6,18 @@ use std::{
     rc::Rc,
 };
 
+use std::time::Duration;
+//~^ ERROR expected item, found `require`
+
+use std::time::Instant;
+//~^ ERROR expected item, found `include`
+
 pub use std::io;
 //~^ ERROR expected item, found `using`
 
 fn main() {
     let x = Rc::new(1);
     let _ = write!(io::stdout(), "{:?}", x);
+    let _ = Duration::new(5, 0);
+    let _ = Instant::now();
 }
index 59e83732328d9fc73baf33ce32a3178c5578bd0e..2db7c24075219f06c91a7d17e6113b5941fedf4d 100644 (file)
@@ -6,10 +6,18 @@
     rc::Rc,
 };
 
+require std::time::Duration;
+//~^ ERROR expected item, found `require`
+
+include std::time::Instant;
+//~^ ERROR expected item, found `include`
+
 pub using std::io;
 //~^ ERROR expected item, found `using`
 
 fn main() {
     let x = Rc::new(1);
     let _ = write!(io::stdout(), "{:?}", x);
+    let _ = Duration::new(5, 0);
+    let _ = Instant::now();
 }
index b22954af80f0600704d7a5a50b378ac50689f9ee..2aac8f68c5ebd96c849385ba49263a33051af941 100644 (file)
@@ -4,11 +4,23 @@ error: expected item, found `import`
 LL | import std::{
    | ^^^^^^ help: items are imported using the `use` keyword
 
+error: expected item, found `require`
+  --> $DIR/use_instead_of_import.rs:9:1
+   |
+LL | require std::time::Duration;
+   | ^^^^^^^ help: items are imported using the `use` keyword
+
+error: expected item, found `include`
+  --> $DIR/use_instead_of_import.rs:12:1
+   |
+LL | include std::time::Instant;
+   | ^^^^^^^ help: items are imported using the `use` keyword
+
 error: expected item, found `using`
-  --> $DIR/use_instead_of_import.rs:9:5
+  --> $DIR/use_instead_of_import.rs:15:5
    |
 LL | pub using std::io;
    |     ^^^^^ help: items are imported using the `use` keyword
 
-error: aborting due to 2 previous errors
+error: aborting due to 4 previous errors
 
index b4605878a54e307122ee819f53c4cd80866c65d6..0d7af3d4f61a87a5adb625a75128ba125df0b8ed 100644 (file)
 
 struct Dt<A: Foo>(&'static str, A);
 struct Dr<'a, B:'a+Foo>(&'static str, &'a B);
-struct Pt<A: Foo, B: Foo>(&'static str, A, B);
-struct Pr<'a, 'b, B:'a+'b+Foo>(&'static str, &'a B, &'b B);
-struct St<A: Foo>(&'static str, A);
-struct Sr<'a, B:'a+Foo>(&'static str, &'a B);
+struct Pt<A: Foo, B: Foo>(&'static str, #[allow(unused_tuple_struct_fields)] A, B);
+struct Pr<'a, 'b, B:'a+'b+Foo>(&'static str, #[allow(unused_tuple_struct_fields)] &'a B, &'b B);
+struct St<A: Foo>(&'static str, #[allow(unused_tuple_struct_fields)] A);
+struct Sr<'a, B:'a+Foo>(&'static str, #[allow(unused_tuple_struct_fields)] &'a B);
 
 impl<A: Foo> Drop for Dt<A> {
     fn drop(&mut self) { println!("drop {}", self.0); self.1.foo(self.0); }
index 9255391e4120631dc14da2edd0096fc4decc9c1f..3c4840d5c7a30223def667a6f933a998f827d0ba 100644 (file)
 
 struct Dt<A: Foo>(&'static str, A);
 struct Dr<'a, B:'a+Foo>(&'static str, &'a B);
-struct Pt<A,B: Foo>(&'static str, A, B);
-struct Pr<'a, 'b, B:'a+'b+Foo>(&'static str, &'a B, &'b B);
-struct St<A: Foo>(&'static str, A);
-struct Sr<'a, B:'a+Foo>(&'static str, &'a B);
+struct Pt<A,B: Foo>(&'static str, #[allow(unused_tuple_struct_fields)] A, B);
+struct Pr<'a, 'b, B:'a+'b+Foo>(&'static str, #[allow(unused_tuple_struct_fields)] &'a B, &'b B);
+struct St<A: Foo>(&'static str, #[allow(unused_tuple_struct_fields)] A);
+struct Sr<'a, B:'a+Foo>(&'static str, #[allow(unused_tuple_struct_fields)] &'a B);
 
 impl<A: Foo> Drop for Dt<A> {
     fn drop(&mut self) { println!("drop {}", self.0); self.1.foo(self.0); }
index 736123ed1198f76dfe22c93818840e2c41aa03b5..e70686774233742021991c2c67c761731fa43787 100644 (file)
@@ -103,7 +103,7 @@ fn dynamic_drop(a: &Allocator, c: bool) {
     };
 }
 
-struct TwoPtrs<'a>(Ptr<'a>, Ptr<'a>);
+struct TwoPtrs<'a>(Ptr<'a>, #[allow(unused_tuple_struct_fields)] Ptr<'a>);
 fn struct_dynamic_drop(a: &Allocator, c0: bool, c1: bool, c: bool) {
     for i in 0..2 {
         let x;
index 23fd86a093b59fd99604ff4a636d1aed03a1d898..04d0d32033a12cdbef4b780b7dfd905c1999fbbf 100644 (file)
@@ -21,7 +21,7 @@ fn drop(&mut self) {
     }
 }
 
-struct Foo<T>(u32, T, Box<for <'r> fn(&'r T) -> String>);
+struct Foo<T>(u32, T, #[allow(unused_tuple_struct_fields)] Box<for <'r> fn(&'r T) -> String>);
 
 unsafe impl<#[may_dangle] T> Drop for Foo<T> {
     fn drop(&mut self) {
index b52a95a701f540fe10fd63894420f7350b4367dd..fbb32cac1284d36004bb74fe0321ad3b16fec95b 100644 (file)
@@ -1,12 +1,10 @@
 // Check that dynamically sized rvalues are forbidden
 
-#![feature(box_syntax)]
-
 pub fn main() {
-    let _x: Box<str> = box *"hello world";
+    let _x: Box<str> = Box::new(*"hello world");
     //~^ ERROR E0277
 
     let array: &[isize] = &[1, 2, 3];
-    let _x: Box<[isize]> = box *array;
+    let _x: Box<[isize]> = Box::new(*array);
     //~^ ERROR E0277
 }
index 15830636b51fe1e5c6f22a32345384dfd51000ed..727f4d843033fd132349d2571fffd4fd812420e3 100644 (file)
@@ -1,20 +1,32 @@
 error[E0277]: the size for values of type `str` cannot be known at compilation time
-  --> $DIR/dst-rvalue.rs:6:28
+  --> $DIR/dst-rvalue.rs:4:33
    |
-LL |     let _x: Box<str> = box *"hello world";
-   |                            ^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+LL |     let _x: Box<str> = Box::new(*"hello world");
+   |                        -------- ^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |                        |
+   |                        required by a bound introduced by this call
    |
    = help: the trait `Sized` is not implemented for `str`
-   = note: the type of a box expression must have a statically known size
+note: required by a bound in `Box::<T>::new`
+  --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
+   |
+LL | impl<T> Box<T> {
+   |      ^ required by this bound in `Box::<T>::new`
 
 error[E0277]: the size for values of type `[isize]` cannot be known at compilation time
-  --> $DIR/dst-rvalue.rs:10:32
+  --> $DIR/dst-rvalue.rs:8:37
    |
-LL |     let _x: Box<[isize]> = box *array;
-   |                                ^^^^^^ doesn't have a size known at compile-time
+LL |     let _x: Box<[isize]> = Box::new(*array);
+   |                            -------- ^^^^^^ doesn't have a size known at compile-time
+   |                            |
+   |                            required by a bound introduced by this call
    |
    = help: the trait `Sized` is not implemented for `[isize]`
-   = note: the type of a box expression must have a statically known size
+note: required by a bound in `Box::<T>::new`
+  --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
+   |
+LL | impl<T> Box<T> {
+   |      ^ required by this bound in `Box::<T>::new`
 
 error: aborting due to 2 previous errors
 
index 25ec07b88a665dfd165d9f5ec32b617f70c1cdd1..5da9381f8378311eee8d1e8fba59d4e222470be9 100644 (file)
@@ -1,5 +1,4 @@
 // run-pass
-#![feature(box_syntax)]
 
 struct Fat<T: ?Sized> {
     f1: isize,
@@ -111,7 +110,7 @@ pub fn main() {
     assert_eq!((*f2)[1], 2);
 
     // Nested Box.
-    let f1 : Box<Fat<[isize; 3]>> = box Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] };
+    let f1 : Box<Fat<[isize; 3]>> = Box::new(Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] });
     foo(&*f1);
     let f2 : Box<Fat<[isize]>> = f1;
     foo(&*f2);
index ec6bc72192d4ffc0e1bb53fcdeba275da23ed433..7ac6f03925bb1adc27cfa042567827f3b9ea6864 100644 (file)
@@ -1,5 +1,4 @@
 // run-pass
-#![feature(box_syntax)]
 
 struct Fat<T: ?Sized> {
     f1: isize,
index 65dc9166330d1e701386426fcbe985ea58ecce8e..8e162d5c455127be15e81f1f6093845bcc974400 100644 (file)
@@ -4,6 +4,7 @@
 
 use std::mem;
 
+#[allow(unused_tuple_struct_fields)]
 enum ADT {
     First(u32, u32),
     Second(u64)
index eb60aaf4b2d04156abc899b205a47ce2c8c18959..65ab411dbcbe640d09491ff7e1717aa49883771b 100644 (file)
@@ -27,13 +27,14 @@ enum CLike3 {
     D
 }
 
+#[allow(unused_tuple_struct_fields)]
 enum ADT {
     First(u32, u32),
     Second(u64)
 }
 
 enum NullablePointer {
-    Something(&'static u32),
+    Something(#[allow(unused_tuple_struct_fields)] &'static u32),
     Nothing
 }
 
index 27fab1bb505b25581503ca38925cac2a1e69fa0b..fc94d281c77e20578c4065eef3fd37f04d39e2b5 100644 (file)
@@ -6,9 +6,9 @@
 enum Eu64 {
     //~^ ERROR discriminant value `0` assigned more than once
     Au64 = 0,
-    //~^NOTE first assignment of `0`
+    //~^NOTE `0` assigned here
     Bu64 = 0x8000_0000_0000_0000
-    //~^NOTE second assignment of `0` (overflowed from `9223372036854775808`)
+    //~^NOTE `0` (overflowed from `9223372036854775808`) assigned here
 }
 
 fn main() {}
index eacea86d67e5523cd3c2e93b7caf1b0ed28d7d69..be3d7c64e28bd988febb63697c6a99279a7b6736 100644 (file)
@@ -5,10 +5,10 @@ LL | enum Eu64 {
    | ^^^^^^^^^
 LL |
 LL |     Au64 = 0,
-   |            - first assignment of `0`
+   |            - `0` assigned here
 LL |
 LL |     Bu64 = 0x8000_0000_0000_0000
-   |            --------------------- second assignment of `0` (overflowed from `9223372036854775808`)
+   |            --------------------- `0` (overflowed from `9223372036854775808`) assigned here
 
 error: aborting due to previous error
 
index 5aa6a786339cf214085639d9ba72df3c5696a983..f53fda864d6558224b082fb5f454e446b7b3a977 100644 (file)
@@ -1,9 +1,9 @@
 enum Enum {
     //~^ ERROR discriminant value `3` assigned more than once
     P = 3,
-    //~^ NOTE first assignment of `3`
+    //~^ NOTE `3` assigned here
     X = 3,
-    //~^ NOTE second assignment of `3`
+    //~^ NOTE `3` assigned here
     Y = 5
 }
 
@@ -11,20 +11,43 @@ enum Enum {
 enum EnumOverflowRepr {
     //~^ ERROR discriminant value `1` assigned more than once
     P = 257,
-    //~^ NOTE first assignment of `1` (overflowed from `257`)
+    //~^ NOTE `1` (overflowed from `257`) assigned here
     X = 513,
-    //~^ NOTE second assignment of `1` (overflowed from `513`)
+    //~^ NOTE `1` (overflowed from `513`) assigned here
 }
 
 #[repr(i8)]
 enum NegDisEnum {
     //~^ ERROR discriminant value `-1` assigned more than once
     First = -1,
-    //~^ NOTE first assignment of `-1`
+    //~^ NOTE `-1` assigned here
     Second = -2,
-    //~^ NOTE assigned discriminant for `Last` was incremented from this discriminant
+    //~^ NOTE discriminant for `Last` incremented from this startpoint (`Second` + 1 variant later => `Last` = -1)
     Last,
-    //~^ NOTE second assignment of `-1`
+    //~^ NOTE `-1` assigned here
+}
+
+enum MultipleDuplicates {
+    //~^ ERROR discriminant value `0` assigned more than once
+    //~^^ ERROR discriminant value `-2` assigned more than once
+    V0,
+    //~^ NOTE `0` assigned here
+    V1 = 0,
+    //~^ NOTE `0` assigned here
+    V2,
+    V3,
+    V4 = 0,
+    //~^ NOTE `0` assigned here
+    V5 = -2,
+    //~^ NOTE discriminant for `V7` incremented from this startpoint (`V5` + 2 variants later => `V7` = 0)
+    //~^^ NOTE `-2` assigned here
+    V6,
+    V7,
+    //~^ NOTE `0` assigned here
+    V8 = -3,
+    //~^ NOTE discriminant for `V9` incremented from this startpoint (`V8` + 1 variant later => `V9` = -2)
+    V9,
+    //~^ NOTE `-2` assigned here
 }
 
 fn main() {
index ff6113646bb8afbf211328a8d056ca4de7f4aa71..64562fefc866c2dc707265a34df1ba346764f5fa 100644 (file)
@@ -5,10 +5,10 @@ LL | enum Enum {
    | ^^^^^^^^^
 LL |
 LL |     P = 3,
-   |         - first assignment of `3`
+   |         - `3` assigned here
 LL |
 LL |     X = 3,
-   |         - second assignment of `3`
+   |         - `3` assigned here
 
 error[E0081]: discriminant value `1` assigned more than once
   --> $DIR/E0081.rs:11:1
@@ -17,10 +17,10 @@ LL | enum EnumOverflowRepr {
    | ^^^^^^^^^^^^^^^^^^^^^
 LL |
 LL |     P = 257,
-   |         --- first assignment of `1` (overflowed from `257`)
+   |         --- `1` (overflowed from `257`) assigned here
 LL |
 LL |     X = 513,
-   |         --- second assignment of `1` (overflowed from `513`)
+   |         --- `1` (overflowed from `513`) assigned here
 
 error[E0081]: discriminant value `-1` assigned more than once
   --> $DIR/E0081.rs:20:1
@@ -29,14 +29,50 @@ LL | enum NegDisEnum {
    | ^^^^^^^^^^^^^^^
 LL |
 LL |     First = -1,
-   |             -- first assignment of `-1`
+   |             -- `-1` assigned here
 LL |
 LL |     Second = -2,
-   |     ----------- assigned discriminant for `Last` was incremented from this discriminant
+   |     ----------- discriminant for `Last` incremented from this startpoint (`Second` + 1 variant later => `Last` = -1)
 LL |
 LL |     Last,
-   |     ---- second assignment of `-1`
+   |     ---- `-1` assigned here
 
-error: aborting due to 3 previous errors
+error[E0081]: discriminant value `0` assigned more than once
+  --> $DIR/E0081.rs:30:1
+   |
+LL | enum MultipleDuplicates {
+   | ^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL |     V0,
+   |     -- `0` assigned here
+LL |
+LL |     V1 = 0,
+   |          - `0` assigned here
+...
+LL |     V4 = 0,
+   |          - `0` assigned here
+LL |
+LL |     V5 = -2,
+   |     ------- discriminant for `V7` incremented from this startpoint (`V5` + 2 variants later => `V7` = 0)
+...
+LL |     V7,
+   |     -- `0` assigned here
+
+error[E0081]: discriminant value `-2` assigned more than once
+  --> $DIR/E0081.rs:30:1
+   |
+LL | enum MultipleDuplicates {
+   | ^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL |     V5 = -2,
+   |          -- `-2` assigned here
+...
+LL |     V8 = -3,
+   |     ------- discriminant for `V9` incremented from this startpoint (`V8` + 1 variant later => `V9` = -2)
+LL |
+LL |     V9,
+   |     -- `-2` assigned here
+
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0081`.
index 14f02163a8320f212a099abdf0e1a134c8b1b33e..d2bba88211ea8c455c7915eb975c7c9fffc698a1 100644 (file)
@@ -5,6 +5,11 @@ LL |     let x = if true { 10i32 } else { 10u32 };
    |                       -----          ^^^^^ expected `i32`, found `u32`
    |                       |
    |                       expected because of this
+   |
+help: change the type of the numeric literal from `u32` to `i32`
+   |
+LL |     let x = if true { 10i32 } else { 10i32 };
+   |                                        ~~~
 
 error: aborting due to previous error
 
index 9fa190d6c9df3d0c6d047a6198a402896a441456..f1fffdb1e7ef8d6443b84aef1cc8e73d1c7be692 100644 (file)
@@ -10,6 +10,11 @@ LL | |         2u32
    | |         ^^^^ expected `i32`, found `u32`
 LL | |     };
    | |_____- `if` and `else` have incompatible types
+   |
+help: change the type of the numeric literal from `u32` to `i32`
+   |
+LL |         2i32
+   |          ~~~
 
 error[E0308]: `if` and `else` have incompatible types
   --> $DIR/if-else-type-mismatch.rs:8:38
@@ -18,6 +23,11 @@ LL |     let _ = if true { 42i32 } else { 42u32 };
    |                       -----          ^^^^^ expected `i32`, found `u32`
    |                       |
    |                       expected because of this
+   |
+help: change the type of the numeric literal from `u32` to `i32`
+   |
+LL |     let _ = if true { 42i32 } else { 42i32 };
+   |                                        ~~~
 
 error[E0308]: `if` and `else` have incompatible types
   --> $DIR/if-else-type-mismatch.rs:13:9
index 518aa20dd68ceefc4ae314f044eac8a496ee9d5f..0594b1384ec2345fb6bd7f95c5e9ac9c02d671c6 100644 (file)
@@ -3,6 +3,9 @@
     #[link_ordinal(42)]
     //~^ ERROR: the `#[link_ordinal]` attribute is an experimental feature
     fn foo();
+    #[link_ordinal(5)]
+    //~^ ERROR: the `#[link_ordinal]` attribute is an experimental feature
+    static mut imported_variable: i32;
 }
 
 fn main() {}
index dbee5f316b0a9559b13f3eb309744f89d184f013..d39969b61cac23986498fca82859c3e58f99bc62 100644 (file)
@@ -7,6 +7,15 @@ LL |     #[link_ordinal(42)]
    = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
    = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
 
-error: aborting due to previous error
+error[E0658]: the `#[link_ordinal]` attribute is an experimental feature
+  --> $DIR/feature-gate-raw-dylib-2.rs:6:5
+   |
+LL |     #[link_ordinal(5)]
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
+   = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
index 5d6796b49448a5dc50b3cea07535c524aef5d98c..310d1f720eb7cb6800ed21c32312e80700d1ba9d 100644 (file)
@@ -212,7 +212,7 @@ note: the lint level is defined here
 LL | #![warn(unused_attributes, unknown_lints)]
    |         ^^^^^^^^^^^^^^^^^
 
-warning: `#[automatically_derived]` only has an effect on items
+warning: `#[automatically_derived]` only has an effect on implementation blocks
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:266:1
    |
 LL | #[automatically_derived]
@@ -515,25 +515,25 @@ warning: `#[path]` only has an effect on modules
 LL |     #[path = "3800"] impl S { }
    |     ^^^^^^^^^^^^^^^^
 
-warning: `#[automatically_derived]` only has an effect on items
+warning: `#[automatically_derived]` only has an effect on implementation blocks
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:269:17
    |
 LL |     mod inner { #![automatically_derived] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: `#[automatically_derived]` only has an effect on items
+warning: `#[automatically_derived]` only has an effect on implementation blocks
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:272:5
    |
 LL |     #[automatically_derived] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: `#[automatically_derived]` only has an effect on items
+warning: `#[automatically_derived]` only has an effect on implementation blocks
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:275:5
    |
 LL |     #[automatically_derived] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: `#[automatically_derived]` only has an effect on items
+warning: `#[automatically_derived]` only has an effect on implementation blocks
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:278:5
    |
 LL |     #[automatically_derived] type T = S;
@@ -923,7 +923,7 @@ warning: `#[must_use]` has no effect when applied to a type alias
 LL |     #[must_use] type T = S;
    |     ^^^^^^^^^^^
 
-warning: `#[must_use]` has no effect when applied to an item
+warning: `#[must_use]` has no effect when applied to an implementation block
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:614:5
    |
 LL |     #[must_use] impl S { }
diff --git a/src/test/ui/fmt/struct-field-as-captured-argument.fixed b/src/test/ui/fmt/struct-field-as-captured-argument.fixed
new file mode 100644 (file)
index 0000000..f7244f6
--- /dev/null
@@ -0,0 +1,18 @@
+// run-rustfix
+
+#[derive(Debug)]
+struct Foo {
+    field: usize,
+}
+
+fn main() {
+    let foo = Foo { field: 0 };
+    let bar = 3;
+    format!("{0}", foo.field); //~ ERROR invalid format string: field access isn't supported
+    format!("{1} {} {bar}", "aa", foo.field); //~ ERROR invalid format string: field access isn't supported
+    format!("{2} {} {1} {bar}", "aa", "bb", foo.field); //~ ERROR invalid format string: field access isn't supported
+    format!("{1} {} {baz}", "aa", foo.field, baz = 3); //~ ERROR invalid format string: field access isn't supported
+    format!("{1:?} {} {baz}", "aa", foo.field, baz = 3); //~ ERROR invalid format string: field access isn't supported
+    format!("{1:#?} {} {baz}", "aa", foo.field, baz = 3); //~ ERROR invalid format string: field access isn't supported
+    format!("{1:.3} {} {baz}", "aa", foo.field, baz = 3); //~ ERROR invalid format string: field access isn't supported
+}
diff --git a/src/test/ui/fmt/struct-field-as-captured-argument.rs b/src/test/ui/fmt/struct-field-as-captured-argument.rs
new file mode 100644 (file)
index 0000000..ab5f255
--- /dev/null
@@ -0,0 +1,18 @@
+// run-rustfix
+
+#[derive(Debug)]
+struct Foo {
+    field: usize,
+}
+
+fn main() {
+    let foo = Foo { field: 0 };
+    let bar = 3;
+    format!("{foo.field}"); //~ ERROR invalid format string: field access isn't supported
+    format!("{foo.field} {} {bar}", "aa"); //~ ERROR invalid format string: field access isn't supported
+    format!("{foo.field} {} {1} {bar}", "aa", "bb"); //~ ERROR invalid format string: field access isn't supported
+    format!("{foo.field} {} {baz}", "aa", baz = 3); //~ ERROR invalid format string: field access isn't supported
+    format!("{foo.field:?} {} {baz}", "aa", baz = 3); //~ ERROR invalid format string: field access isn't supported
+    format!("{foo.field:#?} {} {baz}", "aa", baz = 3); //~ ERROR invalid format string: field access isn't supported
+    format!("{foo.field:.3} {} {baz}", "aa", baz = 3); //~ ERROR invalid format string: field access isn't supported
+}
diff --git a/src/test/ui/fmt/struct-field-as-captured-argument.stderr b/src/test/ui/fmt/struct-field-as-captured-argument.stderr
new file mode 100644 (file)
index 0000000..7ea8b40
--- /dev/null
@@ -0,0 +1,79 @@
+error: invalid format string: field access isn't supported
+  --> $DIR/struct-field-as-captured-argument.rs:11:15
+   |
+LL |     format!("{foo.field}");
+   |               ^^^^^^^^^ not supported in format string
+   |
+help: consider using a positional formatting argument instead
+   |
+LL |     format!("{0}", foo.field);
+   |               ~  +++++++++++
+
+error: invalid format string: field access isn't supported
+  --> $DIR/struct-field-as-captured-argument.rs:12:15
+   |
+LL |     format!("{foo.field} {} {bar}", "aa");
+   |               ^^^^^^^^^ not supported in format string
+   |
+help: consider using a positional formatting argument instead
+   |
+LL |     format!("{1} {} {bar}", "aa", foo.field);
+   |               ~                 +++++++++++
+
+error: invalid format string: field access isn't supported
+  --> $DIR/struct-field-as-captured-argument.rs:13:15
+   |
+LL |     format!("{foo.field} {} {1} {bar}", "aa", "bb");
+   |               ^^^^^^^^^ not supported in format string
+   |
+help: consider using a positional formatting argument instead
+   |
+LL |     format!("{2} {} {1} {bar}", "aa", "bb", foo.field);
+   |               ~                           +++++++++++
+
+error: invalid format string: field access isn't supported
+  --> $DIR/struct-field-as-captured-argument.rs:14:15
+   |
+LL |     format!("{foo.field} {} {baz}", "aa", baz = 3);
+   |               ^^^^^^^^^ not supported in format string
+   |
+help: consider using a positional formatting argument instead
+   |
+LL |     format!("{1} {} {baz}", "aa", foo.field, baz = 3);
+   |               ~                 +++++++++++
+
+error: invalid format string: field access isn't supported
+  --> $DIR/struct-field-as-captured-argument.rs:15:15
+   |
+LL |     format!("{foo.field:?} {} {baz}", "aa", baz = 3);
+   |               ^^^^^^^^^ not supported in format string
+   |
+help: consider using a positional formatting argument instead
+   |
+LL |     format!("{1:?} {} {baz}", "aa", foo.field, baz = 3);
+   |               ~                   +++++++++++
+
+error: invalid format string: field access isn't supported
+  --> $DIR/struct-field-as-captured-argument.rs:16:15
+   |
+LL |     format!("{foo.field:#?} {} {baz}", "aa", baz = 3);
+   |               ^^^^^^^^^ not supported in format string
+   |
+help: consider using a positional formatting argument instead
+   |
+LL |     format!("{1:#?} {} {baz}", "aa", foo.field, baz = 3);
+   |               ~                    +++++++++++
+
+error: invalid format string: field access isn't supported
+  --> $DIR/struct-field-as-captured-argument.rs:17:15
+   |
+LL |     format!("{foo.field:.3} {} {baz}", "aa", baz = 3);
+   |               ^^^^^^^^^ not supported in format string
+   |
+help: consider using a positional formatting argument instead
+   |
+LL |     format!("{1:.3} {} {baz}", "aa", foo.field, baz = 3);
+   |               ~                    +++++++++++
+
+error: aborting due to 7 previous errors
+
index 5a92bcd37b6eea8e7f96dee471cc3e2167a3980e..5d924555625cdc408a9a4495e9aba100b62fdc53 100644 (file)
@@ -1,4 +1,4 @@
-// check-pass
+// check-fail
 
 trait Trait {
     type Type;
@@ -17,6 +17,7 @@ fn f<'a, 'b>(_: <&'a &'b () as Trait>::Type)
 
 fn g<'a, 'b>() {
     f::<'a, 'b>(());
+    //~^ ERROR lifetime may not live long enough
 }
 
 fn main() {}
diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type-2.stderr b/src/test/ui/fn/implied-bounds-unnorm-associated-type-2.stderr
new file mode 100644 (file)
index 0000000..0c3df04
--- /dev/null
@@ -0,0 +1,17 @@
+error: lifetime may not live long enough
+  --> $DIR/implied-bounds-unnorm-associated-type-2.rs:19:5
+   |
+LL | fn g<'a, 'b>() {
+   |      --  -- lifetime `'b` defined here
+   |      |
+   |      lifetime `'a` defined here
+LL |     f::<'a, 'b>(());
+   |     ^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+   = note: requirement occurs because of a function pointer to `f`
+   = note: the function `f` is invariant over the parameter `'a`
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: aborting due to previous error
+
index dc25ac086137a9ba13e715f4688286ba40e04f84..888f74cf6b33745b76e8351f0e1edc03a9de69be 100644 (file)
@@ -1,6 +1,4 @@
-// check-fail
-// See issue #91899. If we treat unnormalized args as WF, `Self` can also be a
-// source of unsoundness.
+// check-pass
 
 pub trait Yokeable<'a>: 'static {
     type Output: 'a;
@@ -17,7 +15,6 @@ pub trait ZeroCopyFrom<C: ?Sized>: for<'a> Yokeable<'a> {
 
 impl<T> ZeroCopyFrom<[T]> for &'static [T] {
     fn zero_copy_from<'b>(cart: &'b [T]) -> &'b [T] {
-        //~^ the parameter
         cart
     }
 }
diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type-3.stderr b/src/test/ui/fn/implied-bounds-unnorm-associated-type-3.stderr
deleted file mode 100644 (file)
index 95cf4fb..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/implied-bounds-unnorm-associated-type-3.rs:19:5
-   |
-LL |     fn zero_copy_from<'b>(cart: &'b [T]) -> &'b [T] {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `[T]` will meet its required lifetime bounds
-   |
-help: consider adding an explicit lifetime bound...
-   |
-LL | impl<T: 'static> ZeroCopyFrom<[T]> for &'static [T] {
-   |       +++++++++
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0310`.
diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type-4.rs b/src/test/ui/fn/implied-bounds-unnorm-associated-type-4.rs
new file mode 100644 (file)
index 0000000..1285925
--- /dev/null
@@ -0,0 +1,24 @@
+// A regression test for #98543
+
+trait Trait {
+    type Type;
+}
+
+impl<T> Trait for T {
+    type Type = ();
+}
+
+fn f<'a, 'b>(s: &'b str, _: <&'a &'b () as Trait>::Type) -> &'a str
+where
+    &'a &'b (): Trait, // <- adding this bound is the change from #91068
+{
+    s
+}
+
+fn main() {
+    let x = String::from("Hello World!");
+    let y = f(&x, ());
+    drop(x);
+    //~^ ERROR cannot move out of `x` because it is borrowed
+    println!("{}", y);
+}
diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type-4.stderr b/src/test/ui/fn/implied-bounds-unnorm-associated-type-4.stderr
new file mode 100644 (file)
index 0000000..fcbaa91
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0505]: cannot move out of `x` because it is borrowed
+  --> $DIR/implied-bounds-unnorm-associated-type-4.rs:21:10
+   |
+LL |     let y = f(&x, ());
+   |               -- borrow of `x` occurs here
+LL |     drop(x);
+   |          ^ move out of `x` occurs here
+LL |
+LL |     println!("{}", y);
+   |                    - borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0505`.
diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type-5.rs b/src/test/ui/fn/implied-bounds-unnorm-associated-type-5.rs
new file mode 100644 (file)
index 0000000..2a9a6a8
--- /dev/null
@@ -0,0 +1,23 @@
+trait Trait<'a>: 'a {
+    type Type;
+}
+
+// if the `T: 'a` bound gets implied we would probably get ub here again
+impl<'a, T> Trait<'a> for T {
+    //~^ ERROR the parameter type `T` may not live long enough
+    type Type = ();
+}
+
+fn f<'a, 'b>(s: &'b str, _: <&'b () as Trait<'a>>::Type) -> &'a str
+where
+    &'b (): Trait<'a>,
+{
+    s
+}
+
+fn main() {
+    let x = String::from("Hello World!");
+    let y = f(&x, ());
+    drop(x);
+    println!("{}", y);
+}
diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type-5.stderr b/src/test/ui/fn/implied-bounds-unnorm-associated-type-5.stderr
new file mode 100644 (file)
index 0000000..458756a
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0309]: the parameter type `T` may not live long enough
+  --> $DIR/implied-bounds-unnorm-associated-type-5.rs:6:13
+   |
+LL | impl<'a, T> Trait<'a> for T {
+   |             ^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
+   |
+note: ...that is required by this bound
+  --> $DIR/implied-bounds-unnorm-associated-type-5.rs:1:18
+   |
+LL | trait Trait<'a>: 'a {
+   |                  ^^
+help: consider adding an explicit lifetime bound...
+   |
+LL | impl<'a, T: 'a> Trait<'a> for T {
+   |           ++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0309`.
index 04b6f4dd84e2e92cfadbb794e1f01ec73c6cc4ab..d58d25036c5bb78898587ca026e1d0a44bee1552 100644 (file)
@@ -1,6 +1,6 @@
 // check-fail
-// See issue #91068. Types in the substs of an associated type can't be implied
-// to be WF, since they don't actually have to be constructed.
+// See issue #91068. We check that the unnormalized associated types in
+// function signatures are implied
 
 trait Trait {
     type Type;
@@ -12,12 +12,12 @@ impl<T> Trait for T {
 
 fn f<'a, 'b>(s: &'b str, _: <&'a &'b () as Trait>::Type) -> &'a str {
     s
-    //~^ ERROR lifetime may not live long enough
 }
 
 fn main() {
     let x = String::from("Hello World!");
     let y = f(&x, ());
     drop(x);
+    //~^ ERROR cannot move out of `x` because it is borrowed
     println!("{}", y);
 }
index 8096f08385c8c67b7a6c7fe27962b7e8260a184a..e35f46e4439a90b1c9e94ac8396b8a2077b9851b 100644 (file)
@@ -1,14 +1,14 @@
-error: lifetime may not live long enough
-  --> $DIR/implied-bounds-unnorm-associated-type.rs:14:5
+error[E0505]: cannot move out of `x` because it is borrowed
+  --> $DIR/implied-bounds-unnorm-associated-type.rs:20:10
    |
-LL | fn f<'a, 'b>(s: &'b str, _: <&'a &'b () as Trait>::Type) -> &'a str {
-   |      --  -- lifetime `'b` defined here
-   |      |
-   |      lifetime `'a` defined here
-LL |     s
-   |     ^ 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`
+LL |     let y = f(&x, ());
+   |               -- borrow of `x` occurs here
+LL |     drop(x);
+   |          ^ move out of `x` occurs here
+LL |
+LL |     println!("{}", y);
+   |                    - borrow later used here
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0505`.
index 6960c4fd8673537f30dd5ffe960a25034a5ea4a4..e79f6a75fdec5df51c0cb9b48aea32af9f6cd0f8 100644 (file)
@@ -31,6 +31,14 @@ LL | |             }
    |
    = note:   expected type `!`
            found unit type `()`
+note: the function expects a value to always be returned, but loops might run zero times
+  --> $DIR/break-while-condition.rs:24:13
+   |
+LL |             while false {
+   |             ^^^^^^^^^^^ this might have zero elements to iterate on
+LL |                 return
+   |                 ------ if the loop doesn't execute, this value would never get returned
+   = help: return a value for the case when the loop has zero elements to iterate on, or consider changing the return type to account for that possibility
 
 error: aborting due to 3 previous errors
 
index 74c60d98154dd3da107bb7672c5d40afa5129c65..3c756a86fc5a5e212eb99906c4c128a6786da2cb 100644 (file)
@@ -18,7 +18,7 @@
 use std::ops::Generator;
 
 const FOO_SIZE: usize = 1024;
-struct Foo([u8; FOO_SIZE]);
+struct Foo(#[allow(unused_tuple_struct_fields)] [u8; FOO_SIZE]);
 
 impl Drop for Foo {
     fn drop(&mut self) {}
index 7938fc8097cd2d54267a1b1f4d59b82005ffa240..b98da1ed8be6e50b6999bf36ab44742706b8fdbe 100644 (file)
@@ -11,6 +11,12 @@ note: return type inferred to be `Result<{integer}, _>` here
    |
 LL |             return Ok(6);
    |                    ^^^^^
+help: try wrapping the expression in a variant of `Result`
+   |
+LL |         Ok(5)
+   |         +++ +
+LL |         Err(5)
+   |         ++++ +
 
 error[E0271]: type mismatch resolving `<[generator@$DIR/type-mismatch-signature-deduction.rs:7:5: 7:7] as Generator>::Return == i32`
   --> $DIR/type-mismatch-signature-deduction.rs:5:13
diff --git a/src/test/ui/generic-associated-types/bugs/issue-87748.rs b/src/test/ui/generic-associated-types/bugs/issue-87748.rs
deleted file mode 100644 (file)
index a3d00ee..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-// check-fail
-// known-bug: #87748
-
-// This should pass, but unnormalized input args aren't treated as implied.
-
-#![feature(generic_associated_types)]
-
-trait MyTrait {
-    type Assoc<'a, 'b> where 'b: 'a;
-    fn do_sth(arg: Self::Assoc<'_, '_>);
-}
-
-struct Foo;
-
-impl MyTrait for Foo {
-    type Assoc<'a, 'b> = u32 where 'b: 'a;
-
-    fn do_sth(_: u32) {}
-    // fn do_sth(_: Self::Assoc<'static, 'static>) {}
-    // fn do_sth(_: Self::Assoc<'_, '_>) {}
-}
-
-fn main() {}
diff --git a/src/test/ui/generic-associated-types/bugs/issue-87748.stderr b/src/test/ui/generic-associated-types/bugs/issue-87748.stderr
deleted file mode 100644 (file)
index ac197df..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-error[E0478]: lifetime bound not satisfied
-  --> $DIR/issue-87748.rs:18:5
-   |
-LL |     fn do_sth(_: u32) {}
-   |     ^^^^^^^^^^^^^^^^^
-   |
-note: lifetime parameter instantiated with the anonymous lifetime as defined here
-  --> $DIR/issue-87748.rs:18:5
-   |
-LL |     fn do_sth(_: u32) {}
-   |     ^^^^^^^^^^^^^^^^^
-note: but lifetime parameter must outlive the anonymous lifetime as defined here
-  --> $DIR/issue-87748.rs:18:5
-   |
-LL |     fn do_sth(_: u32) {}
-   |     ^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0478`.
diff --git a/src/test/ui/generic-associated-types/issue-87748.rs b/src/test/ui/generic-associated-types/issue-87748.rs
new file mode 100644 (file)
index 0000000..1a1ab9b
--- /dev/null
@@ -0,0 +1,23 @@
+// Checks that we properly add implied bounds from unnormalized projections in
+// inputs when typechecking functions.
+
+// check-pass
+
+#![feature(generic_associated_types)]
+
+trait MyTrait {
+    type Assoc<'a, 'b> where 'b: 'a;
+    fn do_sth(arg: Self::Assoc<'_, '_>);
+    fn do_sth2(arg: Self::Assoc<'_, '_>) {}
+}
+
+struct Foo;
+
+impl MyTrait for Foo {
+    type Assoc<'a, 'b> = u32 where 'b: 'a;
+
+    fn do_sth(_: u32) {}
+    fn do_sth2(_: Self::Assoc<'static, 'static>) {}
+}
+
+fn main() {}
index 9e5eaa72c152fc9c70f819a54914a94f87f48a86..834b15be1c59db56354ce0a94d06e4a5ff25a663 100644 (file)
@@ -5,7 +5,7 @@
 
 extern crate default_type_params_xc;
 
-struct Vec<T, A = default_type_params_xc::Heap>(Option<(T,A)>);
+struct Vec<T, A = default_type_params_xc::Heap>(#[allow(unused_tuple_struct_fields)] Option<(T,A)>);
 
 struct Foo;
 
index a8ea1d5069bcf752e889ddc1f5226dec8cd18797..9610bdcb3382e95b9647afed62457cf3c73443b8 100644 (file)
@@ -1,5 +1,5 @@
 // run-pass
 #![allow(non_camel_case_types)]
-enum wrapper<T> { wrapped(T), }
+enum wrapper<T> { wrapped(#[allow(unused_tuple_struct_fields)] T), }
 
 pub fn main() { let _w = wrapper::wrapped(vec![1, 2, 3, 4, 5]); }
index 570c982cc8700a5eba9d977ed1740d289396f155..aa879f01a583f025247c3edb8792d86f288234a6 100644 (file)
@@ -1,7 +1,7 @@
 // run-pass
 // pretty-expanded FIXME #23616
 
-struct S<T>(T);
+struct S<T>(#[allow(unused_tuple_struct_fields)] T);
 
 pub fn main() {
     let _s = S(2);
index 9126ac167cf2aaf3e600bce0368931b04ffcafbd..501acb6e1638a83613f765c044bf91cec3178889 100644 (file)
@@ -76,7 +76,7 @@ impl<T> Trait2<T> for Foo {
     fn qux<'a>(x: &'a i32) -> &i32 { x } //~ ERROR functions generic over types or consts must be mangled
 }
 
-pub struct Bar<T>(T);
+pub struct Bar<T>(#[allow(unused_tuple_struct_fields)] T);
 
 impl<T> Bar<T> {
     
@@ -111,7 +111,7 @@ impl<T> Trait3 for Bar<T> {
     fn baz<U>() {} //~ ERROR functions generic over types or consts must be mangled
 }
 
-pub struct Baz<'a>(&'a i32);
+pub struct Baz<'a>(#[allow(unused_tuple_struct_fields)] &'a i32);
 
 impl<'a> Baz<'a> {
     #[no_mangle]
index e283cf4bfe544335d0c59a7221c6e190d8318c51..74e407078e8b19cfa1a8b6ce5ada61f05aa35b5b 100644 (file)
@@ -76,7 +76,7 @@ fn baz(x: &i32) -> &i32 { x } //~ ERROR functions generic over types or consts m
     fn qux<'a>(x: &'a i32) -> &i32 { x } //~ ERROR functions generic over types or consts must be mangled
 }
 
-pub struct Bar<T>(T);
+pub struct Bar<T>(#[allow(unused_tuple_struct_fields)] T);
 
 impl<T> Bar<T> {
     #[no_mangle]
@@ -111,7 +111,7 @@ extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be
     fn baz<U>() {} //~ ERROR functions generic over types or consts must be mangled
 }
 
-pub struct Baz<'a>(&'a i32);
+pub struct Baz<'a>(#[allow(unused_tuple_struct_fields)] &'a i32);
 
 impl<'a> Baz<'a> {
     #[no_mangle]
index 74f5b701d98a54153ff5e1b95c2ed308b0c5490a..b344da1c7ddeba73872bdaf08e81ba0ad160544b 100644 (file)
@@ -1,7 +1,7 @@
 // run-pass
 #![allow(non_camel_case_types)]
 
-enum list<T> { cons(Box<T>, Box<list<T>>), nil, }
+enum list<T> { #[allow(unused_tuple_struct_fields)] cons(Box<T>, Box<list<T>>), nil, }
 
 pub fn main() {
     let _a: list<isize> =
index aa26183a0d491aed4ae6609f44b0051f5af4ca63..35de3c1f7124693748d53f319e7c2ad50208402a 100644 (file)
@@ -5,6 +5,6 @@
 // This used to cause memory corruption in stage 0.
 // pretty-expanded FIXME #23616
 
-enum thing<K> { some(K), }
+enum thing<K> { some(#[allow(unused_tuple_struct_fields)] K), }
 
 pub fn main() { let _x = thing::some("hi".to_string()); }
index cc85e6e0f0a8d818e2c35e8a09d2054b07cc542f..c5772e84193ac7ff67a5d50ffcbf6c1315af5a70 100644 (file)
@@ -3,6 +3,6 @@
 
 // pretty-expanded FIXME #23616
 
-enum clam<T> { a(T), }
+enum clam<T> { a(#[allow(unused_tuple_struct_fields)] T), }
 
 pub fn main() { let _c = clam::a(3); }
index 67f2ccdde34a1c4bd3c4b0bbde8ed0bb0d002ca7..31fc2178d6d630db4f1c804e9c300885f441d44f 100644 (file)
@@ -6,7 +6,7 @@
 
 #![allow(unused_variables)]
 
-enum option<T> { some(Box<T>), none, }
+enum option<T> { some(#[allow(unused_tuple_struct_fields)] Box<T>), none, }
 
 pub fn main() {
     let mut a: option<isize> = option::some::<isize>(Box::new(10));
index 172bf218c0d4cd7244dcdbbeb4a3cd3f0a62ccd2..de9348f5397099bf5267a8426b28d084fd7bb47e 100644 (file)
@@ -7,7 +7,6 @@ trait SomeTrait<'a> {
 fn give_me_ice<T>() {
     callee::<fn(&()) -> <T as SomeTrait<'_>>::Associated>();
     //~^ ERROR the trait bound `for<'r> T: SomeTrait<'r>` is not satisfied [E0277]
-    //~| ERROR the trait bound `for<'r> T: SomeTrait<'r>` is not satisfied [E0277]
 }
 
 fn callee<T: Fn<(&'static (),)>>() {
index ecca4b999e7e8c1c04bb230261d1c50a8646e545..6a948a116e03bf3bf7477cb94b5060e05bebe960 100644 (file)
@@ -9,17 +9,6 @@ help: consider restricting type parameter `T`
 LL | fn give_me_ice<T: for<'r> SomeTrait<'r>>() {
    |                 +++++++++++++++++++++++
 
-error[E0277]: the trait bound `for<'r> T: SomeTrait<'r>` is not satisfied
-  --> $DIR/issue-85455.rs:8:14
-   |
-LL |     callee::<fn(&()) -> <T as SomeTrait<'_>>::Associated>();
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'r> SomeTrait<'r>` is not implemented for `T`
-   |
-help: consider restricting type parameter `T`
-   |
-LL | fn give_me_ice<T: for<'r> SomeTrait<'r>>() {
-   |                 +++++++++++++++++++++++
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0277`.
index 68da46d46bd14a20fa23b25d9aa33aba934a73ce..1461e7fd2ddd7fbddddb647509cda2b91bfcfe72 100644 (file)
@@ -4,12 +4,10 @@ warning: function cannot return without recursing
 LL | / fn no_hrtb<'b, T>(mut t: T)
 LL | | where
 LL | |     T: Bar<&'b isize>,
-LL | | {
-...  |
-LL | |     no_hrtb(&mut t);
-   | |     --------------- recursive call site
-LL | | }
-   | |_^ cannot return without recursing
+   | |______________________^ cannot return without recursing
+...
+LL |       no_hrtb(&mut t);
+   |       --------------- recursive call site
    |
    = note: `#[warn(unconditional_recursion)]` on by default
    = help: a `loop` may express intention better if this is on purpose
@@ -20,12 +18,10 @@ warning: function cannot return without recursing
 LL | / fn bar_hrtb<T>(mut t: T)
 LL | | where
 LL | |     T: for<'b> Bar<&'b isize>,
-LL | | {
-...  |
-LL | |     bar_hrtb(&mut t);
-   | |     ---------------- recursive call site
-LL | | }
-   | |_^ cannot return without recursing
+   | |______________________________^ cannot return without recursing
+...
+LL |       bar_hrtb(&mut t);
+   |       ---------------- recursive call site
    |
    = help: a `loop` may express intention better if this is on purpose
 
@@ -35,14 +31,10 @@ warning: function cannot return without recursing
 LL | / fn foo_hrtb_bar_not<'b, T>(mut t: T)
 LL | | where
 LL | |     T: for<'a> Foo<&'a isize> + Bar<&'b isize>,
-LL | | {
-...  |
-LL | |     foo_hrtb_bar_not(&mut t);
-   | |     ------------------------ recursive call site
-LL | |
-LL | |
-LL | | }
-   | |_^ cannot return without recursing
+   | |_______________________________________________^ cannot return without recursing
+...
+LL |       foo_hrtb_bar_not(&mut t);
+   |       ------------------------ recursive call site
    |
    = help: a `loop` may express intention better if this is on purpose
 
@@ -70,12 +62,10 @@ warning: function cannot return without recursing
 LL | / fn foo_hrtb_bar_hrtb<T>(mut t: T)
 LL | | where
 LL | |     T: for<'a> Foo<&'a isize> + for<'b> Bar<&'b isize>,
-LL | | {
-LL | |     // OK -- now we have `T : for<'b> Bar<&'b isize>`.
-LL | |     foo_hrtb_bar_hrtb(&mut t);
-   | |     ------------------------- recursive call site
-LL | | }
-   | |_^ cannot return without recursing
+   | |_______________________________________________________^ cannot return without recursing
+...
+LL |       foo_hrtb_bar_hrtb(&mut t);
+   |       ------------------------- recursive call site
    |
    = help: a `loop` may express intention better if this is on purpose
 
index bc7b5e914e127956045de3e169eb5a3757759961..ffe3d7b81f51eca8b207d10a60cd3f5154cef018 100644 (file)
@@ -18,10 +18,6 @@ note: the following trait bounds were not satisfied:
    |
 LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
    |         ---------     -                          ^^^^^^ unsatisfied trait bound introduced here
-help: one of the expressions' fields has a method of the same name
-   |
-LL |     let filter = map.stream.filterx(|x: &_| true);
-   |                      +++++++
 
 error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>`, but its trait bounds were not satisfied
   --> $DIR/issue-30786.rs:130:24
@@ -43,10 +39,6 @@ note: the following trait bounds were not satisfied:
    |
 LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
    |         ---------     -                          ^^^^^^ unsatisfied trait bound introduced here
-help: one of the expressions' fields has a method of the same name
-   |
-LL |     let count = filter.stream.countx();
-   |                        +++++++
 
 error: aborting due to 2 previous errors
 
index 80f099ce3c80210324aa02e897c43382779c0182..ae21dbce011398b060b4e9fd62a659d24ef74a76 100644 (file)
@@ -38,9 +38,13 @@ fn main() {
     let v = Unit2.m(
         //~^ ERROR type mismatch
         L {
-        //~^ ERROR type mismatch
-            f : |x| { drop(x); Unit4 }
-        });
+            //~^ ERROR to be a closure that returns `Unit3`, but it returns `Unit4`
+            f: |x| {
+                drop(x);
+                Unit4
+            },
+        },
+    );
 }
 
 impl<'a> Ty<'a> for Unit2 {
index 79ef56b9fa5cb5d49594db090a9599dafbafd621..8365fd0c79e1b52031fdda59825593ec9c5026b9 100644 (file)
@@ -1,8 +1,8 @@
-error[E0271]: type mismatch resolving `for<'r> <L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:20]> as T0<'r, (&'r u8,)>>::O == <_ as Ty<'r>>::V`
+error[E0271]: type mismatch resolving `for<'r> <L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:16: 42:19]> as T0<'r, (&'r u8,)>>::O == <_ as Ty<'r>>::V`
   --> $DIR/issue-62203-hrtb-ice.rs:38:19
    |
 LL |     let v = Unit2.m(
-   |                   ^ type mismatch resolving `for<'r> <L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:20]> as T0<'r, (&'r u8,)>>::O == <_ as Ty<'r>>::V`
+   |                   ^ type mismatch resolving `for<'r> <L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:16: 42:19]> as T0<'r, (&'r u8,)>>::O == <_ as Ty<'r>>::V`
    |
 note: expected this to be `<_ as Ty<'_>>::V`
   --> $DIR/issue-62203-hrtb-ice.rs:21:14
@@ -22,7 +22,7 @@ LL |     where
 LL |         F: for<'r> T0<'r, (<Self as Ty<'r>>::V,), O = <B as Ty<'r>>::V>,
    |                                                   ^^^^^^^^^^^^^^^^^^^^ required by this bound in `T1::m`
 
-error[E0271]: type mismatch resolving `for<'r> <[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:20] as FnOnce<((&'r u8,),)>>::Output == Unit3`
+error[E0271]: expected `[closure@$DIR/issue-62203-hrtb-ice.rs:42:16: 42:19]` to be a closure that returns `Unit3`, but it returns `Unit4`
   --> $DIR/issue-62203-hrtb-ice.rs:40:9
    |
 LL |       let v = Unit2.m(
@@ -30,11 +30,14 @@ LL |       let v = Unit2.m(
 LL |
 LL | /         L {
 LL | |
-LL | |             f : |x| { drop(x); Unit4 }
-LL | |         });
+LL | |             f: |x| {
+LL | |                 drop(x);
+LL | |                 Unit4
+LL | |             },
+LL | |         },
    | |_________^ expected struct `Unit3`, found struct `Unit4`
    |
-note: required because of the requirements on the impl of `for<'r> T0<'r, (&'r u8,)>` for `L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:20]>`
+note: required because of the requirements on the impl of `for<'r> T0<'r, (&'r u8,)>` for `L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:16: 42:19]>`
   --> $DIR/issue-62203-hrtb-ice.rs:17:16
    |
 LL | impl<'a, A, T> T0<'a, A> for L<T>
index 0fdeb6bdee1cb61ae39ecd813baf28ba03d56db1..31fc46203d32912c0fbf11b3a72227f796390f23 100644 (file)
@@ -15,7 +15,7 @@ pub fn future_from_generator<
     GenFuture(x)
 }
 
-struct GenFuture<T: FakeGenerator<Yield = ()>>(T);
+struct GenFuture<T: FakeGenerator<Yield = ()>>(#[allow(unused_tuple_struct_fields)] T);
 
 impl<T: FakeGenerator<Yield = ()>> FakeFuture for GenFuture<T> {
     type Output = T::Return;
index f14b447b077300d58756493fece8e5223610e492..d4a3495515cf14516f1dce084cd539001e450ead 100644 (file)
@@ -12,10 +12,15 @@ error[E0308]: mismatched types
   --> $DIR/equality.rs:15:5
    |
 LL | fn two(x: bool) -> impl Foo {
-   |                    -------- expected `_` because of return type
+   |                    -------- expected `i32` because of return type
 ...
 LL |     0_u32
    |     ^^^^^ expected `i32`, found `u32`
+   |
+help: change the type of the numeric literal from `u32` to `i32`
+   |
+LL |     0_i32
+   |       ~~~
 
 error[E0277]: cannot add `impl Foo` to `u32`
   --> $DIR/equality.rs:24:11
diff --git a/src/test/ui/impl-trait/issue-100187.rs b/src/test/ui/impl-trait/issue-100187.rs
new file mode 100644 (file)
index 0000000..fc541c6
--- /dev/null
@@ -0,0 +1,12 @@
+// check-pass
+
+trait Trait<T> {
+    type Ty;
+}
+impl Trait<&u8> for () {
+    type Ty = ();
+}
+
+fn test<'a, 'b>() -> impl Trait<&'a u8, Ty = impl Sized + 'b> {}
+
+fn main() {}
index 002e4cde40abe62cb380982e78d1a5b00e56f312..90d1cd3798a83b2ae89a2b7cc4a173c2d3e235f2 100644 (file)
@@ -7,7 +7,7 @@
 struct Bug {
     V1: [(); {
         fn concrete_use() -> F {
-            //~^ ERROR type mismatch
+            //~^ ERROR expected `impl Future<Output = ()>` to be a future that resolves to `u8`, but it resolves to `()`
             async {}
         }
         let f: F = async { 1 };
index 690d6abc76663cf7cacf3d993fa7a94c7493b846..9a0ffbc89d92e6ce1321fd371f53f39cc035b52e 100644 (file)
@@ -16,7 +16,7 @@ LL |         let f: F = async { 1 };
 LL |     }],
    |     - value is dropped here
 
-error[E0271]: type mismatch resolving `<impl Future<Output = ()> as Future>::Output == u8`
+error[E0271]: expected `impl Future<Output = ()>` to be a future that resolves to `u8`, but it resolves to `()`
   --> $DIR/issue-78722.rs:9:30
    |
 LL |         fn concrete_use() -> F {
index 5ca01a593761cd54eb835bfb7d3df6f87d0810b6..d6f5a1ac25b641e5cc653d68404c694976c92bd2 100644 (file)
@@ -2,7 +2,7 @@ error[E0308]: mismatched types
   --> $DIR/object-unsafe-trait-in-return-position-impl-trait.rs:36:5
    |
 LL | fn can() -> impl NotObjectSafe {
-   |             ------------------ expected `_` because of return type
+   |             ------------------ expected `A` because of return type
 ...
 LL |     B
    |     ^ expected struct `A`, found struct `B`
@@ -11,7 +11,7 @@ error[E0308]: mismatched types
   --> $DIR/object-unsafe-trait-in-return-position-impl-trait.rs:43:5
    |
 LL | fn cat() -> impl ObjectSafe {
-   |             --------------- expected `_` because of return type
+   |             --------------- expected `A` because of return type
 ...
 LL |     B
    |     ^ expected struct `A`, found struct `B`
index 10510c1754eda5ca842c6d8f0d4fac312ed4b5ee..3c65fd998c5afe9a9dc780f501900c673f597317 100644 (file)
@@ -2,28 +2,43 @@ error[E0308]: mismatched types
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:5:5
    |
 LL | fn foo() -> impl std::fmt::Display {
-   |             ---------------------- expected `_` because of return type
+   |             ---------------------- expected `i32` because of return type
 ...
 LL |     1u32
    |     ^^^^ expected `i32`, found `u32`
+   |
+help: change the type of the numeric literal from `u32` to `i32`
+   |
+LL |     1i32
+   |      ~~~
 
 error[E0308]: mismatched types
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:12:16
    |
 LL | fn bar() -> impl std::fmt::Display {
-   |             ---------------------- expected `_` because of return type
+   |             ---------------------- expected `i32` because of return type
 ...
 LL |         return 1u32;
    |                ^^^^ expected `i32`, found `u32`
+   |
+help: change the type of the numeric literal from `u32` to `i32`
+   |
+LL |         return 1i32;
+   |                 ~~~
 
 error[E0308]: mismatched types
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:20:9
    |
 LL | fn baz() -> impl std::fmt::Display {
-   |             ---------------------- expected `_` because of return type
+   |             ---------------------- expected `i32` because of return type
 ...
 LL |         1u32
    |         ^^^^ expected `i32`, found `u32`
+   |
+help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit
+   |
+LL |     }.try_into().unwrap()
+   |      ++++++++++++++++++++
 
 error[E0308]: `if` and `else` have incompatible types
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:28:9
@@ -36,36 +51,66 @@ LL | |         1u32
    | |         ^^^^ expected `i32`, found `u32`
 LL | |     }
    | |_____- `if` and `else` have incompatible types
+   |
+help: you could change the return type to be a boxed trait object
+   |
+LL | fn qux() -> Box<dyn std::fmt::Display> {
+   |             ~~~~~~~                  +
+help: if you change the return type to expect trait objects, box the returned expressions
+   |
+LL ~         Box::new(0i32)
+LL |     } else {
+LL ~         Box::new(1u32)
+   |
+help: change the type of the numeric literal from `u32` to `i32`
+   |
+LL |         1i32
+   |          ~~~
 
 error[E0308]: mismatched types
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:35:14
    |
 LL | fn bat() -> impl std::fmt::Display {
-   |             ---------------------- expected `_` because of return type
+   |             ---------------------- expected `i32` because of return type
 ...
 LL |         _ => 1u32,
    |              ^^^^ expected `i32`, found `u32`
+   |
+help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit
+   |
+LL |     }.try_into().unwrap()
+   |      ++++++++++++++++++++
 
 error[E0308]: mismatched types
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:40:5
    |
 LL |   fn can() -> impl std::fmt::Display {
-   |               ---------------------- expected `_` because of return type
+   |               ---------------------- expected `i32` because of return type
 LL | /     match 13 {
 LL | |         0 => return 0i32,
 LL | |         1 => 1u32,
 LL | |         _ => 2u32,
 LL | |     }
    | |_____^ expected `i32`, found `u32`
+   |
+help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit
+   |
+LL |     }.try_into().unwrap()
+   |      ++++++++++++++++++++
 
 error[E0308]: mismatched types
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:53:13
    |
 LL | fn cat() -> impl std::fmt::Display {
-   |             ---------------------- expected `_` because of return type
+   |             ---------------------- expected `i32` because of return type
 ...
 LL |             1u32
    |             ^^^^ expected `i32`, found `u32`
+   |
+help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit
+   |
+LL |     }.try_into().unwrap()
+   |      ++++++++++++++++++++
 
 error[E0308]: `match` arms have incompatible types
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:61:14
@@ -78,6 +123,20 @@ LL | |         1 => 1u32,
 LL | |         _ => 2u32,
 LL | |     }
    | |_____- `match` arms have incompatible types
+   |
+help: you could change the return type to be a boxed trait object
+   |
+LL | fn dog() -> Box<dyn std::fmt::Display> {
+   |             ~~~~~~~                  +
+help: if you change the return type to expect trait objects, box the returned expressions
+   |
+LL ~         0 => Box::new(0i32),
+LL ~         1 => Box::new(1u32),
+   |
+help: change the type of the numeric literal from `u32` to `i32`
+   |
+LL |         1 => 1i32,
+   |               ~~~
 
 error[E0308]: `if` and `else` have incompatible types
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:97:9
@@ -90,6 +149,21 @@ LL | |         1u32
    | |         ^^^^ expected `i32`, found `u32`
 LL | |     }
    | |_____- `if` and `else` have incompatible types
+   |
+help: you could change the return type to be a boxed trait object
+   |
+LL | fn apt() -> Box<dyn std::fmt::Display> {
+   |             ~~~~~~~                  +
+help: if you change the return type to expect trait objects, box the returned expressions
+   |
+LL ~         Box::new(0i32)
+LL |     } else {
+LL ~         Box::new(1u32)
+   |
+help: change the type of the numeric literal from `u32` to `i32`
+   |
+LL |         1i32
+   |          ~~~
 
 error[E0746]: return type cannot have an unboxed trait object
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:66:13
@@ -125,6 +199,11 @@ LL | |         1 => 1u32,
 LL | |         _ => 2u32,
 LL | |     }
    | |_____- `match` arms have incompatible types
+   |
+help: change the type of the numeric literal from `u32` to `i32`
+   |
+LL |         1 => 1i32,
+   |               ~~~
 
 error[E0746]: return type cannot have an unboxed trait object
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:77:13
@@ -164,6 +243,11 @@ LL | |         1u32
    | |         ^^^^ expected `i32`, found `u32`
 LL | |     }
    | |_____- `if` and `else` have incompatible types
+   |
+help: change the type of the numeric literal from `u32` to `i32`
+   |
+LL |         1i32
+   |          ~~~
 
 error[E0746]: return type cannot have an unboxed trait object
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:85:13
diff --git a/src/test/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs b/src/test/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs
new file mode 100644 (file)
index 0000000..a4e603d
--- /dev/null
@@ -0,0 +1,7 @@
+// check-pass
+
+pub fn iter<'a>(v: Vec<(u32, &'a u32)>) -> impl DoubleEndedIterator<Item = (u32, &u32)> {
+    v.into_iter()
+}
+
+fn main() {}
diff --git a/src/test/ui/implied-bounds/assoc-ty-wf-used-to-get-assoc-ty.rs b/src/test/ui/implied-bounds/assoc-ty-wf-used-to-get-assoc-ty.rs
new file mode 100644 (file)
index 0000000..33b746c
--- /dev/null
@@ -0,0 +1,27 @@
+// Test for a less than ideal interaction of implied bounds and normalization.
+trait Tr {
+    type Ty;
+}
+
+impl<T: 'static> Tr for T {
+    type Ty = &'static T;
+}
+
+// `<&'a u8 as Tr>::Ty` should cause an error because `&'a u8: Tr` doesn't hold for
+// all possible 'a. However, we consider normalized types for implied bounds.
+//
+// We normalize this projection to `&'static &'a u8` and add a nested `&'a u8: 'static`
+// bound. This bound is then proven using the implied bounds for `&'static &'a u8` which
+// we only get by normalizing in the first place.
+fn test<'a>(x: &'a u8, _wf: <&'a u8 as Tr>::Ty) -> &'static u8 { x }
+
+fn main() {
+    // This works as we have 'static references due to promotion.
+    let _: &'static u8 = test(&3, &&3);
+    // This causes an error because the projection requires 'a to be 'static.
+    // It would be unsound if this compiled.
+    let x: u8 = 3;
+    let _: &'static u8 = test(&x, &&3);
+    //~^ ERROR `x` does not live long enough
+
+}
diff --git a/src/test/ui/implied-bounds/assoc-ty-wf-used-to-get-assoc-ty.stderr b/src/test/ui/implied-bounds/assoc-ty-wf-used-to-get-assoc-ty.stderr
new file mode 100644 (file)
index 0000000..d0249e7
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0597]: `x` does not live long enough
+  --> $DIR/assoc-ty-wf-used-to-get-assoc-ty.rs:24:31
+   |
+LL |     let _: &'static u8 = test(&x, &&3);
+   |                          -----^^------
+   |                          |    |
+   |                          |    borrowed value does not live long enough
+   |                          argument requires that `x` is borrowed for `'static`
+...
+LL | }
+   | - `x` dropped here while still borrowed
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
index 52f4e594f1a0aac33839c4d89847f8bf6400b641..e5640f5ab53b192ab352109e039dc3b4616a59fe 100644 (file)
@@ -27,7 +27,7 @@ fn baz(n: bool) -> i32 {
 
 const fn return_ty_mismatch() {
     const_eval_select((1,), foo, bar);
-    //~^ ERROR type mismatch
+    //~^ ERROR expected `fn(i32) -> bool {bar}` to be a fn item that returns `i32`, but it returns `bool`
 }
 
 const fn args_ty_mismatch() {
index 89dba12c818c8ab3564410ee1d4ac6c7778bc0cb..e7b7e4a4a910c85d9251fc6e32959f6a1c0a7ee1 100644 (file)
@@ -51,7 +51,7 @@ note: required by a bound in `const_eval_select`
 LL |     G: FnOnce<ARG, Output = RET> + ~const Destruct,
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
 
-error[E0271]: type mismatch resolving `<fn(i32) -> bool {bar} as FnOnce<(i32,)>>::Output == i32`
+error[E0271]: expected `fn(i32) -> bool {bar}` to be a fn item that returns `i32`, but it returns `bool`
   --> $DIR/const-eval-select-bad.rs:29:5
    |
 LL |     const_eval_select((1,), foo, bar);
index 9a51a73c9a37bd7585d41548c076e13c83259bd2..79fd62d16332f9d69d84dc150f54c8155917eaa6 100644 (file)
@@ -1,8 +1,6 @@
 #![crate_name="a"]
 #![crate_type = "lib"]
 
-#![feature(box_syntax)]
-
 pub trait i<T>
 {
     fn dummy(&self, t: T) -> T { panic!() }
@@ -11,5 +9,5 @@ fn dummy(&self, t: T) -> T { panic!() }
 pub fn f<T>() -> Box<i<T>+'static> {
     impl<T> i<T> for () { }
 
-    box () as Box<i<T>+'static>
+    Box::new(()) as Box<i<T>+'static>
 }
index afaa90f05caa1757fe7771c0f6a4adc45b84a957..72e4559d31a799f84d287787fec3a5dfd97fed49 100644 (file)
@@ -4,12 +4,10 @@
 
 // pretty-expanded FIXME #23616
 
-#![feature(box_syntax)]
-
 fn work(_: Box<isize>) {}
 fn foo<F:FnOnce()>(_: F) {}
 
 pub fn main() {
-  let a = box 1;
+  let a = Box::new(1);
   foo(move|| { foo(move|| { work(a) }) })
 }
index f40815fdbdbc5626ad3ccb166cf28d2c867523eb..5670cd458f39436a6a6515ec9ef5301d252bda14 100644 (file)
@@ -1,10 +1,8 @@
 // run-pass
 // pretty-expanded FIXME #23616
 
-#![feature(box_syntax)]
-
 pub fn main() {
     fn f() {
     }
-    let _: Box<fn()> = box (f as fn());
+    let _: Box<fn()> = Box::new(f as fn());
 }
index f1d6b37a6843f3fff6f98efdb8628b82aaba9f82..99e1a92dfcc299ad9c62061f837fc7487964bd5f 100644 (file)
@@ -1,6 +1,5 @@
 // run-pass
 #![allow(dead_code)]
-#![feature(box_syntax)]
 
 struct DroppableStruct;
 enum DroppableEnum {
@@ -33,14 +32,14 @@ fn new(w: Box<dyn MyTrait+'static>) -> Whatever {
 
 fn main() {
     {
-        let f: Box<_> = box DroppableStruct;
-        let _a = Whatever::new(box f as Box<dyn MyTrait>);
+        let f: Box<_> = Box::new(DroppableStruct);
+        let _a = Whatever::new(Box::new(f) as Box<dyn MyTrait>);
     }
     assert!(unsafe { DROPPED });
     unsafe { DROPPED = false; }
     {
-        let f: Box<_> = box DroppableEnum::DroppableVariant1;
-        let _a = Whatever::new(box f as Box<dyn MyTrait>);
+        let f: Box<_> = Box::new(DroppableEnum::DroppableVariant1);
+        let _a = Whatever::new(Box::new(f) as Box<dyn MyTrait>);
     }
     assert!(unsafe { DROPPED });
 }
index 3bf91675ec3bbdcd3f1b669c40b61922ac320515..1a3d8c9fe5869ab637ce48b0790cff85f836590b 100644 (file)
@@ -1,20 +1,20 @@
-#![feature(box_syntax)]
-
 struct Foo {
     x: isize
 }
 
+
 impl Drop for Foo {
     fn drop(&mut self) {
         println!("drop {}", self.x);
     }
 }
 
+
 fn main() {
-    let mut ptr: Box<_> = box Foo { x: 0 };
+    let mut ptr: Box<_> = Box::new(Foo { x: 0 });
     let mut test = |foo: &Foo| {
         println!("access {}", foo.x);
-        ptr = box Foo { x: ptr.x + 1 };
+        ptr = Box::new(Foo { x: ptr.x + 1 });
         println!("access {}", foo.x);
     };
     test(&*ptr);
index 2a9d913171c3eed222679f0fd42f7de0919c80d0..fc1548013405605ac4718fdac48dc434c3e8c212 100644 (file)
@@ -4,7 +4,7 @@ error[E0502]: cannot borrow `*ptr` as immutable because it is also borrowed as m
 LL |     let mut test = |foo: &Foo| {
    |                    ----------- mutable borrow occurs here
 LL |         println!("access {}", foo.x);
-LL |         ptr = box Foo { x: ptr.x + 1 };
+LL |         ptr = Box::new(Foo { x: ptr.x + 1 });
    |         --- first borrow occurs due to use of `ptr` in closure
 ...
 LL |     test(&*ptr);
index 2072f9c47e2a65dd766fbb707d13e5eec0e44578..b5c942f96a7023fd545073c1a1957f88d4b31722 100644 (file)
@@ -1,10 +1,10 @@
-#![feature(box_syntax)]
-
 struct Test {
     func: Box<dyn FnMut() + 'static>,
 }
 
+
+
 fn main() {
     let closure: Box<dyn Fn() + 'static> = Box::new(|| ());
-    let test = box Test { func: closure }; //~ ERROR trait upcasting coercion is experimental [E0658]
+    let test = Box::new(Test { func: closure }); //~ ERROR trait upcasting coercion is experimental [E0658]
 }
index 17bfae2a4e46bdd33fa983a2d29f512a92579916..accd47f0f5fbc0c14c086874ea5c9273468d09c2 100644 (file)
@@ -1,8 +1,8 @@
 error[E0658]: cannot cast `dyn Fn()` to `dyn FnMut()`, trait upcasting coercion is experimental
-  --> $DIR/issue-11515.rs:9:33
+  --> $DIR/issue-11515.rs:9:38
    |
-LL |     let test = box Test { func: closure };
-   |                                 ^^^^^^^
+LL |     let test = Box::new(Test { func: closure });
+   |                                      ^^^^^^^
    |
    = note: see issue #65991 <https://github.com/rust-lang/rust/issues/65991> for more information
    = help: add `#![feature(trait_upcasting)]` to the crate attributes to enable
index bae12375da124950058858fdf9ed446b6e019fd7..9fb9f3d2e3f34907146c8549b6032b37872f1aba 100644 (file)
@@ -1,6 +1,5 @@
 // run-pass
 #![feature(box_patterns)]
-#![feature(box_syntax)]
 
 #[derive(Clone)]
 enum Noun
@@ -18,5 +17,8 @@ fn fas(n: &Noun) -> Noun
 }
 
 pub fn main() {
-    fas(&Noun::Cell(box Noun::Atom(2), box Noun::Cell(box Noun::Atom(2), box Noun::Atom(3))));
+    fas(
+        &Noun::Cell(Box::new(Noun::Atom(2)),
+        Box::new(Noun::Cell(Box::new(Noun::Atom(2)), Box::new(Noun::Atom(3)))))
+    );
 }
index bb06f00d5cf2d5f0cf171e176b70607a44ff25a2..f974a4702960afbcfb3a9fcde7984ddbbb1352e2 100644 (file)
@@ -1,7 +1,5 @@
-#![feature(box_syntax)]
-
 fn main() {
-    let a = Some(box 1);
+    let a = Some(Box::new(1));
     match a {
         Ok(a) => //~ ERROR: mismatched types
             println!("{}",a),
index 9d7470e7af9aa9c557edc551e87a9647494c9fc7..81cf918a1030ba713435cad3b9f21f58823df710 100644 (file)
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/issue-11844.rs:6:9
+  --> $DIR/issue-11844.rs:4:9
    |
 LL |     match a {
    |           - this expression has type `Option<Box<{integer}>>`
index bb2c2734583eb9d19e91e8d362963e7a241624f9..8b30ddc2de67e912e6f4dffdc37f3ea77f0a738d 100644 (file)
@@ -1,10 +1,10 @@
-#![feature(box_syntax, unboxed_closures)]
+#![feature(unboxed_closures)]
 
 fn to_fn_once<A,F:FnOnce<A>>(f: F) -> F { f }
 fn do_it(x: &isize) { }
 
 fn main() {
-    let x: Box<_> = box 22;
+    let x: Box<_> = Box::new(22);
     let f = to_fn_once(move|| do_it(&*x));
     to_fn_once(move|| {
         f();
index 5f2b98c5237db15c4d1d46699d60e68b7e1fac13..789a1141c04f9e9502ff5664d0516ab64aeb69a3 100644 (file)
@@ -23,8 +23,10 @@ LL | trait T2 : T1 {
 note: cycle used when collecting item types in top-level module
   --> $DIR/issue-12511.rs:1:1
    |
-LL | trait T1 : T2 {
-   | ^^^^^^^^^^^^^
+LL | / trait T1 : T2 {
+LL | |
+LL | | }
+   | |_^
 
 error: aborting due to previous error
 
index 1bab82a543f053c34bd5574ff214007b0c6fb1cf..64bf2a11d0ecd0261f977ba3711a163dc689b559 100644 (file)
@@ -164,7 +164,7 @@ fn range_shadow_multi_pats() {
 
 fn misc() {
     enum Foo {
-        Bar(usize, bool)
+        Bar(#[allow(unused_tuple_struct_fields)] usize, bool)
     }
     // This test basically mimics how trace_macros! macro is implemented,
     // which is a rare combination of vector patterns, multiple wild-card
index 26847ee7a0839ee4a0db09737dd5bf4272d127db..71e14d4dab5a6599cfd6856dca8a754efc4fc0ed 100644 (file)
@@ -1,5 +1,4 @@
 // run-pass
-#![feature(box_syntax)]
 
 struct StrWrap {
     s: String
@@ -48,7 +47,7 @@ fn matches(&self, actual: T) -> bool {
 }
 
 fn equal_to<T: Eq>(expected: T) -> Box<EqualTo<T>> {
-    box EqualTo { expected: expected }
+    Box::new(EqualTo { expected: expected })
 }
 
 pub fn main() {
index 671e7a22667428122267a3cf7fd358f35032e238..dca24d0be8a2acb458ea7771beaccd1b25269f3e 100644 (file)
@@ -1,6 +1,6 @@
 // run-pass
 #[derive(Debug)]
-struct Matrix4<S>(S);
+struct Matrix4<S>(#[allow(unused_tuple_struct_fields)] S);
 trait POrd<S> {}
 
 fn translate<S: POrd<S>>(s: S) -> Matrix4<S> { Matrix4(s) }
index 6bf8a589959c57afa908a31f6f8f686e94880cc1..7b32bf8e4cbb7a44be9f606e2f2719d65755fd13 100644 (file)
@@ -6,8 +6,6 @@
 
 // pretty-expanded FIXME #23616
 
-#![feature(box_syntax)]
-
 #[derive(Clone)]
 struct B1;
 
@@ -15,6 +13,6 @@ trait A { fn foo(&self) {} }
 impl A for B1 {}
 
 fn main() {
-    let v: Box<_> = box B1;
+    let v: Box<_> = Box::new(B1);
     let _c: Box<dyn A> = v.clone();
 }
index 909540355ed89a5e5ab3be6749d6bb4e483f767c..127b909dd63eb129492e728d72c51bc57d10601f 100644 (file)
@@ -1,7 +1,5 @@
-#![feature(box_syntax)]
-
 fn main() {
-    let x: Box<isize> = box 0;
+    let x: Box<isize> = Box::new(0);
 
     println!("{}", x + 1);
     //~^ ERROR cannot add `{integer}` to `Box<isize>`
index bd0b1d39a538a407a18045ceeb7cfc1916ddb89f..6e63269293b75460f0010d4e54a47800980c96db 100644 (file)
@@ -1,5 +1,5 @@
 error[E0369]: cannot add `{integer}` to `Box<isize>`
-  --> $DIR/issue-14915.rs:6:22
+  --> $DIR/issue-14915.rs:4:22
    |
 LL |     println!("{}", x + 1);
    |                    - ^ - {integer}
diff --git a/src/test/ui/issues/issue-15524.rs b/src/test/ui/issues/issue-15524.rs
deleted file mode 100644 (file)
index 565db2d..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-const N: isize = 1;
-
-enum Foo {
-    //~^ ERROR discriminant value `1` assigned more than once
-    //~| ERROR discriminant value `1` assigned more than once
-    //~| ERROR discriminant value `1` assigned more than once
-    A = 1,
-    B = 1,
-    C = 0,
-    D,
-
-    E = N,
-
-}
-
-fn main() {}
diff --git a/src/test/ui/issues/issue-15524.stderr b/src/test/ui/issues/issue-15524.stderr
deleted file mode 100644 (file)
index 1195e0a..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-error[E0081]: discriminant value `1` assigned more than once
-  --> $DIR/issue-15524.rs:3:1
-   |
-LL | enum Foo {
-   | ^^^^^^^^
-...
-LL |     A = 1,
-   |         - first assignment of `1`
-LL |     B = 1,
-   |         - second assignment of `1`
-
-error[E0081]: discriminant value `1` assigned more than once
-  --> $DIR/issue-15524.rs:3:1
-   |
-LL | enum Foo {
-   | ^^^^^^^^
-...
-LL |     A = 1,
-   |         - first assignment of `1`
-LL |     B = 1,
-LL |     C = 0,
-   |     ----- assigned discriminant for `D` was incremented from this discriminant
-LL |     D,
-   |     - second assignment of `1`
-
-error[E0081]: discriminant value `1` assigned more than once
-  --> $DIR/issue-15524.rs:3:1
-   |
-LL | enum Foo {
-   | ^^^^^^^^
-...
-LL |     A = 1,
-   |         - first assignment of `1`
-...
-LL |     E = N,
-   |         - second assignment of `1`
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0081`.
index 5381d65232f1292cc9245bcfce41addaff379413..5f228b2863e46ca102ba947b7f085ed4eb42d213 100644 (file)
@@ -1,8 +1,7 @@
 // run-pass
-#![feature(box_syntax)]
 
 fn match_on_local() {
-    let mut foo: Option<Box<_>> = Some(box 5);
+    let mut foo: Option<Box<_>> = Some(Box::new(5));
     match foo {
         None => {},
         Some(x) => {
@@ -37,7 +36,7 @@ fn match_on_binding() {
 }
 
 fn match_on_upvar() {
-    let mut foo: Option<Box<_>> = Some(box 8);
+    let mut foo: Option<Box<_>> = Some(Box::new(8));
     let f = move|| {
         match foo {
             None => {},
@@ -52,7 +51,7 @@ fn match_on_upvar() {
 
 fn main() {
     match_on_local();
-    match_on_arg(Some(box 6));
+    match_on_arg(Some(Box::new(6)));
     match_on_binding();
     match_on_upvar();
 }
index 9ceffff2e38066ac903cfe1b37ccdd83025fcb3a..ae0863615e2c7754fbb1d69ad47c4c671da9f393 100644 (file)
@@ -1,6 +1,5 @@
 // run-pass
 #![allow(unreachable_code)]
-#![feature(box_syntax)]
 
 #[derive(PartialEq, Debug)]
 struct Bar {
@@ -78,12 +77,12 @@ fn main() {
     assert_eq!(cc().unwrap(), 3);
     assert_eq!(dd().unwrap(), 3);
 
-    let i = box 32isize as Box<dyn A>;
+    let i = Box::new(32isize) as Box<dyn A>;
     assert_eq!(i.aaa(), 3);
-    let i = box 32isize as Box<dyn A>;
+    let i = Box::new(32isize) as Box<dyn A>;
     assert_eq!(i.bbb(), 3);
-    let i = box 32isize as Box<dyn A>;
+    let i = Box::new(32isize) as Box<dyn A>;
     assert_eq!(i.ccc().unwrap(), 3);
-    let i = box 32isize as Box<dyn A>;
+    let i = Box::new(32isize) as Box<dyn A>;
     assert_eq!(i.ddd().unwrap(), 3);
 }
index 41d2f13952ae0bd383574d51e7c0c06c45989b13..8d65afc4883d7071237a08b8a3ce50f491143e1f 100644 (file)
@@ -12,7 +12,7 @@ fn do_something(&mut self) {}
 }
 
 
-struct Foo<B: Bar>(B);
+struct Foo<B: Bar>(#[allow(unused_tuple_struct_fields)] B);
 
 impl<B: Bar> Drop for Foo<B> {
     fn drop(&mut self) {
index 94da2ca5cab815e2bc2251f8e7a7d8666633dc74..b21ea4bcd7869b783383d290bf75eb957899ebdf 100644 (file)
@@ -1,5 +1,4 @@
 // run-pass
-#![feature(box_syntax)]
 #![feature(unboxed_closures, fn_traits)]
 
 // Test that unboxing shim for calling rust-call ABI methods through a
@@ -35,12 +34,12 @@ extern "rust-call" fn call_once(mut self, args: (u32,u32)) -> u32 { self.call_mu
 }
 
 fn main() {
-    let mut f = box Foo { foo: 42 } as Box<dyn FnMut() -> u32>;
+    let mut f = Box::new(Foo { foo: 42 }) as Box<dyn FnMut() -> u32>;
     assert_eq!(f.call_mut(()), 42);
 
-    let mut f = box Foo { foo: 40 } as Box<dyn FnMut(u32) -> u32>;
+    let mut f = Box::new(Foo { foo: 40 }) as Box<dyn FnMut(u32) -> u32>;
     assert_eq!(f.call_mut((2,)), 42);
 
-    let mut f = box Foo { foo: 40 } as Box<dyn FnMut(u32, u32) -> u32>;
+    let mut f = Box::new(Foo { foo: 40 }) as Box<dyn FnMut(u32, u32) -> u32>;
     assert_eq!(f.call_mut((1, 1)), 42);
 }
index 9e9b84034dbd826c3b9d3388473263441fe01c19..2b308ef76e43d6f1287026aa7168ec5e2e4f9e00 100644 (file)
@@ -1,5 +1,4 @@
 // run-pass
-#![feature(box_syntax)]
 #![feature(box_patterns)]
 
 use std::ops::{Deref, DerefMut};
@@ -35,7 +34,7 @@ fn deref_mut(&mut self) -> &mut isize {
 
 fn main() {
     {
-        let mut test = X(box 5);
+        let mut test = X(Box::new(5));
         {
             let mut change = || { *test = 10 };
             change();
index 20a8d136124695495b4dbe7e6e798497ffa4e4ff..b4fc40c3f2b7c376f20ac75dcbabca7dddea7115 100644 (file)
@@ -1,8 +1,6 @@
 // run-pass
 // pretty-expanded FIXME #23616
 
-#![feature(box_syntax)]
-
 use std::io::{self, Write};
 
 fn f(wr: &mut dyn Write) {
@@ -10,6 +8,6 @@ fn f(wr: &mut dyn Write) {
 }
 
 fn main() {
-    let mut wr = box io::stdout() as Box<dyn Write>;
+    let mut wr = Box::new(io::stdout()) as Box<dyn Write>;
     f(&mut wr);
 }
index 95133a4584430b13fdaec66ee02b2511beb548d4..dae9648b9173f0a3324fb35ada1fc1af5f0ff8d7 100644 (file)
@@ -1,6 +1,7 @@
 // run-pass
 
 #[derive(Debug)]
+#[allow(unused_tuple_struct_fields)]
 struct Pair<T, V> (T, V);
 
 impl Pair<
index 9dbac6ccee1d17be1e03480f7f465cbeca2afc70..f08f9d4cfe4103b55a8989edd7b5b17cbc0a76f5 100644 (file)
@@ -3,7 +3,7 @@
 // cause compiler to loop.  Note that no instances
 // of such a type could ever be constructed.
 
-struct T(Box<T>);
+struct T(#[allow(unused_tuple_struct_fields)] Box<T>);
 
 trait ToStr2 {
     fn my_to_string(&self) -> String;
index 86cc7707e50f93f35361b011a9717d9506928fe9..91f72eb369bca73b3fcb874efd7b76cb7f796f6c 100644 (file)
@@ -4,7 +4,6 @@
 // pretty-expanded FIXME #23616
 
 #![feature(box_patterns)]
-#![feature(box_syntax)]
 
 enum E {
     StructVar { boxed: Box<i32> }
@@ -13,7 +12,7 @@ enum E {
 fn main() {
 
     // Test matching each shorthand notation for field patterns.
-    let mut a = E::StructVar { boxed: box 3 };
+    let mut a = E::StructVar { boxed: Box::new(3) };
     match a {
         E::StructVar { box boxed } => { }
     }
@@ -38,7 +37,7 @@ fn main() {
 
     // Test matching non shorthand notation. Recreate a since last test
     // moved `boxed`
-    let mut a = E::StructVar { boxed: box 3 };
+    let mut a = E::StructVar { boxed: Box::new(3) };
     match a {
         E::StructVar { boxed: box ref mut num } => { }
     }
index c74e53fca60fdfac8b07edf7c483277f39c491ff..6fd690a4d956a8510914171417a303aabbda3a3b 100644 (file)
@@ -1,8 +1,6 @@
 // run-pass
 #![allow(non_camel_case_types)]
 
-#![feature(box_syntax)]
-
 trait clam<A> {
   fn chowder(&self, y: A);
 }
@@ -30,6 +28,6 @@ fn f<A>(x: Box<dyn clam<A>>, a: A) {
 pub fn main() {
 
   let c = foo(42);
-  let d: Box<dyn clam<isize>> = box c as Box<dyn clam<isize>>;
+  let d: Box<dyn clam<isize>> = Box::new(c) as Box<dyn clam<isize>>;
   f(d, c.x);
 }
index e92273bd409142c22324b14f0c34b991530f8a9b..010281ee371cdd31282463d0a53ee518bc081a4c 100644 (file)
@@ -1,11 +1,10 @@
-#![feature(box_syntax)]
 use std::any::Any;
 
 fn main()
 {
     fn h(x:i32) -> i32 {3*x}
     let mut vfnfer:Vec<Box<dyn Any>> = vec![];
-    vfnfer.push(box h);
+    vfnfer.push(Box::new(h));
     println!("{:?}",(vfnfer[0] as dyn Fn)(3));
     //~^ ERROR the precise format of `Fn`-family traits'
     //~| ERROR missing generics for trait `Fn`
index 7a4d90b4412f9a3d6cf56e8ae9ec579dd22f154e..73f93c51d34e82d982195836796c281d637f889c 100644 (file)
@@ -1,5 +1,5 @@
 error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change
-  --> $DIR/issue-23024.rs:9:39
+  --> $DIR/issue-23024.rs:8:39
    |
 LL |     println!("{:?}",(vfnfer[0] as dyn Fn)(3));
    |                                       ^^ help: use parenthetical notation instead: `Fn() -> ()`
@@ -8,7 +8,7 @@ LL |     println!("{:?}",(vfnfer[0] as dyn Fn)(3));
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
 error[E0107]: missing generics for trait `Fn`
-  --> $DIR/issue-23024.rs:9:39
+  --> $DIR/issue-23024.rs:8:39
    |
 LL |     println!("{:?}",(vfnfer[0] as dyn Fn)(3));
    |                                       ^^ expected 1 generic argument
@@ -24,7 +24,7 @@ LL |     println!("{:?}",(vfnfer[0] as dyn Fn<Args>)(3));
    |                                       ~~~~~~~~
 
 error[E0191]: the value of the associated type `Output` (from trait `FnOnce`) must be specified
-  --> $DIR/issue-23024.rs:9:39
+  --> $DIR/issue-23024.rs:8:39
    |
 LL |     println!("{:?}",(vfnfer[0] as dyn Fn)(3));
    |                                       ^^ help: specify the associated type: `Fn<Output = Type>`
index d2ded88aeff192a8e5c9b958ed4adefb6d07e4a1..e5f9dd3efbd2a3df3c253c8d67100a3587f5ff6b 100644 (file)
@@ -1,9 +1,8 @@
 // run-pass
 #![allow(unused_variables)]
-#![feature(box_syntax)]
 
-struct Node<T: ?Sized>(T);
+struct Node<T: ?Sized>(#[allow(unused_tuple_struct_fields)] T);
 
 fn main() {
-    let x: Box<Node<[isize]>> = box Node([]);
+    let x: Box<Node<[isize]>> = Box::new(Node([]));
 }
index 9c39a5d22387de69ab9ade18a06aada1d52dda78..4a582c68efc9bb01d8453cb093416cd44703c409 100644 (file)
@@ -4,7 +4,7 @@ fn method1() {}
     fn method2();
 }
 
-struct Slice<'a, T: 'a>(&'a [T]);
+struct Slice<'a, T: 'a>(#[allow(unused_tuple_struct_fields)] &'a [T]);
 
 impl<'a, T: 'a> Foo for Slice<'a, T> {
     fn method2() {
index 555eefeb3a1f8722720151ae3eaf55f6fc498fae..45761b61c3e95097b5108020b3188d8473998c1a 100644 (file)
@@ -19,7 +19,7 @@ impl<'a, T> UserDefined for &'a T { }
 //   ```
 macro_rules! impl_drop {
     ($Bound:ident, $Id:ident) => {
-        struct $Id<T: $Bound>(T);
+        struct $Id<T: $Bound>(#[allow(unused_tuple_struct_fields)] T);
         unsafe impl <#[may_dangle] T: $Bound> Drop for $Id<T> {
             fn drop(&mut self) { }
         }
index 0f0f78623a212a7fd2546cbafb3473f765e17e43..c988f8f55fa47a0b43ea229d383afb9866c2e083 100644 (file)
@@ -4,7 +4,7 @@
 
 use std::thread;
 
-struct Foo(i32);
+struct Foo(#[allow(unused_tuple_struct_fields)] i32);
 
 impl Drop for Foo {
     fn drop(&mut self) {
index 89544c9eb88c9804450e9a3639a69696248cb698..b548da98888872d22c33fdd559d3d47d1c9f0df3 100644 (file)
@@ -2,6 +2,7 @@
 trait Device {
     type Resources;
 }
+#[allow(unused_tuple_struct_fields)]
 struct Foo<D, R>(D, R);
 
 impl<D: Device> Foo<D, D::Resources> {
index 7bc9673a5be360717151d2edb5dfa839e6dc4b61..5e71a52ba4e963104c75e293f2c48e0095ed73aa 100644 (file)
@@ -1,5 +1,5 @@
 // run-pass
-struct S<T: 'static>(Option<&'static T>);
+struct S<T: 'static>(#[allow(unused_tuple_struct_fields)] Option<&'static T>);
 
 trait Tr { type Out; }
 impl<T> Tr for T { type Out = T; }
index b161e68abafd0e2e4b638e4609dbda1e44b582cf..89b1db496f95c5e10e0ddff25bda6627f95009fd 100644 (file)
@@ -3,8 +3,9 @@ pub trait Parser {
     type Input;
 }
 
-pub struct Iter<P: Parser>(P, P::Input);
+pub struct Iter<P: Parser>(#[allow(unused_tuple_struct_fields)] P, P::Input);
 
+#[allow(unused_tuple_struct_fields)]
 pub struct Map<P, F>(P, F);
 impl<P, F> Parser for Map<P, F> where F: FnMut(P) {
     type Input = u8;
index 45c452d618d84b88b81143281f17c7cca8d66a01..e5b9a97523dfd7452fbf34af6ce60246ad53b74e 100644 (file)
@@ -1,4 +1,4 @@
-struct S<T: 'static>(Option<&'static T>);
+struct S<T: 'static>(#[allow(unused_tuple_struct_fields)] Option<&'static T>);
 
 trait Tr { type Out; }
 impl<T> Tr for T { type Out = T; }
index cb479a2308599bd50ed55d649045083c408a7b8f..f3f9c1d9ae821b18db99ead7465f4a2781554a9e 100644 (file)
@@ -1,7 +1,7 @@
 // run-pass
 trait Tr { type T; }
 impl Tr for u8 { type T=(); }
-struct S<I: Tr>(I::T);
+struct S<I: Tr>(#[allow(unused_tuple_struct_fields)] I::T);
 
 fn foo<I: Tr>(i: I::T) {
     S::<I>(i);
index 4b6f2c2b3bc7d7d70dbcbef21a934368b6992ee1..e08edd0b5cb67c4b64cfc379b8d95a31eb2d2d4c 100644 (file)
@@ -1,5 +1,5 @@
 // run-pass
-struct Parser<'a>(Box<dyn FnMut(Parser) + 'a>);
+struct Parser<'a>(#[allow(unused_tuple_struct_fields)] Box<dyn FnMut(Parser) + 'a>);
 
 fn main() {
     let _x = Parser(Box::new(|_|{}));
index 281ae13399dd2590dfc88d358c07f90ece659a41..1bd2651dd6c12e7bd686874ee68dd3a2808be910 100644 (file)
@@ -1,5 +1,5 @@
 // run-pass
-struct Wrapper<'a, T: ?Sized>(&'a mut i32, T);
+struct Wrapper<'a, T: ?Sized>(&'a mut i32, #[allow(unused_tuple_struct_fields)] T);
 
 impl<'a, T: ?Sized> Drop for Wrapper<'a, T> {
     fn drop(&mut self) {
index abd5e9507f8eeeb7d03a57482bae6e37a7fc6d35..4e53b9d145f0b57bbc6bf6bfe848ec59d7314946 100644 (file)
@@ -4,7 +4,7 @@
 
 // pretty-expanded FIXME #23616
 
-#![feature(box_syntax)]
+
 
 struct Font {
     fontbuf: usize,
@@ -26,5 +26,5 @@ fn Font() -> Font {
 }
 
 pub fn main() {
-    let _f: Box<_> = box Font();
+    let _f: Box<_> = Box::new(Font());
 }
index a22db76b9bc4d92752e5ca0ba258116293638e99..eaf254f3361932a399f50d4ad9ef964b48ac8e53 100644 (file)
@@ -2,12 +2,12 @@
 #![allow(unused_assignments)]
 #![allow(unused_variables)]
 use std::fmt;
-struct NoisyDrop<T: fmt::Debug>(T);
+struct NoisyDrop<T: fmt::Debug>(#[allow(unused_tuple_struct_fields)] T);
 impl<T: fmt::Debug> Drop for NoisyDrop<T> {
     fn drop(&mut self) {}
 }
 
-struct Bar<T: fmt::Debug>([*const NoisyDrop<T>; 2]);
+struct Bar<T: fmt::Debug>(#[allow(unused_tuple_struct_fields)] [*const NoisyDrop<T>; 2]);
 
 fn fine() {
     let (u,b);
@@ -15,6 +15,7 @@ fn fine() {
     b = Bar([&NoisyDrop(&u), &NoisyDrop(&u)]);
 }
 
+#[allow(unused_tuple_struct_fields)]
 struct Bar2<T: fmt::Debug>(*const NoisyDrop<T>, *const NoisyDrop<T>);
 
 fn lolwut() {
index d449f6449aa091e3a0d42de258bbe4961fd34397..df4f394dc373f63b0907eb069f7890a5ec9d8a59 100644 (file)
@@ -4,21 +4,19 @@
 
 // pretty-expanded FIXME #23616
 
-#![feature(box_syntax)]
-
 trait hax {
     fn dummy(&self) { }
 }
 impl<A> hax for A { }
 
 fn perform_hax<T: 'static>(x: Box<T>) -> Box<dyn hax+'static> {
-    box x as Box<dyn hax+'static>
+    Box::new(x) as Box<dyn hax+'static>
 }
 
 fn deadcode() {
-    perform_hax(box "deadcode".to_string());
+    perform_hax(Box::new("deadcode".to_string()));
 }
 
 pub fn main() {
-    let _ = perform_hax(box 42);
+    let _ = perform_hax(Box::new(42));
 }
index 794c7d4edaa113f6e9d9089f7d820b0c988c48a5..20d3949a9f998ca9cb98b95ba4241eb180d2f66c 100644 (file)
@@ -4,21 +4,19 @@
 
 // pretty-expanded FIXME #23616
 
-#![feature(box_syntax)]
-
 trait hax {
     fn dummy(&self) { }
 }
 impl<A> hax for A { }
 
 fn perform_hax<T: 'static>(x: Box<T>) -> Box<dyn hax+'static> {
-    box x as Box<dyn hax+'static>
+    Box::new(x) as Box<dyn hax+'static>
 }
 
 fn deadcode() {
-    perform_hax(box "deadcode".to_string());
+    perform_hax(Box::new("deadcode".to_string()));
 }
 
 pub fn main() {
-    perform_hax(box 42);
+    perform_hax(Box::new(42));
 }
index b5a2b2f55a6d4905af0425b580efa1406101b0a9..208b340d0641067309f2545dff511e8851662e9d 100644 (file)
@@ -10,6 +10,10 @@ LL |     let _d = c.clone();
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `clone`, perhaps you need to implement it:
            candidate #1: `Clone`
+help: one of the expressions' fields has a method of the same name
+   |
+LL |     let _d = c.x.clone();
+   |                ++
 
 error: aborting due to previous error
 
index 4699d3352ad20e4264dafca2b11ad5e547ef13d3..ab6d190e0a153ee90313c7846853ecbc0ac6293c 100644 (file)
@@ -6,7 +6,7 @@
 
 use std::cell::Cell;
 
-struct Concrete<'a>(u32, Cell<Option<&'a Concrete<'a>>>);
+struct Concrete<'a>(#[allow(unused_tuple_struct_fields)] u32, Cell<Option<&'a Concrete<'a>>>);
 
 fn main() {
     let mut data = Vec::new();
index cadf62461fdf5cdefdeefc6d226f0cb5bd2b7de9..378d736ee3d9bf55aed7b9bf0db7cbfc6a15b8fd 100644 (file)
@@ -6,7 +6,7 @@
 
 use std::cell::Cell;
 
-struct Concrete<'a>(u32, Cell<Option<&'a Concrete<'a>>>);
+struct Concrete<'a>(#[allow(unused_tuple_struct_fields)] u32, Cell<Option<&'a Concrete<'a>>>);
 
 struct Foo<T> { data: Vec<T> }
 
index 90cf2cddcf02a940f9a40d8b8aaa1c5ee33dd7e1..24bf706cef9da895b486edc7339c1bd934c5b3b0 100644 (file)
@@ -8,7 +8,7 @@
 #![feature(dropck_eyepatch)]
 use std::cell::Cell;
 
-struct Concrete<'a>(u32, Cell<Option<&'a Concrete<'a>>>);
+struct Concrete<'a>(#[allow(unused_tuple_struct_fields)] u32, Cell<Option<&'a Concrete<'a>>>);
 
 struct Foo<T> { data: Vec<T> }
 
index 101bca307f1ab1fa89386f89ed3e537ac6629d88..439f8bb5308f2dfe93a3df89e859edd6bf9c08cf 100644 (file)
@@ -1,5 +1,6 @@
 // run-pass
 #![recursion_limit="1024"]
+#![allow(dead_code)]
 
 use std::mem;
 
index 271bc526033d412c97a9ce07602ec94200a41321..190ecf46009ffe974f849d607568075d660a38d0 100644 (file)
@@ -1,4 +1,5 @@
 #![recursion_limit="1024"]
+#![allow(dead_code)]
 
 pub struct S0<T>(T,T);
 pub struct S1<T>(Option<Box<S0<S0<T>>>>,Option<Box<S0<S0<T>>>>);
index 5570e887edce5752524df39fb77818b891334b27..138d477dc6b29d5a12cf5dd170a941feeae35a1e 100644 (file)
@@ -1,11 +1,11 @@
 error[E0283]: type annotations needed
-  --> $DIR/issue-29147.rs:21:13
+  --> $DIR/issue-29147.rs:22:13
    |
 LL |     let _ = <S5<_>>::xxx;
    |             ^^^^^^^^^^^^ cannot infer type for struct `S5<_>`
    |
 note: multiple `impl`s satisfying `S5<_>: Foo` found
-  --> $DIR/issue-29147.rs:17:1
+  --> $DIR/issue-29147.rs:18:1
    |
 LL | impl Foo for S5<u32> { fn xxx(&self) {} }
    | ^^^^^^^^^^^^^^^^^^^^
index 11641ca738018396765f77182fa3e1d0d70492be..37f8181991c404e3419de3c68da53899a1d4c2b1 100644 (file)
@@ -1,7 +1,6 @@
 // run-pass
 #![allow(dead_code)]
 #![allow(non_camel_case_types)]
-#![feature(box_syntax)]
 
 //type t = { a: isize };
 // type t = { a: bool };
@@ -20,7 +19,7 @@ pub fn main() {
   //   let y = box ({a: 4});
   //    let z = box ({a: 4} as it);
   //    let z = box ({a: true} as it);
-    let z: Box<_> = box (box true as Box<dyn it>);
+    let z: Box<_> = Box::new(Box::new(true) as Box<dyn it>);
     //  x.f();
     // y.f();
     // (*z).f();
index 1dea8134fba2f2590f5bec54bdfb28b289d27708..4619a3fe78718c8e5e099fe0c0785579d93a183a 100644 (file)
@@ -1,13 +1,11 @@
 // run-pass
 // pretty-expanded FIXME #23616
 
-#![feature(box_syntax)]
-
 use std::collections::HashMap;
 
 pub fn main() {
     let x: Box<_>;
     let mut buggy_map: HashMap<usize, &usize> = HashMap::new();
-    x = box 1;
+    x = Box::new(1);
     buggy_map.insert(42, &*x);
 }
index 48061ae54ae206ebff1f353987d860789eee296f..472a95d4636bc16e39b756a08df4aacb00a29782 100644 (file)
@@ -3,12 +3,13 @@
 pub fn get_tok(it: &mut IntoIter<u8>) {
     let mut found_e = false;
 
-    let temp: Vec<u8> = it.take_while(|&x| {
-        found_e = true;
-        false
-    })
+    let temp: Vec<u8> = it
+        .take_while(|&x| {
+            found_e = true;
+            false
+        })
         .cloned()
-        //~^ ERROR type mismatch resolving
+        //~^ ERROR to be an iterator that yields `&_`, but it yields `u8`
         .collect(); //~ ERROR the method
 }
 
index 68337a715e14ff639343f5ad28a5ebbce7da5cd3..e89105540dfb22fac332455c81ced467fc02bf19 100644 (file)
@@ -1,5 +1,5 @@
-error[E0271]: type mismatch resolving `<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]> as Iterator>::Item == &_`
-  --> $DIR/issue-31173.rs:10:10
+error[E0271]: expected `TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>` to be an iterator that yields `&_`, but it yields `u8`
+  --> $DIR/issue-31173.rs:11:10
    |
 LL |         .cloned()
    |          ^^^^^^ expected reference, found `u8`
@@ -12,11 +12,11 @@ note: required by a bound in `cloned`
 LL |         Self: Sized + Iterator<Item = &'a T>,
    |                                ^^^^^^^^^^^^ required by this bound in `cloned`
 
-error[E0599]: the method `collect` exists for struct `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>`, but its trait bounds were not satisfied
-  --> $DIR/issue-31173.rs:12:10
+error[E0599]: the method `collect` exists for struct `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>`, but its trait bounds were not satisfied
+  --> $DIR/issue-31173.rs:13:10
    |
 LL |         .collect();
-   |          ^^^^^^^ method cannot be called on `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>` due to unsatisfied trait bounds
+   |          ^^^^^^^ method cannot be called on `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>` due to unsatisfied trait bounds
    |
   ::: $SRC_DIR/core/src/iter/adapters/cloned.rs:LL:COL
    |
@@ -29,10 +29,10 @@ LL | pub struct TakeWhile<I, P> {
    | -------------------------- doesn't satisfy `<_ as Iterator>::Item = &_`
    |
    = note: the following trait bounds were not satisfied:
-           `<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]> as Iterator>::Item = &_`
-           which is required by `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>: Iterator`
-           `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>: Iterator`
-           which is required by `&mut Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>: Iterator`
+           `<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]> as Iterator>::Item = &_`
+           which is required by `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>: Iterator`
+           `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>: Iterator`
+           which is required by `&mut Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>: Iterator`
 
 error: aborting due to 2 previous errors
 
index f7bbfa9f6f4bdc644d7d201c3e932e46d8345ec2..4bf5b9b60a804811a81aa17fefcd1b76ebb4e0e0 100644 (file)
@@ -1,7 +1,6 @@
 // run-pass
 #![allow(dead_code)]
 #![allow(non_camel_case_types)]
-#![feature(box_syntax)]
 
 #[derive(Copy, Clone)]
 enum side { mayo, catsup, vinegar }
@@ -21,5 +20,5 @@ fn foo(m: Box<meal>, cond: bool) {
 }
 
 pub fn main() {
-    foo(box meal::for_here(order::hamburger), true)
+    foo(Box::new(meal::for_here(order::hamburger)), true)
 }
index 70dce2c949035caedcb0da0ec969f0bab4b94b43..7f0cbd658f1177f05d2624082ae28dbe8bbf05c7 100644 (file)
@@ -6,7 +6,7 @@
 const BAZ: Bar = Bar;
 
 #[derive(Debug)]
-struct Foo([Bar; 1]);
+struct Foo(#[allow(unused_tuple_struct_fields)] [Bar; 1]);
 
 struct Biz;
 
index d93ffcb2262eb362edb6e0cd773599847741b139..78c3252d32e81d7a3409a2bef633aa476124150f 100644 (file)
@@ -25,9 +25,9 @@ impl<T> Front for Vec<T> {
     type Back = Vec<T>;
 }
 
-struct PtrBack<T: Front>(Vec<T::Back>);
+struct PtrBack<T: Front>(#[allow(unused_tuple_struct_fields)] Vec<T::Back>);
 
-struct M(PtrBack<Vec<M>>);
+struct M(#[allow(unused_tuple_struct_fields)] PtrBack<Vec<M>>);
 
 #[allow(unused_must_use)]
 fn main() {
index 840c7ff8355d0f20c8a8f736833a455f5a7a7f2a..7014d517f181ef9969b803d79ac8e0fc8492fbc0 100644 (file)
@@ -1,9 +1,8 @@
 // run-pass
-#![feature(box_syntax)]
 #![allow(dead_code)]
 
 pub fn main() {
-   let mut x: Box<_> = box 3;
+   let mut x: Box<_> = Box::new(3);
    x = x;
    assert_eq!(*x, 3);
 }
index a1213623e6f94f949190794dce7602ac6cbf83cf..8430e85df871514f1269f49b6c7b9bccfe2b6efa 100644 (file)
@@ -3,7 +3,7 @@
 use std::collections::HashMap;
 
 fn main() {
-    for _ in HashMap::new().iter().cloned() {} //~ ERROR type mismatch
-    //~^ ERROR type mismatch
-    //~| ERROR type mismatch
+    for _ in HashMap::new().iter().cloned() {} //~ ERROR expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
+    //~^ ERROR expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
+    //~| ERROR expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
 }
index e1ce6eed98efb9028005c7049e28041aaa4a3437..565a7fef379411cdd21ad61145fe9fb38c1eb2ca 100644 (file)
@@ -1,4 +1,4 @@
-error[E0271]: type mismatch resolving `<std::collections::hash_map::Iter<'_, _, _> as Iterator>::Item == &_`
+error[E0271]: expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
   --> $DIR/issue-33941.rs:6:36
    |
 LL |     for _ in HashMap::new().iter().cloned() {}
@@ -12,7 +12,7 @@ note: required by a bound in `cloned`
 LL |         Self: Sized + Iterator<Item = &'a T>,
    |                                ^^^^^^^^^^^^ required by this bound in `cloned`
 
-error[E0271]: type mismatch resolving `<std::collections::hash_map::Iter<'_, _, _> as Iterator>::Item == &_`
+error[E0271]: expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
   --> $DIR/issue-33941.rs:6:14
    |
 LL |     for _ in HashMap::new().iter().cloned() {}
@@ -23,7 +23,7 @@ LL |     for _ in HashMap::new().iter().cloned() {}
    = note: required because of the requirements on the impl of `Iterator` for `Cloned<std::collections::hash_map::Iter<'_, _, _>>`
    = note: required because of the requirements on the impl of `IntoIterator` for `Cloned<std::collections::hash_map::Iter<'_, _, _>>`
 
-error[E0271]: type mismatch resolving `<std::collections::hash_map::Iter<'_, _, _> as Iterator>::Item == &_`
+error[E0271]: expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
   --> $DIR/issue-33941.rs:6:14
    |
 LL |     for _ in HashMap::new().iter().cloned() {}
index 1e329d1522af4496188d9499b47a53acab024f21..ee5b22778117e1ca1c4d215e4283ad0557aacb47 100644 (file)
@@ -2,7 +2,6 @@
 #![allow(dead_code)]
 #![allow(non_snake_case)]
 #![allow(non_camel_case_types)]
-#![feature(box_syntax)]
 
 use std::cell::RefCell;
 
@@ -20,7 +19,7 @@ pub fn addEnd(&mut self, element: T) {
             next: None
         };
 
-        self.next = Some(box RefCell::new(newList));
+        self.next = Some(Box::new(RefCell::new(newList)));
     }
 }
 
index bad1bebc69754a8ff21d69323656ec810fd5aa67..5498091da58e36896f7f616dce0e3c63c94e8f3d 100644 (file)
@@ -1,7 +1,7 @@
 // run-pass
 #[repr(u8)]
 enum Foo {
-    Foo(u8),
+    Foo(#[allow(unused_tuple_struct_fields)] u8),
 }
 
 fn main() {
index a61c02c0a12c9a7e27681b5156d9b345a86b798f..5c6d078041600b7d92b7a1f083e52826d8a0675e 100644 (file)
@@ -7,7 +7,7 @@
 
 use std::iter::FusedIterator;
 
-struct Thing<'a>(&'a str);
+struct Thing<'a>(#[allow(unused_tuple_struct_fields)] &'a str);
 impl<'a> Iterator for Thing<'a> {
     type Item = &'a str;
     fn next(&mut self) -> Option<&'a str> {
index 62d1f5f8258860dd1fabb0dca7932e7db4eb2564..a809f7f132937c6f2cbad3ff0f76c0921a3fb425 100644 (file)
@@ -5,6 +5,7 @@
 use std::mem;
 
 const SZ: usize = 100;
+#[allow(unused_tuple_struct_fields)]
 struct P<T: ?Sized>([u8; SZ], T);
 
 type Ack<T> = P<P<T>>;
index 1809e822c54213d4dbdc222bbac07f17d90fbf4b..b1f028fbccb9d81846cca70723bffb735d86d69f 100644 (file)
@@ -1,5 +1,4 @@
 // run-pass
-#![feature(box_syntax)]
 #![allow(dead_code)]
 
 trait T {
@@ -26,7 +25,7 @@ fn print_s(s: &S) {
 }
 
 pub fn main() {
-    let s: Box<S> = box S { s: 5 };
+    let s: Box<S> = Box::new(S { s: 5 });
     print_s(&*s);
     let t: Box<dyn T> = s as Box<dyn T>;
     print_t(&*t);
index a121f0ba878efcf7be52cf1da7f658f2cb999aca..6de3405af0d95fda4f76ed0acd5df700650bbbec 100644 (file)
@@ -2,9 +2,8 @@
 // pretty-expanded FIXME #23616
 
 #![allow(path_statements)]
-#![feature(box_syntax)]
 
 pub fn main() {
-    let y: Box<_> = box 1;
+    let y: Box<_> = Box::new(1);
     y;
 }
index 642de6b8fe3527871144ed2d0a1f5ef3976f9878..5e61361f9877a2a1c87db010847106719e780ff9 100644 (file)
@@ -153,7 +153,7 @@ pub struct BufferUnordered<S> {
     }
 
     enum Slot<T> {
-        Next(usize),
+        Next(#[allow(unused_tuple_struct_fields)] usize),
         _Data { _a: T },
     }
 
index 48e617fd7ebb57ed6836791724e5c1efd11fd345..0d47a7f0c16c22a9e1770647295db96c3d1d924e 100644 (file)
@@ -7,7 +7,7 @@ fn default_method<T: std::fmt::Debug>(&self, x: &T) {
 }
 
 #[derive(Debug)]
-struct Y(isize);
+struct Y(#[allow(unused_tuple_struct_fields)] isize);
 
 #[derive(Debug)]
 struct Z<T: X+std::fmt::Debug> {
index 1d4f789828d8bd726534258facfee1094b7408e8..c418128c1866fe00edf37e953a355c954e359ef6 100644 (file)
@@ -2,7 +2,7 @@
 use std::iter::{Fuse, Cloned};
 use std::slice::Iter;
 
-struct Foo<'a, T: 'a>(&'a T);
+struct Foo<'a, T: 'a>(#[allow(unused_tuple_struct_fields)] &'a T);
 impl<'a, T: 'a> Copy for Foo<'a, T> {}
 impl<'a, T: 'a> Clone for Foo<'a, T> {
     fn clone(&self) -> Self { *self }
index 53785af09626ad3a21bdd7912a145944657885a7..e5b9e2ed57438bca387786d1b8fcf128b603007b 100644 (file)
@@ -2,8 +2,6 @@
 // pretty-expanded FIXME #23616
 #![allow(non_shorthand_field_patterns)]
 
-#![feature(box_syntax)]
-
 struct T { a: Box<isize> }
 
 trait U {
@@ -15,6 +13,6 @@ fn f(self) { }
 }
 
 pub fn main() {
-    let T { a: a } = T { a: box 0 };
+    let T { a: a } = T { a: Box::new(0) };
     a.f();
 }
index fab258f137e68c66f683a3d6b34a7ca002ec4aa8..3f1c6f855007cc34747eb95b259b822adb58276e 100644 (file)
@@ -1,5 +1,4 @@
 #![feature(box_patterns)]
-#![feature(box_syntax)]
 
 trait MyTrait {
     fn dummy(&self) {}
index 40db50278ca76ada7d8fb2f8d028ba740ee9af4f..83daded7e093e0176e78a5b980f59b5927c1054d 100644 (file)
@@ -1,5 +1,5 @@
 error[E0033]: type `Box<(dyn MyTrait + 'static)>` cannot be dereferenced
-  --> $DIR/issue-4972.rs:14:25
+  --> $DIR/issue-4972.rs:13:25
    |
 LL |         TraitWrapper::A(box ref map) => map,
    |                         ^^^^^^^^^^^ type `Box<(dyn MyTrait + 'static)>` cannot be dereferenced
index 5e926fabe2118201ed8e4958fb14bff1c8537e3a..69ed4b0e4328bdb794d945d065f0d2a48a845916 100644 (file)
@@ -1,5 +1,5 @@
 #![feature(box_patterns)]
-#![feature(box_syntax)]
+
 
 enum A { B, C }
 
index 5a83d1c2ff9fd1b10fb3b989849611e0906374be..e2f835c19973815c079602bfe34ccc9d811bca38 100644 (file)
@@ -2,8 +2,6 @@
 #![allow(dead_code)]
 // pretty-expanded FIXME #23616
 
-#![feature(box_syntax)]
-
 pub trait EventLoop {
     fn dummy(&self) { }
 }
@@ -37,5 +35,5 @@ pub fn new(event_loop: Box<dyn EventLoop+'static>) -> Scheduler {
 }
 
 pub fn main() {
-    let _sched = Scheduler::new(box UvEventLoop::new() as Box<dyn EventLoop>);
+    let _sched = Scheduler::new(Box::new(UvEventLoop::new()) as Box<dyn EventLoop>);
 }
index 38c98254b9350791571be7e50d038dd92c050ace..0c121a5eee6389b963fcb31da314725260591d77 100644 (file)
@@ -1,7 +1,7 @@
 // run-pass
 // pretty-expanded FIXME #23616
 
-struct A(bool);
+struct A(#[allow(unused_tuple_struct_fields)] bool);
 
 pub fn main() {
     let f = A;
index cd039506f381642f8fcdcc1d63f06d10fa406b50..852b264dc5dbf5a6629cf4d8e8c51daa5ba183ad 100644 (file)
@@ -1,5 +1,3 @@
-#![feature(box_syntax)]
-
 struct Foo {
     foo: isize,
 }
@@ -10,7 +8,7 @@ struct Bar {
 
 impl Bar {
     fn make_foo (&self, i: isize) -> Box<Foo> {
-        return box Foo { nonexistent: self, foo: i }; //~ ERROR: no field named
+        return Box::new(Foo { nonexistent: self, foo: i }); //~ ERROR: no field named
     }
 }
 
index bd0cb670bc210e4642e0b449797288284fecad55..dc8f8b878d730e9eef77b574ba4d026e267e3906 100644 (file)
@@ -1,8 +1,8 @@
 error[E0560]: struct `Foo` has no field named `nonexistent`
-  --> $DIR/issue-5439.rs:13:26
+  --> $DIR/issue-5439.rs:11:31
    |
-LL |         return box Foo { nonexistent: self, foo: i };
-   |                          ^^^^^^^^^^^ `Foo` does not have this field
+LL |         return Box::new(Foo { nonexistent: self, foo: i });
+   |                               ^^^^^^^^^^^ `Foo` does not have this field
    |
    = note: available fields are: `foo`
 
index aa513277830128d70f11828117d92aa69fba4ea3..810895b1b1bc4e40c39e009c6b88f816da09a7c7 100644 (file)
@@ -1,5 +1,4 @@
 // run-pass
-#![feature(box_syntax)]
 
 struct Dog {
     name : String
@@ -17,8 +16,8 @@ fn bark(&self) -> String {
 
 
 pub fn main() {
-    let snoopy = box Dog{name: "snoopy".to_string()};
-    let bubbles = box Dog{name: "bubbles".to_string()};
+    let snoopy = Box::new(Dog{name: "snoopy".to_string()});
+    let bubbles = Box::new(Dog{name: "bubbles".to_string()});
     let barker = [snoopy as Box<dyn Barks>, bubbles as Box<dyn Barks>];
 
     for pup in &barker {
index 63efec953118a7b7ca6328145eed3288c2a17064..f29a1e2a060d2a43d29fb2d63f97c9bb64aaec6b 100644 (file)
@@ -1,14 +1,12 @@
 // run-pass
 // pretty-expanded FIXME #23616
 
-#![feature(box_syntax)]
-
 struct Element;
 
 macro_rules! foo {
     ($tag: expr, $string: expr) => {
         if $tag == $string {
-            let element: Box<_> = box Element;
+            let element: Box<_> = Box::new(Element);
             unsafe {
                 return std::mem::transmute::<_, usize>(element);
             }
index 2f64342a6dd82c3cdf9ddb9fc1b0c2d15ebae775..991c52321bfeb0f1fe19bb42124264f549e54305 100644 (file)
@@ -2,8 +2,6 @@
 #![allow(dead_code)]
 // pretty-expanded FIXME #23616
 
-#![feature(box_syntax)]
-
 pub struct Foo {
     a: isize,
 }
@@ -14,7 +12,7 @@ struct Bar<'a> {
 }
 
 fn check(a: Box<Foo>) {
-    let _ic = Bar{ b: &*a, a: box None };
+    let _ic = Bar{ b: &*a, a: Box::new(None) };
 }
 
 pub fn main(){}
index c018ac73fb53669a74ff59fb2787bb041a5f210c..776fdbb7466f7a17ac7b1f9246d7d7989c84449c 100644 (file)
@@ -4,7 +4,7 @@
 
 use std::any::type_name;
 
-struct Bar<M>(M);
+struct Bar<M>(#[allow(unused_tuple_struct_fields)] M);
 
 impl<M> Bar<M> {
     fn foo(&self) -> &'static str {
index d8bd83f0dc6adfba71918c8eec3f61cf60db59dd..e5f245f6fb80fb67df2993bf56ea2a742ef51a9f 100644 (file)
@@ -1,8 +1,6 @@
 // run-pass
 // pretty-expanded FIXME #23616
 
-#![feature(box_syntax)]
-
 pub enum Thing {
     A(Box<dyn Foo+'static>)
 }
@@ -16,7 +14,7 @@ fn dummy(&self) { }
 impl Foo for Struct {}
 
 pub fn main() {
-    match Thing::A(box Struct as Box<dyn Foo + 'static>) {
+    match Thing::A(Box::new(Struct) as Box<dyn Foo + 'static>) {
         Thing::A(_a) => 0,
     };
 }
index e066aa52923b96136c47d6f43cf56583095619b6..757e9608f1a1f2152b095dfe92e8040e92927304 100644 (file)
@@ -3,7 +3,6 @@
 // pretty-expanded FIXME #23616
 
 #![feature(box_patterns)]
-#![feature(box_syntax)]
 
 fn foo(box (_x, _y): Box<(isize, isize)>) {}
 
index e5ab65169ce3bfad4818c90857a3d7f79b640207..f581429a281540cf6242a6c4708beac4ccacee3f 100644 (file)
@@ -17,10 +17,10 @@ LL | | }
    = note: this error originates in the macro `suite` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: missing type for `const` item
-  --> $DIR/issue-69396-const-no-type-in-macro.rs:4:19
+  --> $DIR/issue-69396-const-no-type-in-macro.rs:4:20
    |
 LL |               const A = "A".$fn();
-   |                     ^ help: provide a type for the constant: `A: usize`
+   |                      ^ help: provide a type for the constant: `: usize`
 ...
 LL | / suite! {
 LL | |     len;
@@ -31,13 +31,13 @@ LL | | }
    = note: this error originates in the macro `suite` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
-  --> $DIR/issue-69396-const-no-type-in-macro.rs:4:19
+  --> $DIR/issue-69396-const-no-type-in-macro.rs:4:20
    |
 LL |               const A = "A".$fn();
-   |                     ^
-   |                     |
-   |                     not allowed in type signatures
-   |                     help: replace with the correct type: `bool`
+   |                      ^
+   |                      |
+   |                      not allowed in type signatures
+   |                      help: replace with the correct type: `bool`
 ...
 LL | / suite! {
 LL | |     len;
index c1f400b33049ff37ebea3d9a57227e7afaa900a3..1fb01303c78361d208b70c9d8579e76188c6562c 100644 (file)
@@ -1,5 +1,3 @@
-#![feature(box_syntax)]
-
 use std::cell::RefCell;
 use std::rc::Rc;
 
@@ -23,6 +21,6 @@ struct A {
 }
 
 fn main() {
-    let a = A {v: box B{v: None} as Box<dyn Foo + Send>};
+    let a = A {v: Box::new(B{v: None}) as Box<dyn Foo + Send>};
     //~^ ERROR `Rc<RefCell<A>>` cannot be sent between threads safely
 }
index f6cb1cbdc11c677df8fd6d9616a7e7c72c73ac71..4575f4dbae62d3cca76913ae3e73bcd4e0774fc8 100644 (file)
@@ -1,13 +1,13 @@
 error[E0277]: `Rc<RefCell<A>>` cannot be sent between threads safely
-  --> $DIR/issue-7013.rs:26:19
+  --> $DIR/issue-7013.rs:24:19
    |
-LL |     let a = A {v: box B{v: None} as Box<dyn Foo + Send>};
-   |                   ^^^^^^^^^^^^^^ `Rc<RefCell<A>>` cannot be sent between threads safely
+LL |     let a = A {v: Box::new(B{v: None}) as Box<dyn Foo + Send>};
+   |                   ^^^^^^^^^^^^^^^^^^^^ `Rc<RefCell<A>>` cannot be sent between threads safely
    |
    = help: within `B`, the trait `Send` is not implemented for `Rc<RefCell<A>>`
    = note: required because it appears within the type `Option<Rc<RefCell<A>>>`
 note: required because it appears within the type `B`
-  --> $DIR/issue-7013.rs:10:8
+  --> $DIR/issue-7013.rs:8:8
    |
 LL | struct B {
    |        ^
index 83c52d286a199c9ea1c2d9f71c22aafef4af4047..79642bd411b38b1fe46de507b6664ac9839fab81 100644 (file)
@@ -1,9 +1,7 @@
-#![feature(box_syntax)]
-
 use std::cell::RefCell;
 
 // Regression test for issue 7364
-static boxed: Box<RefCell<isize>> = box RefCell::new(0);
+static boxed: Box<RefCell<isize>> = Box::new(RefCell::new(0));
 //~^ ERROR `RefCell<isize>` cannot be shared between threads safely [E0277]
 
 fn main() { }
index f2e80f451695ac3a9c4fe235572cff1f146e1613..1018a92f64dfcba442043fab2415aa8c81659e1e 100644 (file)
@@ -1,7 +1,7 @@
 error[E0277]: `RefCell<isize>` cannot be shared between threads safely
-  --> $DIR/issue-7364.rs:6:15
+  --> $DIR/issue-7364.rs:4:15
    |
-LL | static boxed: Box<RefCell<isize>> = box RefCell::new(0);
+LL | static boxed: Box<RefCell<isize>> = Box::new(RefCell::new(0));
    |               ^^^^^^^^^^^^^^^^^^^ `RefCell<isize>` cannot be shared between threads safely
    |
    = help: the trait `Sync` is not implemented for `RefCell<isize>`
index 2961dc79f10efed104156e1be50d1d373c7a6d6b..c089c33083984d7f77ac91b36a45cc64dcf3f7a7 100644 (file)
@@ -8,8 +8,6 @@
 
 */
 
-#![feature(box_syntax)]
-
 pub fn main() {}
 
 trait A {
@@ -19,4 +17,4 @@ fn dummy(&self) { }
 impl<T: 'static> A for T {}
 
 fn owned2<T: 'static>(a: Box<T>) { a as Box<dyn A>; }
-fn owned3<T: 'static>(a: Box<T>) { box a as Box<dyn A>; }
+fn owned3<T: 'static>(a: Box<T>) { Box::new(a) as Box<dyn A>; }
index de833324bd20f4be22b8356ff04c47ca45fc3d71..f64887136cad646daa73b532d95c92b278e31d6d 100644 (file)
@@ -6,7 +6,7 @@
 trait FooBar {
     fn dummy(&self) { }
 }
-struct Bar(i32);
+struct Bar(#[allow(unused_tuple_struct_fields)] i32);
 struct Foo { bar: Bar }
 
 impl FooBar for Bar {}
index 780a6419c5f305ba60b94c10e04ce4e361a696f7..04110b3ae8959a3ca498d909a22febd2df33f54d 100644 (file)
@@ -4,8 +4,6 @@
 #![allow(non_snake_case)]
 // ignore-pretty unreported
 
-#![feature(box_syntax)]
-
 pub trait bomb { fn boom(&self, _: Ident); }
 pub struct S;
 impl bomb for S { fn boom(&self, _: Ident) { } }
@@ -29,6 +27,6 @@ pub fn light_fuse(fld: Box<dyn bomb>) {
 }
 
 pub fn main() {
-    let b = box S as Box<dyn bomb>;
+    let b = Box::new(S) as Box<dyn bomb>;
     light_fuse(b);
 }
index dbb0fa524ef5180d1489dc9e3663751a6b309c2f..65718343fc6a98a1379419e37b56b3b00d4da7d0 100644 (file)
@@ -3,7 +3,6 @@
 
 // run-pass
 #![allow(dead_code)]
-#![feature(box_syntax)]
 
 // Tests for a previous bug that occurred due to an interaction
 // between struct field initialization and the auto-coercion
@@ -24,11 +23,11 @@ struct Thing2<'a> {
 pub fn main() {
     let _t1_fixed = Thing1 {
         baz: &[],
-        bar: box 32,
+        bar: Box::new(32),
     };
     Thing1 {
         baz: &Vec::new(),
-        bar: box 32,
+        bar: Box::new(32),
     };
     let _t2_fixed = Thing2 {
         baz: &[],
diff --git a/src/test/ui/issues/issue-99838.rs b/src/test/ui/issues/issue-99838.rs
new file mode 100644 (file)
index 0000000..eaeeac7
--- /dev/null
@@ -0,0 +1,40 @@
+// run-pass
+#![feature(bench_black_box)]
+use std::hint;
+
+struct U16(u16);
+
+impl Drop for U16 {
+    fn drop(&mut self) {
+        // Prevent LLVM from optimizing away our alignment check.
+        assert!(hint::black_box(self as *mut U16 as usize) % 2 == 0);
+    }
+}
+
+struct HasDrop;
+
+impl Drop for HasDrop {
+    fn drop(&mut self) {}
+}
+
+struct Wrapper {
+    _a: U16,
+    b: HasDrop,
+}
+
+#[repr(packed)]
+struct Misalign(u8, Wrapper);
+
+fn main() {
+    let m = Misalign(
+        0,
+        Wrapper {
+            _a: U16(10),
+            b: HasDrop,
+        },
+    );
+    // Put it somewhere definitely even (so the `a` field is definitely at an odd address).
+    let m: ([u16; 0], Misalign) = ([], m);
+    // Move out one field, so we run custom per-field drop logic below.
+    let _x = m.1.1.b;
+}
diff --git a/src/test/ui/json-and-color.rs b/src/test/ui/json-and-color.rs
deleted file mode 100644 (file)
index 6f8326f..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-// compile-flags: --json=artifacts --error-format=json --color never
-
-fn main() {}
diff --git a/src/test/ui/json-and-color.stderr b/src/test/ui/json-and-color.stderr
deleted file mode 100644 (file)
index 1cda6af..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-error: cannot specify the `--color` option with `--json`
-
diff --git a/src/test/ui/json-and-error-format.rs b/src/test/ui/json-and-error-format.rs
deleted file mode 100644 (file)
index 6e2d73c..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-// compile-flags: --json=artifacts --error-format=short
-
-fn main() {}
diff --git a/src/test/ui/json-and-error-format.stderr b/src/test/ui/json-and-error-format.stderr
deleted file mode 100644 (file)
index 80e0221..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-error: using `--json` requires also using `--error-format=json`
-
diff --git a/src/test/ui/json-bom-plus-crlf-multifile-aux.rs b/src/test/ui/json-bom-plus-crlf-multifile-aux.rs
deleted file mode 100644 (file)
index 991ea1d..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-// (This line has BOM so it's ignored by compiletest for directives)\r
-//\r
-// ignore-test Not a test. Used by other tests\r
-// ignore-tidy-cr\r
-\r
-// For easier verifying, the byte offsets in this file should match those\r
-// in the json-bom-plus-crlf.rs - given the actual fn is identical (just with\r
-// a different, but equally sized name), the easiest way to do this is to\r
-// ensure the two files are of equal size on disk.\r
-// Padding............................\r
-\r
-// N.B., this file needs CRLF line endings. The .gitattributes file in\r
-// this directory should enforce it.\r
-\r
-pub fn test() {\r
-\r
-    let s : String = 1;  // Error in the middle of line.\r
-\r
-    let s : String = 1\r
-    ;  // Error before the newline.\r
-\r
-    let s : String =\r
-1;  // Error after the newline.\r
-\r
-    let s : String = (\r
-    );  // Error spanning the newline.\r
-}\r
diff --git a/src/test/ui/json-bom-plus-crlf-multifile.rs b/src/test/ui/json-bom-plus-crlf-multifile.rs
deleted file mode 100644 (file)
index 9290e01..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-// (This line has BOM so it's ignored by compiletest for directives)\r
-//\r
-// compile-flags: --json=diagnostic-short --error-format=json\r
-// ignore-tidy-cr\r
-\r
-#[path = "json-bom-plus-crlf-multifile-aux.rs"]\r
-mod json_bom_plus_crlf_multifile_aux;\r
-\r
-fn main() {\r
-    json_bom_plus_crlf_multifile_aux::test();\r
-}\r
diff --git a/src/test/ui/json-bom-plus-crlf-multifile.stderr b/src/test/ui/json-bom-plus-crlf-multifile.stderr
deleted file mode 100644 (file)
index 02f3bc6..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
-
-Erroneous code examples:
-
-```compile_fail,E0308
-fn plus_one(x: i32) -> i32 {
-    x + 1
-}
-
-plus_one(\"Not a number\");
-//       ^^^^^^^^^^^^^^ expected `i32`, found `&str`
-
-if \"Not a bool\" {
-// ^^^^^^^^^^^^ expected `bool`, found `&str`
-}
-
-let x: f32 = \"Not a float\";
-//     ---   ^^^^^^^^^^^^^ expected `f32`, found `&str`
-//     |
-//     expected due to this
-```
-
-This error occurs when an expression was used in a place where the compiler
-expected an expression of a different type. It can occur in several cases, the
-most common being when calling a function and passing an argument which has a
-different type than the matching type in the function declaration.
-"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":621,"byte_end":622,"line_start":17,"line_end":17,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1;  // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":612,"byte_end":618,"line_start":17,"line_end":17,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String = 1;  // Error in the middle of line.","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":622,"byte_end":622,"line_start":17,"line_end":17,"column_start":23,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1;  // Error in the middle of line.","highlight_start":23,"highlight_end":23}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:17:22: error[E0308]: mismatched types
-"}
-{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
-
-Erroneous code examples:
-
-```compile_fail,E0308
-fn plus_one(x: i32) -> i32 {
-    x + 1
-}
-
-plus_one(\"Not a number\");
-//       ^^^^^^^^^^^^^^ expected `i32`, found `&str`
-
-if \"Not a bool\" {
-// ^^^^^^^^^^^^ expected `bool`, found `&str`
-}
-
-let x: f32 = \"Not a float\";
-//     ---   ^^^^^^^^^^^^^ expected `f32`, found `&str`
-//     |
-//     expected due to this
-```
-
-This error occurs when an expression was used in a place where the compiler
-expected an expression of a different type. It can occur in several cases, the
-most common being when calling a function and passing an argument which has a
-different type than the matching type in the function declaration.
-"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":681,"byte_end":682,"line_start":19,"line_end":19,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":672,"byte_end":678,"line_start":19,"line_end":19,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String = 1","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":682,"byte_end":682,"line_start":19,"line_end":19,"column_start":23,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1","highlight_start":23,"highlight_end":23}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:19:22: error[E0308]: mismatched types
-"}
-{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
-
-Erroneous code examples:
-
-```compile_fail,E0308
-fn plus_one(x: i32) -> i32 {
-    x + 1
-}
-
-plus_one(\"Not a number\");
-//       ^^^^^^^^^^^^^^ expected `i32`, found `&str`
-
-if \"Not a bool\" {
-// ^^^^^^^^^^^^ expected `bool`, found `&str`
-}
-
-let x: f32 = \"Not a float\";
-//     ---   ^^^^^^^^^^^^^ expected `f32`, found `&str`
-//     |
-//     expected due to this
-```
-
-This error occurs when an expression was used in a place where the compiler
-expected an expression of a different type. It can occur in several cases, the
-most common being when calling a function and passing an argument which has a
-different type than the matching type in the function declaration.
-"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":745,"byte_end":746,"line_start":23,"line_end":23,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1;  // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":735,"byte_end":741,"line_start":22,"line_end":22,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String =","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":746,"byte_end":746,"line_start":23,"line_end":23,"column_start":2,"column_end":2,"is_primary":true,"text":[{"text":"1;  // Error after the newline.","highlight_start":2,"highlight_end":2}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:23:1: error[E0308]: mismatched types
-"}
-{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
-
-Erroneous code examples:
-
-```compile_fail,E0308
-fn plus_one(x: i32) -> i32 {
-    x + 1
-}
-
-plus_one(\"Not a number\");
-//       ^^^^^^^^^^^^^^ expected `i32`, found `&str`
-
-if \"Not a bool\" {
-// ^^^^^^^^^^^^ expected `bool`, found `&str`
-}
-
-let x: f32 = \"Not a float\";
-//     ---   ^^^^^^^^^^^^^ expected `f32`, found `&str`
-//     |
-//     expected due to this
-```
-
-This error occurs when an expression was used in a place where the compiler
-expected an expression of a different type. It can occur in several cases, the
-most common being when calling a function and passing an argument which has a
-different type than the matching type in the function declaration.
-"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":801,"byte_end":809,"line_start":25,"line_end":26,"column_start":22,"column_end":6,"is_primary":true,"text":[{"text":"    let s : String = (","highlight_start":22,"highlight_end":23},{"text":"    );  // Error spanning the newline.","highlight_start":1,"highlight_end":6}],"label":"expected struct `String`, found `()`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":792,"byte_end":798,"line_start":25,"line_end":25,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String = (","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:25:22: error[E0308]: mismatched types
-"}
-{"message":"aborting due to 4 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to 4 previous errors
-"}
diff --git a/src/test/ui/json-bom-plus-crlf.rs b/src/test/ui/json-bom-plus-crlf.rs
deleted file mode 100644 (file)
index be5b7dd..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-// (This line has BOM so it's ignored by compiletest for directives)\r
-//\r
-// compile-flags: --json=diagnostic-short --error-format=json\r
-// ignore-tidy-cr\r
-\r
-// For easier verifying, the byte offsets in this file should match those\r
-// in the json_bom_plus_crlf_multifile_aux.rs - given the actual fn is\r
-// identical (just with a different, but equally sized name), the easiest way\r
-// to do this is to ensure the two files are of equal size on disk.\r
-\r
-// N.B., this file needs CRLF line endings. The .gitattributes file in\r
-// this directory should enforce it.\r
-\r
-fn main() {\r
-\r
-    let s : String = 1;  // Error in the middle of line.\r
-\r
-    let s : String = 1\r
-    ;  // Error before the newline.\r
-\r
-    let s : String =\r
-1;  // Error after the newline.\r
-\r
-    let s : String = (\r
-    );  // Error spanning the newline.\r
-}\r
diff --git a/src/test/ui/json-bom-plus-crlf.stderr b/src/test/ui/json-bom-plus-crlf.stderr
deleted file mode 100644 (file)
index df6bd72..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
-
-Erroneous code examples:
-
-```compile_fail,E0308
-fn plus_one(x: i32) -> i32 {
-    x + 1
-}
-
-plus_one(\"Not a number\");
-//       ^^^^^^^^^^^^^^ expected `i32`, found `&str`
-
-if \"Not a bool\" {
-// ^^^^^^^^^^^^ expected `bool`, found `&str`
-}
-
-let x: f32 = \"Not a float\";
-//     ---   ^^^^^^^^^^^^^ expected `f32`, found `&str`
-//     |
-//     expected due to this
-```
-
-This error occurs when an expression was used in a place where the compiler
-expected an expression of a different type. It can occur in several cases, the
-most common being when calling a function and passing an argument which has a
-different type than the matching type in the function declaration.
-"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":606,"byte_end":607,"line_start":16,"line_end":16,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1;  // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":597,"byte_end":603,"line_start":16,"line_end":16,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String = 1;  // Error in the middle of line.","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":607,"byte_end":607,"line_start":16,"line_end":16,"column_start":23,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1;  // Error in the middle of line.","highlight_start":23,"highlight_end":23}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:16:22: error[E0308]: mismatched types
-"}
-{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
-
-Erroneous code examples:
-
-```compile_fail,E0308
-fn plus_one(x: i32) -> i32 {
-    x + 1
-}
-
-plus_one(\"Not a number\");
-//       ^^^^^^^^^^^^^^ expected `i32`, found `&str`
-
-if \"Not a bool\" {
-// ^^^^^^^^^^^^ expected `bool`, found `&str`
-}
-
-let x: f32 = \"Not a float\";
-//     ---   ^^^^^^^^^^^^^ expected `f32`, found `&str`
-//     |
-//     expected due to this
-```
-
-This error occurs when an expression was used in a place where the compiler
-expected an expression of a different type. It can occur in several cases, the
-most common being when calling a function and passing an argument which has a
-different type than the matching type in the function declaration.
-"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":666,"byte_end":667,"line_start":18,"line_end":18,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":657,"byte_end":663,"line_start":18,"line_end":18,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String = 1","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":667,"byte_end":667,"line_start":18,"line_end":18,"column_start":23,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1","highlight_start":23,"highlight_end":23}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:18:22: error[E0308]: mismatched types
-"}
-{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
-
-Erroneous code examples:
-
-```compile_fail,E0308
-fn plus_one(x: i32) -> i32 {
-    x + 1
-}
-
-plus_one(\"Not a number\");
-//       ^^^^^^^^^^^^^^ expected `i32`, found `&str`
-
-if \"Not a bool\" {
-// ^^^^^^^^^^^^ expected `bool`, found `&str`
-}
-
-let x: f32 = \"Not a float\";
-//     ---   ^^^^^^^^^^^^^ expected `f32`, found `&str`
-//     |
-//     expected due to this
-```
-
-This error occurs when an expression was used in a place where the compiler
-expected an expression of a different type. It can occur in several cases, the
-most common being when calling a function and passing an argument which has a
-different type than the matching type in the function declaration.
-"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":730,"byte_end":731,"line_start":22,"line_end":22,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1;  // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":720,"byte_end":726,"line_start":21,"line_end":21,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String =","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":731,"byte_end":731,"line_start":22,"line_end":22,"column_start":2,"column_end":2,"is_primary":true,"text":[{"text":"1;  // Error after the newline.","highlight_start":2,"highlight_end":2}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:22:1: error[E0308]: mismatched types
-"}
-{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
-
-Erroneous code examples:
-
-```compile_fail,E0308
-fn plus_one(x: i32) -> i32 {
-    x + 1
-}
-
-plus_one(\"Not a number\");
-//       ^^^^^^^^^^^^^^ expected `i32`, found `&str`
-
-if \"Not a bool\" {
-// ^^^^^^^^^^^^ expected `bool`, found `&str`
-}
-
-let x: f32 = \"Not a float\";
-//     ---   ^^^^^^^^^^^^^ expected `f32`, found `&str`
-//     |
-//     expected due to this
-```
-
-This error occurs when an expression was used in a place where the compiler
-expected an expression of a different type. It can occur in several cases, the
-most common being when calling a function and passing an argument which has a
-different type than the matching type in the function declaration.
-"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":786,"byte_end":794,"line_start":24,"line_end":25,"column_start":22,"column_end":6,"is_primary":true,"text":[{"text":"    let s : String = (","highlight_start":22,"highlight_end":23},{"text":"    );  // Error spanning the newline.","highlight_start":1,"highlight_end":6}],"label":"expected struct `String`, found `()`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":777,"byte_end":783,"line_start":24,"line_end":24,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String = (","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-bom-plus-crlf.rs:24:22: error[E0308]: mismatched types
-"}
-{"message":"aborting due to 4 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to 4 previous errors
-"}
diff --git a/src/test/ui/json-invalid.rs b/src/test/ui/json-invalid.rs
deleted file mode 100644 (file)
index 54d0dd1..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-// compile-flags: --json=foo --error-format=json
-
-fn main() {}
diff --git a/src/test/ui/json-invalid.stderr b/src/test/ui/json-invalid.stderr
deleted file mode 100644 (file)
index 18bc76a..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-error: unknown `--json` option `foo`
-
diff --git a/src/test/ui/json-multiple.polonius.stderr b/src/test/ui/json-multiple.polonius.stderr
deleted file mode 100644 (file)
index 0e4d442..0000000
+++ /dev/null
@@ -1 +0,0 @@
-{"artifact":"$TEST_BUILD_DIR/json-multiple.polonius/libjson_multiple.rlib","emit":"link"}
diff --git a/src/test/ui/json-multiple.rs b/src/test/ui/json-multiple.rs
deleted file mode 100644 (file)
index fb12633..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-// build-pass
-// ignore-pass (different metadata emitted in different modes)
-// compile-flags: --json=diagnostic-short --json artifacts --error-format=json
-
-#![crate_type = "lib"]
diff --git a/src/test/ui/json-multiple.stderr b/src/test/ui/json-multiple.stderr
deleted file mode 100644 (file)
index 7ed3451..0000000
+++ /dev/null
@@ -1 +0,0 @@
-{"artifact":"$TEST_BUILD_DIR/json-multiple/libjson_multiple.rlib","emit":"link"}
diff --git a/src/test/ui/json-options.polonius.stderr b/src/test/ui/json-options.polonius.stderr
deleted file mode 100644 (file)
index e21f6f8..0000000
+++ /dev/null
@@ -1 +0,0 @@
-{"artifact":"$TEST_BUILD_DIR/json-options.polonius/libjson_options.rlib","emit":"link"}
diff --git a/src/test/ui/json-options.rs b/src/test/ui/json-options.rs
deleted file mode 100644 (file)
index 8b6ba13..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-// build-pass
-// ignore-pass (different metadata emitted in different modes)
-// compile-flags: --json=diagnostic-short,artifacts --error-format=json
-
-#![crate_type = "lib"]
diff --git a/src/test/ui/json-options.stderr b/src/test/ui/json-options.stderr
deleted file mode 100644 (file)
index 2497773..0000000
+++ /dev/null
@@ -1 +0,0 @@
-{"artifact":"$TEST_BUILD_DIR/json-options/libjson_options.rlib","emit":"link"}
diff --git a/src/test/ui/json-short.rs b/src/test/ui/json-short.rs
deleted file mode 100644 (file)
index 7414a55..0000000
+++ /dev/null
@@ -1 +0,0 @@
-// compile-flags: --json=diagnostic-short --error-format=json
diff --git a/src/test/ui/json-short.stderr b/src/test/ui/json-short.stderr
deleted file mode 100644 (file)
index 3bd85b0..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-{"message":"`main` function not found in crate `json_short`","code":{"code":"E0601","explanation":"No `main` function was found in a binary crate.
-
-To fix this error, add a `main` function:
-
-```
-fn main() {
-    // Your program will start here.
-    println!(\"Hello world!\");
-}
-```
-
-If you don't know the basics of Rust, you can look at the
-[Rust Book][rust-book] to get started.
-
-[rust-book]: https://doc.rust-lang.org/book/
-"},"level":"error","spans":[{"file_name":"$DIR/json-short.rs","byte_start":62,"byte_end":62,"line_start":1,"line_end":1,"column_start":63,"column_end":63,"is_primary":true,"text":[{"text":"// compile-flags: --json=diagnostic-short --error-format=json","highlight_start":63,"highlight_end":63}],"label":"consider adding a `main` function to `$DIR/json-short.rs`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-short.rs:1:63: error[E0601]: `main` function not found in crate `json_short`
-"}
-{"message":"aborting due to previous error","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to previous error
-"}
diff --git a/src/test/ui/json/json-and-color.rs b/src/test/ui/json/json-and-color.rs
new file mode 100644 (file)
index 0000000..6f8326f
--- /dev/null
@@ -0,0 +1,3 @@
+// compile-flags: --json=artifacts --error-format=json --color never
+
+fn main() {}
diff --git a/src/test/ui/json/json-and-color.stderr b/src/test/ui/json/json-and-color.stderr
new file mode 100644 (file)
index 0000000..1cda6af
--- /dev/null
@@ -0,0 +1,2 @@
+error: cannot specify the `--color` option with `--json`
+
diff --git a/src/test/ui/json/json-and-error-format.rs b/src/test/ui/json/json-and-error-format.rs
new file mode 100644 (file)
index 0000000..6e2d73c
--- /dev/null
@@ -0,0 +1,3 @@
+// compile-flags: --json=artifacts --error-format=short
+
+fn main() {}
diff --git a/src/test/ui/json/json-and-error-format.stderr b/src/test/ui/json/json-and-error-format.stderr
new file mode 100644 (file)
index 0000000..80e0221
--- /dev/null
@@ -0,0 +1,2 @@
+error: using `--json` requires also using `--error-format=json`
+
diff --git a/src/test/ui/json/json-bom-plus-crlf-multifile-aux.rs b/src/test/ui/json/json-bom-plus-crlf-multifile-aux.rs
new file mode 100644 (file)
index 0000000..991ea1d
--- /dev/null
@@ -0,0 +1,27 @@
+// (This line has BOM so it's ignored by compiletest for directives)\r
+//\r
+// ignore-test Not a test. Used by other tests\r
+// ignore-tidy-cr\r
+\r
+// For easier verifying, the byte offsets in this file should match those\r
+// in the json-bom-plus-crlf.rs - given the actual fn is identical (just with\r
+// a different, but equally sized name), the easiest way to do this is to\r
+// ensure the two files are of equal size on disk.\r
+// Padding............................\r
+\r
+// N.B., this file needs CRLF line endings. The .gitattributes file in\r
+// this directory should enforce it.\r
+\r
+pub fn test() {\r
+\r
+    let s : String = 1;  // Error in the middle of line.\r
+\r
+    let s : String = 1\r
+    ;  // Error before the newline.\r
+\r
+    let s : String =\r
+1;  // Error after the newline.\r
+\r
+    let s : String = (\r
+    );  // Error spanning the newline.\r
+}\r
diff --git a/src/test/ui/json/json-bom-plus-crlf-multifile.rs b/src/test/ui/json/json-bom-plus-crlf-multifile.rs
new file mode 100644 (file)
index 0000000..9290e01
--- /dev/null
@@ -0,0 +1,11 @@
+// (This line has BOM so it's ignored by compiletest for directives)\r
+//\r
+// compile-flags: --json=diagnostic-short --error-format=json\r
+// ignore-tidy-cr\r
+\r
+#[path = "json-bom-plus-crlf-multifile-aux.rs"]\r
+mod json_bom_plus_crlf_multifile_aux;\r
+\r
+fn main() {\r
+    json_bom_plus_crlf_multifile_aux::test();\r
+}\r
diff --git a/src/test/ui/json/json-bom-plus-crlf-multifile.stderr b/src/test/ui/json/json-bom-plus-crlf-multifile.stderr
new file mode 100644 (file)
index 0000000..02f3bc6
--- /dev/null
@@ -0,0 +1,114 @@
+{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
+
+Erroneous code examples:
+
+```compile_fail,E0308
+fn plus_one(x: i32) -> i32 {
+    x + 1
+}
+
+plus_one(\"Not a number\");
+//       ^^^^^^^^^^^^^^ expected `i32`, found `&str`
+
+if \"Not a bool\" {
+// ^^^^^^^^^^^^ expected `bool`, found `&str`
+}
+
+let x: f32 = \"Not a float\";
+//     ---   ^^^^^^^^^^^^^ expected `f32`, found `&str`
+//     |
+//     expected due to this
+```
+
+This error occurs when an expression was used in a place where the compiler
+expected an expression of a different type. It can occur in several cases, the
+most common being when calling a function and passing an argument which has a
+different type than the matching type in the function declaration.
+"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":621,"byte_end":622,"line_start":17,"line_end":17,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1;  // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":612,"byte_end":618,"line_start":17,"line_end":17,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String = 1;  // Error in the middle of line.","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":622,"byte_end":622,"line_start":17,"line_end":17,"column_start":23,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1;  // Error in the middle of line.","highlight_start":23,"highlight_end":23}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:17:22: error[E0308]: mismatched types
+"}
+{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
+
+Erroneous code examples:
+
+```compile_fail,E0308
+fn plus_one(x: i32) -> i32 {
+    x + 1
+}
+
+plus_one(\"Not a number\");
+//       ^^^^^^^^^^^^^^ expected `i32`, found `&str`
+
+if \"Not a bool\" {
+// ^^^^^^^^^^^^ expected `bool`, found `&str`
+}
+
+let x: f32 = \"Not a float\";
+//     ---   ^^^^^^^^^^^^^ expected `f32`, found `&str`
+//     |
+//     expected due to this
+```
+
+This error occurs when an expression was used in a place where the compiler
+expected an expression of a different type. It can occur in several cases, the
+most common being when calling a function and passing an argument which has a
+different type than the matching type in the function declaration.
+"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":681,"byte_end":682,"line_start":19,"line_end":19,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":672,"byte_end":678,"line_start":19,"line_end":19,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String = 1","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":682,"byte_end":682,"line_start":19,"line_end":19,"column_start":23,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1","highlight_start":23,"highlight_end":23}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:19:22: error[E0308]: mismatched types
+"}
+{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
+
+Erroneous code examples:
+
+```compile_fail,E0308
+fn plus_one(x: i32) -> i32 {
+    x + 1
+}
+
+plus_one(\"Not a number\");
+//       ^^^^^^^^^^^^^^ expected `i32`, found `&str`
+
+if \"Not a bool\" {
+// ^^^^^^^^^^^^ expected `bool`, found `&str`
+}
+
+let x: f32 = \"Not a float\";
+//     ---   ^^^^^^^^^^^^^ expected `f32`, found `&str`
+//     |
+//     expected due to this
+```
+
+This error occurs when an expression was used in a place where the compiler
+expected an expression of a different type. It can occur in several cases, the
+most common being when calling a function and passing an argument which has a
+different type than the matching type in the function declaration.
+"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":745,"byte_end":746,"line_start":23,"line_end":23,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1;  // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":735,"byte_end":741,"line_start":22,"line_end":22,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String =","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":746,"byte_end":746,"line_start":23,"line_end":23,"column_start":2,"column_end":2,"is_primary":true,"text":[{"text":"1;  // Error after the newline.","highlight_start":2,"highlight_end":2}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:23:1: error[E0308]: mismatched types
+"}
+{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
+
+Erroneous code examples:
+
+```compile_fail,E0308
+fn plus_one(x: i32) -> i32 {
+    x + 1
+}
+
+plus_one(\"Not a number\");
+//       ^^^^^^^^^^^^^^ expected `i32`, found `&str`
+
+if \"Not a bool\" {
+// ^^^^^^^^^^^^ expected `bool`, found `&str`
+}
+
+let x: f32 = \"Not a float\";
+//     ---   ^^^^^^^^^^^^^ expected `f32`, found `&str`
+//     |
+//     expected due to this
+```
+
+This error occurs when an expression was used in a place where the compiler
+expected an expression of a different type. It can occur in several cases, the
+most common being when calling a function and passing an argument which has a
+different type than the matching type in the function declaration.
+"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":801,"byte_end":809,"line_start":25,"line_end":26,"column_start":22,"column_end":6,"is_primary":true,"text":[{"text":"    let s : String = (","highlight_start":22,"highlight_end":23},{"text":"    );  // Error spanning the newline.","highlight_start":1,"highlight_end":6}],"label":"expected struct `String`, found `()`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":792,"byte_end":798,"line_start":25,"line_end":25,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String = (","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:25:22: error[E0308]: mismatched types
+"}
+{"message":"aborting due to 4 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to 4 previous errors
+"}
diff --git a/src/test/ui/json/json-bom-plus-crlf.rs b/src/test/ui/json/json-bom-plus-crlf.rs
new file mode 100644 (file)
index 0000000..be5b7dd
--- /dev/null
@@ -0,0 +1,26 @@
+// (This line has BOM so it's ignored by compiletest for directives)\r
+//\r
+// compile-flags: --json=diagnostic-short --error-format=json\r
+// ignore-tidy-cr\r
+\r
+// For easier verifying, the byte offsets in this file should match those\r
+// in the json_bom_plus_crlf_multifile_aux.rs - given the actual fn is\r
+// identical (just with a different, but equally sized name), the easiest way\r
+// to do this is to ensure the two files are of equal size on disk.\r
+\r
+// N.B., this file needs CRLF line endings. The .gitattributes file in\r
+// this directory should enforce it.\r
+\r
+fn main() {\r
+\r
+    let s : String = 1;  // Error in the middle of line.\r
+\r
+    let s : String = 1\r
+    ;  // Error before the newline.\r
+\r
+    let s : String =\r
+1;  // Error after the newline.\r
+\r
+    let s : String = (\r
+    );  // Error spanning the newline.\r
+}\r
diff --git a/src/test/ui/json/json-bom-plus-crlf.stderr b/src/test/ui/json/json-bom-plus-crlf.stderr
new file mode 100644 (file)
index 0000000..df6bd72
--- /dev/null
@@ -0,0 +1,114 @@
+{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
+
+Erroneous code examples:
+
+```compile_fail,E0308
+fn plus_one(x: i32) -> i32 {
+    x + 1
+}
+
+plus_one(\"Not a number\");
+//       ^^^^^^^^^^^^^^ expected `i32`, found `&str`
+
+if \"Not a bool\" {
+// ^^^^^^^^^^^^ expected `bool`, found `&str`
+}
+
+let x: f32 = \"Not a float\";
+//     ---   ^^^^^^^^^^^^^ expected `f32`, found `&str`
+//     |
+//     expected due to this
+```
+
+This error occurs when an expression was used in a place where the compiler
+expected an expression of a different type. It can occur in several cases, the
+most common being when calling a function and passing an argument which has a
+different type than the matching type in the function declaration.
+"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":606,"byte_end":607,"line_start":16,"line_end":16,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1;  // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":597,"byte_end":603,"line_start":16,"line_end":16,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String = 1;  // Error in the middle of line.","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":607,"byte_end":607,"line_start":16,"line_end":16,"column_start":23,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1;  // Error in the middle of line.","highlight_start":23,"highlight_end":23}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:16:22: error[E0308]: mismatched types
+"}
+{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
+
+Erroneous code examples:
+
+```compile_fail,E0308
+fn plus_one(x: i32) -> i32 {
+    x + 1
+}
+
+plus_one(\"Not a number\");
+//       ^^^^^^^^^^^^^^ expected `i32`, found `&str`
+
+if \"Not a bool\" {
+// ^^^^^^^^^^^^ expected `bool`, found `&str`
+}
+
+let x: f32 = \"Not a float\";
+//     ---   ^^^^^^^^^^^^^ expected `f32`, found `&str`
+//     |
+//     expected due to this
+```
+
+This error occurs when an expression was used in a place where the compiler
+expected an expression of a different type. It can occur in several cases, the
+most common being when calling a function and passing an argument which has a
+different type than the matching type in the function declaration.
+"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":666,"byte_end":667,"line_start":18,"line_end":18,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":657,"byte_end":663,"line_start":18,"line_end":18,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String = 1","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":667,"byte_end":667,"line_start":18,"line_end":18,"column_start":23,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1","highlight_start":23,"highlight_end":23}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:18:22: error[E0308]: mismatched types
+"}
+{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
+
+Erroneous code examples:
+
+```compile_fail,E0308
+fn plus_one(x: i32) -> i32 {
+    x + 1
+}
+
+plus_one(\"Not a number\");
+//       ^^^^^^^^^^^^^^ expected `i32`, found `&str`
+
+if \"Not a bool\" {
+// ^^^^^^^^^^^^ expected `bool`, found `&str`
+}
+
+let x: f32 = \"Not a float\";
+//     ---   ^^^^^^^^^^^^^ expected `f32`, found `&str`
+//     |
+//     expected due to this
+```
+
+This error occurs when an expression was used in a place where the compiler
+expected an expression of a different type. It can occur in several cases, the
+most common being when calling a function and passing an argument which has a
+different type than the matching type in the function declaration.
+"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":730,"byte_end":731,"line_start":22,"line_end":22,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1;  // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":720,"byte_end":726,"line_start":21,"line_end":21,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String =","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":731,"byte_end":731,"line_start":22,"line_end":22,"column_start":2,"column_end":2,"is_primary":true,"text":[{"text":"1;  // Error after the newline.","highlight_start":2,"highlight_end":2}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:22:1: error[E0308]: mismatched types
+"}
+{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
+
+Erroneous code examples:
+
+```compile_fail,E0308
+fn plus_one(x: i32) -> i32 {
+    x + 1
+}
+
+plus_one(\"Not a number\");
+//       ^^^^^^^^^^^^^^ expected `i32`, found `&str`
+
+if \"Not a bool\" {
+// ^^^^^^^^^^^^ expected `bool`, found `&str`
+}
+
+let x: f32 = \"Not a float\";
+//     ---   ^^^^^^^^^^^^^ expected `f32`, found `&str`
+//     |
+//     expected due to this
+```
+
+This error occurs when an expression was used in a place where the compiler
+expected an expression of a different type. It can occur in several cases, the
+most common being when calling a function and passing an argument which has a
+different type than the matching type in the function declaration.
+"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":786,"byte_end":794,"line_start":24,"line_end":25,"column_start":22,"column_end":6,"is_primary":true,"text":[{"text":"    let s : String = (","highlight_start":22,"highlight_end":23},{"text":"    );  // Error spanning the newline.","highlight_start":1,"highlight_end":6}],"label":"expected struct `String`, found `()`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":777,"byte_end":783,"line_start":24,"line_end":24,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String = (","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-bom-plus-crlf.rs:24:22: error[E0308]: mismatched types
+"}
+{"message":"aborting due to 4 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to 4 previous errors
+"}
diff --git a/src/test/ui/json/json-invalid.rs b/src/test/ui/json/json-invalid.rs
new file mode 100644 (file)
index 0000000..54d0dd1
--- /dev/null
@@ -0,0 +1,3 @@
+// compile-flags: --json=foo --error-format=json
+
+fn main() {}
diff --git a/src/test/ui/json/json-invalid.stderr b/src/test/ui/json/json-invalid.stderr
new file mode 100644 (file)
index 0000000..18bc76a
--- /dev/null
@@ -0,0 +1,2 @@
+error: unknown `--json` option `foo`
+
diff --git a/src/test/ui/json/json-multiple.polonius.stderr b/src/test/ui/json/json-multiple.polonius.stderr
new file mode 100644 (file)
index 0000000..0e4d442
--- /dev/null
@@ -0,0 +1 @@
+{"artifact":"$TEST_BUILD_DIR/json-multiple.polonius/libjson_multiple.rlib","emit":"link"}
diff --git a/src/test/ui/json/json-multiple.rs b/src/test/ui/json/json-multiple.rs
new file mode 100644 (file)
index 0000000..fb12633
--- /dev/null
@@ -0,0 +1,5 @@
+// build-pass
+// ignore-pass (different metadata emitted in different modes)
+// compile-flags: --json=diagnostic-short --json artifacts --error-format=json
+
+#![crate_type = "lib"]
diff --git a/src/test/ui/json/json-multiple.stderr b/src/test/ui/json/json-multiple.stderr
new file mode 100644 (file)
index 0000000..55ccfd5
--- /dev/null
@@ -0,0 +1 @@
+{"artifact":"$TEST_BUILD_DIR/json/json-multiple/libjson_multiple.rlib","emit":"link"}
diff --git a/src/test/ui/json/json-options.polonius.stderr b/src/test/ui/json/json-options.polonius.stderr
new file mode 100644 (file)
index 0000000..e21f6f8
--- /dev/null
@@ -0,0 +1 @@
+{"artifact":"$TEST_BUILD_DIR/json-options.polonius/libjson_options.rlib","emit":"link"}
diff --git a/src/test/ui/json/json-options.rs b/src/test/ui/json/json-options.rs
new file mode 100644 (file)
index 0000000..8b6ba13
--- /dev/null
@@ -0,0 +1,5 @@
+// build-pass
+// ignore-pass (different metadata emitted in different modes)
+// compile-flags: --json=diagnostic-short,artifacts --error-format=json
+
+#![crate_type = "lib"]
diff --git a/src/test/ui/json/json-options.stderr b/src/test/ui/json/json-options.stderr
new file mode 100644 (file)
index 0000000..645a26f
--- /dev/null
@@ -0,0 +1 @@
+{"artifact":"$TEST_BUILD_DIR/json/json-options/libjson_options.rlib","emit":"link"}
diff --git a/src/test/ui/json/json-short.rs b/src/test/ui/json/json-short.rs
new file mode 100644 (file)
index 0000000..7414a55
--- /dev/null
@@ -0,0 +1 @@
+// compile-flags: --json=diagnostic-short --error-format=json
diff --git a/src/test/ui/json/json-short.stderr b/src/test/ui/json/json-short.stderr
new file mode 100644 (file)
index 0000000..3bd85b0
--- /dev/null
@@ -0,0 +1,19 @@
+{"message":"`main` function not found in crate `json_short`","code":{"code":"E0601","explanation":"No `main` function was found in a binary crate.
+
+To fix this error, add a `main` function:
+
+```
+fn main() {
+    // Your program will start here.
+    println!(\"Hello world!\");
+}
+```
+
+If you don't know the basics of Rust, you can look at the
+[Rust Book][rust-book] to get started.
+
+[rust-book]: https://doc.rust-lang.org/book/
+"},"level":"error","spans":[{"file_name":"$DIR/json-short.rs","byte_start":62,"byte_end":62,"line_start":1,"line_end":1,"column_start":63,"column_end":63,"is_primary":true,"text":[{"text":"// compile-flags: --json=diagnostic-short --error-format=json","highlight_start":63,"highlight_end":63}],"label":"consider adding a `main` function to `$DIR/json-short.rs`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-short.rs:1:63: error[E0601]: `main` function not found in crate `json_short`
+"}
+{"message":"aborting due to previous error","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to previous error
+"}
index 73b32066fadcd3addb3e6def2ed0b5c390b2b455..68bcc3c1aff0ea96c364085ed5d60e3c7fb6987b 100644 (file)
 use std::num::NonZeroU32 as N32;
 use std::sync::{Mutex, RwLock};
 
-struct Wrapper<T>(T);
+struct Wrapper<T>(#[allow(unused_tuple_struct_fields)] T);
 
 #[repr(transparent)]
-struct Transparent<T>(T);
+struct Transparent<T>(#[allow(unused_tuple_struct_fields)] T);
 
 struct NoNiche<T>(UnsafeCell<T>);
 
diff --git a/src/test/ui/let-else/issue-100103.rs b/src/test/ui/let-else/issue-100103.rs
new file mode 100644 (file)
index 0000000..e393dea
--- /dev/null
@@ -0,0 +1,15 @@
+// edition:2021
+// check-pass
+
+#![feature(try_blocks)]
+#![feature(let_else)]
+
+fn main() {
+    let _: Result<i32, i32> = try {
+        let Some(x) = Some(0) else {
+            Err(1)?
+        };
+
+        x
+    };
+}
diff --git a/src/test/ui/lifetimes/elided-lifetime-in-path-in-type-relative-expression.rs b/src/test/ui/lifetimes/elided-lifetime-in-path-in-type-relative-expression.rs
new file mode 100644 (file)
index 0000000..b9d2711
--- /dev/null
@@ -0,0 +1,17 @@
+// check-pass
+
+struct Sqlite {}
+
+trait HasArguments<'q> {
+    type Arguments;
+}
+
+impl<'q> HasArguments<'q> for Sqlite {
+    type Arguments = std::marker::PhantomData<&'q ()>;
+}
+
+fn foo() {
+    let _ = <Sqlite as HasArguments>::Arguments::default();
+}
+
+fn main() {}
diff --git a/src/test/ui/lifetimes/fullwidth-ampersand.rs b/src/test/ui/lifetimes/fullwidth-ampersand.rs
new file mode 100644 (file)
index 0000000..7d8948b
--- /dev/null
@@ -0,0 +1,7 @@
+// Verify that we do not ICE when the user uses a multubyte ampersand.
+
+fn f(_: &&()) -> &() { todo!() }
+//~^ ERROR unknown start of token: \u{ff06}
+//~| ERROR missing lifetime specifier [E0106]
+
+fn main() {}
diff --git a/src/test/ui/lifetimes/fullwidth-ampersand.stderr b/src/test/ui/lifetimes/fullwidth-ampersand.stderr
new file mode 100644 (file)
index 0000000..4645254
--- /dev/null
@@ -0,0 +1,26 @@
+error: unknown start of token: \u{ff06}
+  --> $DIR/fullwidth-ampersand.rs:3:10
+   |
+LL | fn f(_: &&()) -> &() { todo!() }
+   |          ^^
+   |
+help: Unicode character '&' (Fullwidth Ampersand) looks like '&' (Ampersand), but it is not
+   |
+LL | fn f(_: &&()) -> &() { todo!() }
+   |          ~
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/fullwidth-ampersand.rs:3:18
+   |
+LL | fn f(_: &&()) -> &() { todo!() }
+   |         -----     ^ expected named lifetime parameter
+   |
+   = help: this function's return type contains a borrowed value, but the signature does not say which one of argument 1's 2 lifetimes it is borrowed from
+help: consider introducing a named lifetime parameter
+   |
+LL | fn f<'a>(_: &'a &'a ()) -> &'a () { todo!() }
+   |     ++++     ++   ++         ++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0106`.
index ca13b9bd6ae7b54888448e893c807d605c843a1f..8d4cbe201846170474309da211fa78bddf51ae86 100644 (file)
@@ -6,18 +6,16 @@
 // normalize-stderr-test "thread.*panicked.*Metadata module not compiled.*\n" -> ""
 // normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> ""
 
-#![feature(box_syntax)]
-
 #[cfg(target_pointer_width = "64")]
 fn main() {
     let n = 0_usize;
-    let a: Box<_> = box [&n; 0xF000000000000000_usize];
+    let a: Box<_> = Box::new([&n; 0xF000000000000000_usize]);
     println!("{}", a[0xFFFFFF_usize]);
 }
 
 #[cfg(target_pointer_width = "32")]
 fn main() {
     let n = 0_usize;
-    let a: Box<_> = box [&n; 0xFFFFFFFF_usize];
+    let a: Box<_> = Box::new([&n; 0xFFFFFFFF_usize]);
     println!("{}", a[0xFFFFFF_usize]);
 }
index c8fd32c64d6db757c16ce36778c26bc56b41faec..b15d706368633e3e9cd9142f7462ad97c60228cf 100644 (file)
@@ -1,12 +1,37 @@
-// check-pass
+#![deny(unused_tuple_struct_fields)]
+//~^ NOTE: the lint level is defined here
 
-#![deny(dead_code)]
+use std::marker::PhantomData;
 
 const LEN: usize = 4;
 
-#[derive(Debug)]
-struct Wrapper([u8; LEN]);
+struct SingleUnused(i32, [u8; LEN], String);
+//~^ ERROR: field `1` is never read
+//~| NOTE: field in this struct
+//~| HELP: consider changing the field to be of unit type
+
+struct MultipleUnused(i32, f32, String, u8);
+//~^ ERROR: fields `0`, `1`, `2` and `3` are never read
+//~| NOTE: fields in this struct
+//~| HELP: consider changing the fields to be of unit type
+
+struct GoodUnit(());
+
+struct GoodPhantom(PhantomData<i32>);
+
+struct Void;
+struct GoodVoid(Void);
 
 fn main() {
-    println!("{:?}", Wrapper([0, 1, 2, 3]));
+    let w = SingleUnused(42, [0, 1, 2, 3], "abc".to_string());
+    let _ = w.0;
+    let _ = w.2;
+
+    let m = MultipleUnused(42, 3.14, "def".to_string(), 4u8);
+
+    let gu = GoodUnit(());
+    let gp = GoodPhantom(PhantomData);
+    let gv = GoodVoid(Void);
+
+    let _ = (gu, gp, gv, m);
 }
diff --git a/src/test/ui/lint/dead-code/tuple-struct-field.stderr b/src/test/ui/lint/dead-code/tuple-struct-field.stderr
new file mode 100644 (file)
index 0000000..ca0989f
--- /dev/null
@@ -0,0 +1,33 @@
+error: field `1` is never read
+  --> $DIR/tuple-struct-field.rs:8:26
+   |
+LL | struct SingleUnused(i32, [u8; LEN], String);
+   |        ------------      ^^^^^^^^^
+   |        |
+   |        field in this struct
+   |
+note: the lint level is defined here
+  --> $DIR/tuple-struct-field.rs:1:9
+   |
+LL | #![deny(unused_tuple_struct_fields)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider changing the field to be of unit type to suppress this warning while preserving the field numbering, or remove the field
+   |
+LL | struct SingleUnused(i32, (), String);
+   |                          ~~
+
+error: fields `0`, `1`, `2` and `3` are never read
+  --> $DIR/tuple-struct-field.rs:13:23
+   |
+LL | struct MultipleUnused(i32, f32, String, u8);
+   |        -------------- ^^^  ^^^  ^^^^^^  ^^
+   |        |
+   |        fields in this struct
+   |
+help: consider changing the fields to be of unit type to suppress this warning while preserving the field numbering, or remove the fields
+   |
+LL | struct MultipleUnused((), (), (), ());
+   |                       ~~  ~~  ~~  ~~
+
+error: aborting due to 2 previous errors
+
index 84829c98e573908cdddc1a50890d25680ceca2b3..812fcdd09b6cf9635eb7faa3d782a7d29cff25cd 100644 (file)
@@ -2,7 +2,7 @@
 
 #![deny(dead_code)]
 
-pub struct GenericFoo<T>(T);
+pub struct GenericFoo<T>(#[allow(unused_tuple_struct_fields)] T);
 
 type Foo = GenericFoo<u32>;
 
diff --git a/src/test/ui/lint/issue-99387.rs b/src/test/ui/lint/issue-99387.rs
new file mode 100644 (file)
index 0000000..616eb93
--- /dev/null
@@ -0,0 +1,24 @@
+// check-pass
+
+#![feature(type_alias_impl_trait)]
+#![allow(private_in_public)]
+
+pub type Successors<'a> = impl Iterator<Item = &'a ()>;
+
+pub fn f<'a>() -> Successors<'a> {
+    None.into_iter()
+}
+
+trait Tr {
+    type Item;
+}
+
+impl<'a> Tr for &'a () {
+    type Item = Successors<'a>;
+}
+
+pub fn ohno<'a>() -> <&'a () as Tr>::Item {
+    None.into_iter()
+}
+
+fn main() {}
index d06b06b504f0652e2286c002f11dae966cf6281c..e547f031a9cfdf9886a0d7ad7e384edd102e1c54 100644 (file)
@@ -47,4 +47,57 @@ fn main() {
         let _ = &packed2.y; // ok, has align 2 in packed(2) struct
         let _ = &packed2.z; // ok, has align 1
     }
+
+    unsafe {
+        struct U16(u16);
+
+        impl Drop for U16 {
+            fn drop(&mut self) {
+                println!("{:p}", self);
+            }
+        }
+
+        struct HasDrop;
+
+        impl Drop for HasDrop {
+            fn drop(&mut self) {}
+        }
+
+        #[allow(unused)]
+        struct Wrapper {
+            a: U16,
+            b: HasDrop,
+        }
+        #[allow(unused)]
+        #[repr(packed(2))]
+        struct Wrapper2 {
+            a: U16,
+            b: HasDrop,
+        }
+
+        // An outer struct with more restrictive packing than the inner struct -- make sure we
+        // notice that!
+        #[repr(packed)]
+        struct Misalign<T>(u8, T);
+
+        let m1 = Misalign(
+            0,
+            Wrapper {
+                a: U16(10),
+                b: HasDrop,
+            },
+        );
+        let _ref = &m1.1.a; //~ ERROR reference to packed field
+        //~^ previously accepted
+
+        let m2 = Misalign(
+            0,
+            Wrapper2 {
+                a: U16(10),
+                b: HasDrop,
+            },
+        );
+        let _ref = &m2.1.a; //~ ERROR reference to packed field
+        //~^ previously accepted
+    }
 }
index ed5dd2ec0118160fc835573aa46af434791e118f..97dbec2861cd2ababaae65e09ab1678148e12e13 100644 (file)
@@ -80,7 +80,29 @@ LL |         let _ = &packed2.x;
    = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
-error: aborting due to 7 previous errors
+error: reference to packed field is unaligned
+  --> $DIR/unaligned_references.rs:90:20
+   |
+LL |         let _ref = &m1.1.a;
+   |                    ^^^^^^^
+   |
+   = 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 #82523 <https://github.com/rust-lang/rust/issues/82523>
+   = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
+
+error: reference to packed field is unaligned
+  --> $DIR/unaligned_references.rs:100:20
+   |
+LL |         let _ref = &m2.1.a;
+   |                    ^^^^^^^
+   |
+   = 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 #82523 <https://github.com/rust-lang/rust/issues/82523>
+   = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
+
+error: aborting due to 9 previous errors
 
 Future incompatibility report: Future breakage diagnostic:
 error: reference to packed field is unaligned
@@ -201,3 +223,37 @@ LL | #![deny(unaligned_references)]
    = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
+Future breakage diagnostic:
+error: reference to packed field is unaligned
+  --> $DIR/unaligned_references.rs:90:20
+   |
+LL |         let _ref = &m1.1.a;
+   |                    ^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/unaligned_references.rs:1:9
+   |
+LL | #![deny(unaligned_references)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+   = 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 #82523 <https://github.com/rust-lang/rust/issues/82523>
+   = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
+
+Future breakage diagnostic:
+error: reference to packed field is unaligned
+  --> $DIR/unaligned_references.rs:100:20
+   |
+LL |         let _ref = &m2.1.a;
+   |                    ^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/unaligned_references.rs:1:9
+   |
+LL | #![deny(unaligned_references)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+   = 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 #82523 <https://github.com/rust-lang/rust/issues/82523>
+   = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
+
index ce22eca1b8ce61e89eb795e6d9d17a7717bc22f1..e021f500c66ae4f308ae2d661f1fc40bb2661145 100644 (file)
@@ -1,8 +1,8 @@
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub.rs:8:5
+  --> $DIR/unreachable_pub.rs:8:13
    |
 LL |     pub use std::fmt;
-   |     ---^^^^^^^^^^^^^^
+   |     ---     ^^^^^^^^
    |     |
    |     help: consider restricting its visibility: `pub(crate)`
    |
@@ -93,7 +93,7 @@ warning: unreachable `pub` item
   --> $DIR/unreachable_pub.rs:33:5
    |
 LL |     pub const CARBON: usize = 1;
-   |     ---^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ---^^^^^^^^^^^^^^^^^^^^
    |     |
    |     help: consider restricting its visibility: `pub(crate)`
    |
@@ -103,7 +103,7 @@ warning: unreachable `pub` item
   --> $DIR/unreachable_pub.rs:34:5
    |
 LL |     pub static NITROGEN: usize = 2;
-   |     ---^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ---^^^^^^^^^^^^^^^^^^^^^^^
    |     |
    |     help: consider restricting its visibility: `pub(crate)`
    |
@@ -113,7 +113,7 @@ warning: unreachable `pub` item
   --> $DIR/unreachable_pub.rs:35:5
    |
 LL |     pub type Oxygen = bool;
-   |     ---^^^^^^^^^^^^^^^^^^^^
+   |     ---^^^^^^^^^^^^
    |     |
    |     help: consider restricting its visibility: `pub(crate)`
    |
@@ -123,7 +123,7 @@ warning: unreachable `pub` item
   --> $DIR/unreachable_pub.rs:38:47
    |
 LL |         ($visibility: vis, $name: ident) => { $visibility struct $name {} }
-   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 ...
 LL |     define_empty_struct_with_visibility!(pub, Fluorine);
    |     ---------------------------------------------------
@@ -138,7 +138,7 @@ warning: unreachable `pub` item
   --> $DIR/unreachable_pub.rs:44:9
    |
 LL |         pub fn catalyze() -> bool;
-   |         ---^^^^^^^^^^^^^^^^^^^^^^^
+   |         ---^^^^^^^^^^^^^^^^^^^^^^
    |         |
    |         help: consider restricting its visibility: `pub(crate)`
    |
diff --git a/src/test/ui/lint/unused/issue-92751.rs b/src/test/ui/lint/unused/issue-92751.rs
new file mode 100644 (file)
index 0000000..2fb2927
--- /dev/null
@@ -0,0 +1,9 @@
+#[deny(unused)]
+pub fn broken(x: Option<()>) -> i32 {
+    match x {
+        Some(()) => (1), //~ ERROR unnecessary parentheses around match arm expression
+        None => (2), //~ ERROR unnecessary parentheses around match arm expression
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/lint/unused/issue-92751.stderr b/src/test/ui/lint/unused/issue-92751.stderr
new file mode 100644 (file)
index 0000000..0a8d8e6
--- /dev/null
@@ -0,0 +1,32 @@
+error: unnecessary parentheses around match arm expression
+  --> $DIR/issue-92751.rs:4:21
+   |
+LL |         Some(()) => (1),
+   |                     ^ ^
+   |
+note: the lint level is defined here
+  --> $DIR/issue-92751.rs:1:8
+   |
+LL | #[deny(unused)]
+   |        ^^^^^^
+   = note: `#[deny(unused_parens)]` implied by `#[deny(unused)]`
+help: remove these parentheses
+   |
+LL -         Some(()) => (1),
+LL +         Some(()) => 1,
+   |
+
+error: unnecessary parentheses around match arm expression
+  --> $DIR/issue-92751.rs:5:17
+   |
+LL |         None => (2),
+   |                 ^ ^
+   |
+help: remove these parentheses
+   |
+LL -         None => (2),
+LL +         None => 2,
+   |
+
+error: aborting due to 2 previous errors
+
index 27269580e52e2bd479cdf33c0d267eb60b165a64..317d81c591d55cd5cdb0cec79b306eb14ae84376 100644 (file)
@@ -45,7 +45,7 @@ error: `#[must_use]` has no effect when applied to a static item
 LL | #[must_use]
    | ^^^^^^^^^^^
 
-error: `#[must_use]` has no effect when applied to an item
+error: `#[must_use]` has no effect when applied to an implementation block
   --> $DIR/unused_attributes-must_use.rs:33:1
    |
 LL | #[must_use]
@@ -69,7 +69,7 @@ error: `#[must_use]` has no effect when applied to a type parameter
 LL | fn qux<#[must_use] T>(_: T) {}
    |        ^^^^^^^^^^^
 
-error: `#[must_use]` has no effect when applied to an item
+error: `#[must_use]` has no effect when applied to an implementation block
   --> $DIR/unused_attributes-must_use.rs:79:1
    |
 LL | #[must_use]
diff --git a/src/test/ui/lint/unused_parens_multibyte_recovery.rs b/src/test/ui/lint/unused_parens_multibyte_recovery.rs
new file mode 100644 (file)
index 0000000..8fcfae2
--- /dev/null
@@ -0,0 +1,11 @@
+// ignore-tidy-trailing-newlines
+//
+// error-pattern: this file contains an unclosed delimiter
+// error-pattern: this file contains an unclosed delimiter
+// error-pattern: this file contains an unclosed delimiter
+// error-pattern: format argument must be a string literal
+//
+// Verify that unused parens lint does not try to create a span
+// which points in the middle of a multibyte character.
+
+fn f(){(print!(á
\ No newline at end of file
diff --git a/src/test/ui/lint/unused_parens_multibyte_recovery.stderr b/src/test/ui/lint/unused_parens_multibyte_recovery.stderr
new file mode 100644 (file)
index 0000000..a0302b1
--- /dev/null
@@ -0,0 +1,43 @@
+error: this file contains an unclosed delimiter
+  --> $DIR/unused_parens_multibyte_recovery.rs:11:17
+   |
+LL | fn f(){(print!(á
+   |       --      - ^
+   |       ||      |
+   |       ||      unclosed delimiter
+   |       |unclosed delimiter
+   |       unclosed delimiter
+
+error: this file contains an unclosed delimiter
+  --> $DIR/unused_parens_multibyte_recovery.rs:11:17
+   |
+LL | fn f(){(print!(á
+   |       --      - ^
+   |       ||      |
+   |       ||      unclosed delimiter
+   |       |unclosed delimiter
+   |       unclosed delimiter
+
+error: this file contains an unclosed delimiter
+  --> $DIR/unused_parens_multibyte_recovery.rs:11:17
+   |
+LL | fn f(){(print!(á
+   |       --      - ^
+   |       ||      |
+   |       ||      unclosed delimiter
+   |       |unclosed delimiter
+   |       unclosed delimiter
+
+error: format argument must be a string literal
+  --> $DIR/unused_parens_multibyte_recovery.rs:11:16
+   |
+LL | fn f(){(print!(á
+   |                ^
+   |
+help: you might be missing a string literal to format with
+   |
+LL | fn f(){(print!("{}", á
+   |                +++++
+
+error: aborting due to 4 previous errors
+
index cb83d4103dcedd375bd7d3ab2e38f7775d67a9b5..ffe9f93860a31255d79b790185f1d7b9f3767d5f 100644 (file)
@@ -3,7 +3,7 @@
 #![allow(non_camel_case_types)]
 // pretty-expanded FIXME #23616
 
-enum list { cons(isize, Box<list>), nil, }
+enum list { #[allow(unused_tuple_struct_fields)] cons(isize, Box<list>), nil, }
 
 pub fn main() {
     list::cons(10, Box::new(list::cons(11, Box::new(list::cons(12, Box::new(list::nil))))));
diff --git a/src/test/ui/lowering/issue-96847.rs b/src/test/ui/lowering/issue-96847.rs
new file mode 100644 (file)
index 0000000..2aa34c8
--- /dev/null
@@ -0,0 +1,14 @@
+// run-pass
+
+// Test that this doesn't abort during AST lowering. In #96847 it did abort
+// because the attribute was being lowered twice.
+
+#![feature(stmt_expr_attributes)]
+#![feature(lang_items)]
+
+fn main() {
+    for _ in [1,2,3] {
+        #![lang="foo"]
+        println!("foo");
+    }
+}
diff --git a/src/test/ui/macros/auxiliary/issue-100199.rs b/src/test/ui/macros/auxiliary/issue-100199.rs
new file mode 100644 (file)
index 0000000..9e190b5
--- /dev/null
@@ -0,0 +1,18 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+#![feature(proc_macro_quote)]
+
+extern crate proc_macro;
+
+use proc_macro::{quote, Ident, Span, TokenStream, TokenTree};
+
+#[proc_macro_attribute]
+pub fn struct_with_bound(_: TokenStream, _: TokenStream) -> TokenStream {
+    let crate_ident = TokenTree::Ident(Ident::new("crate", Span::call_site()));
+    let trait_ident = TokenTree::Ident(Ident::new("MyTrait", Span::call_site()));
+    quote!(
+        struct Foo<T: $crate_ident::$trait_ident> {}
+    )
+}
index ae45e97c8b07070aac07e01fa68c54800ccfe289..26f00fed9c45a41f58dcfa3a5a522ef5e17f78a1 100644 (file)
@@ -88,6 +88,7 @@ pub fn main() {
     );
 }
 
+#[allow(unused_tuple_struct_fields)]
 enum HTMLFragment {
     tag(String, Vec<HTMLFragment> ),
     text(String),
diff --git a/src/test/ui/macros/issue-100199.rs b/src/test/ui/macros/issue-100199.rs
new file mode 100644 (file)
index 0000000..6e50afa
--- /dev/null
@@ -0,0 +1,16 @@
+#[issue_100199::struct_with_bound] //~ ERROR cannot find trait `MyTrait` in the crate root
+struct Foo {}
+// The above must be on the first line so that it's span points to pos 0.
+// This used to trigger an ICE because the diagnostic emitter would get
+// an unexpected dummy span (lo == 0 == hi) while attempting to print a
+// suggestion.
+
+// aux-build: issue-100199.rs
+
+extern crate issue_100199;
+
+mod traits {
+    pub trait MyTrait {}
+}
+
+fn main() {}
diff --git a/src/test/ui/macros/issue-100199.stderr b/src/test/ui/macros/issue-100199.stderr
new file mode 100644 (file)
index 0000000..2cb45dc
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0405]: cannot find trait `MyTrait` in the crate root
+  --> $DIR/issue-100199.rs:1:1
+   |
+LL | #[issue_100199::struct_with_bound]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in the crate root
+   |
+   = note: this error originates in the attribute macro `issue_100199::struct_with_bound` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider importing this trait
+   |
+LL | use traits::MyTrait;
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0405`.
index 4a39dd1440b1f212aff5098246a2ed4092aeac88..c93451c761ae4f3619c0f8b75790b1c2e4da88a4 100644 (file)
@@ -2,9 +2,9 @@ warning: named argument `_x` is not used by name
   --> $DIR/issue-98466.rs:7:26
    |
 LL |     println!("_x is {}", _x = 5);
-   |                      -   ^^ this named argument is only referred to by position in formatting string
-   |                      |
-   |                      this formatting argument uses named argument `_x` by position
+   |                     --   ^^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `_x` by position
    |
    = note: `#[warn(named_arguments_used_positionally)]` on by default
 help: use the named argument by name to avoid ambiguity
@@ -16,9 +16,9 @@ warning: named argument `y` is not used by name
   --> $DIR/issue-98466.rs:10:26
    |
 LL |     println!("_x is {}", y = _x);
-   |                      -   ^ this named argument is only referred to by position in formatting string
-   |                      |
-   |                      this formatting argument uses named argument `y` by position
+   |                     --   ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `y` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -29,9 +29,9 @@ warning: named argument `y` is not used by name
   --> $DIR/issue-98466.rs:13:83
    |
 LL |     println!("first positional arg {}, second positional arg {}, _x is {}", 1, 2, y = _x);
-   |                                                                         -         ^ this named argument is only referred to by position in formatting string
-   |                                                                         |
-   |                                                                         this formatting argument uses named argument `y` by position
+   |                                                                        --         ^ this named argument is referred to by position in formatting string
+   |                                                                        |
+   |                                                                        this formatting argument uses named argument `y` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -42,9 +42,9 @@ warning: named argument `_x` is not used by name
   --> $DIR/issue-98466.rs:19:34
    |
 LL |     let _f = format!("_x is {}", _x = 5);
-   |                              -   ^^ this named argument is only referred to by position in formatting string
-   |                              |
-   |                              this formatting argument uses named argument `_x` by position
+   |                             --   ^^ this named argument is referred to by position in formatting string
+   |                             |
+   |                             this formatting argument uses named argument `_x` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -55,9 +55,9 @@ warning: named argument `y` is not used by name
   --> $DIR/issue-98466.rs:22:34
    |
 LL |     let _f = format!("_x is {}", y = _x);
-   |                              -   ^ this named argument is only referred to by position in formatting string
-   |                              |
-   |                              this formatting argument uses named argument `y` by position
+   |                             --   ^ this named argument is referred to by position in formatting string
+   |                             |
+   |                             this formatting argument uses named argument `y` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -68,9 +68,9 @@ warning: named argument `y` is not used by name
   --> $DIR/issue-98466.rs:25:91
    |
 LL |     let _f = format!("first positional arg {}, second positional arg {}, _x is {}", 1, 2, y = _x);
-   |                                                                                 -         ^ this named argument is only referred to by position in formatting string
-   |                                                                                 |
-   |                                                                                 this formatting argument uses named argument `y` by position
+   |                                                                                --         ^ this named argument is referred to by position in formatting string
+   |                                                                                |
+   |                                                                                this formatting argument uses named argument `y` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
index 0798ad8dc517c18533dcde650234ba176c3e555b..2bfeedd7d07370312c8e0fc1fa6bf1063d61283b 100644 (file)
@@ -2,9 +2,9 @@ warning: named argument `a` is not used by name
   --> $DIR/issue-99265.rs:5:24
    |
 LL |     println!("{b} {}", a=1, b=2);
-   |                    -   ^ this named argument is only referred to by position in formatting string
-   |                    |
-   |                    this formatting argument uses named argument `a` by position
+   |                   --   ^ this named argument is referred to by position in formatting string
+   |                   |
+   |                   this formatting argument uses named argument `a` by position
    |
    = note: `#[warn(named_arguments_used_positionally)]` on by default
 help: use the named argument by name to avoid ambiguity
@@ -16,9 +16,9 @@ warning: named argument `a` is not used by name
   --> $DIR/issue-99265.rs:9:35
    |
 LL |     println!("{} {} {} {} {}", 0, a=1, b=2, c=3, d=4);
-   |                   -               ^ this named argument is only referred to by position in formatting string
-   |                   |
-   |                   this formatting argument uses named argument `a` by position
+   |                  --               ^ this named argument is referred to by position in formatting string
+   |                  |
+   |                  this formatting argument uses named argument `a` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -29,9 +29,9 @@ warning: named argument `b` is not used by name
   --> $DIR/issue-99265.rs:9:40
    |
 LL |     println!("{} {} {} {} {}", 0, a=1, b=2, c=3, d=4);
-   |                      -                 ^ this named argument is only referred to by position in formatting string
-   |                      |
-   |                      this formatting argument uses named argument `b` by position
+   |                     --                 ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `b` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -42,9 +42,9 @@ warning: named argument `c` is not used by name
   --> $DIR/issue-99265.rs:9:45
    |
 LL |     println!("{} {} {} {} {}", 0, a=1, b=2, c=3, d=4);
-   |                         -                   ^ this named argument is only referred to by position in formatting string
-   |                         |
-   |                         this formatting argument uses named argument `c` by position
+   |                        --                   ^ this named argument is referred to by position in formatting string
+   |                        |
+   |                        this formatting argument uses named argument `c` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -55,9 +55,9 @@ warning: named argument `d` is not used by name
   --> $DIR/issue-99265.rs:9:50
    |
 LL |     println!("{} {} {} {} {}", 0, a=1, b=2, c=3, d=4);
-   |                            -                     ^ this named argument is only referred to by position in formatting string
-   |                            |
-   |                            this formatting argument uses named argument `d` by position
+   |                           --                     ^ this named argument is referred to by position in formatting string
+   |                           |
+   |                           this formatting argument uses named argument `d` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -68,9 +68,9 @@ warning: named argument `width` is not used by name
   --> $DIR/issue-99265.rs:19:35
    |
 LL |     println!("Hello {:1$}!", "x", width = 5);
-   |                       --          ^^^^^ this named argument is only referred to by position in formatting string
+   |                       --          ^^^^^ this named argument is referred to by position in formatting string
    |                       |
-   |                       this formatting argument uses named argument `width$` by position
+   |                       this formatting argument uses named argument `width` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -81,9 +81,9 @@ warning: named argument `width` is not used by name
   --> $DIR/issue-99265.rs:23:46
    |
 LL |     println!("Hello {:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
-   |                       --                     ^^^^^ this named argument is only referred to by position in formatting string
+   |                       --                     ^^^^^ this named argument is referred to by position in formatting string
    |                       |
-   |                       this formatting argument uses named argument `width$` by position
+   |                       this formatting argument uses named argument `width` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -94,9 +94,9 @@ warning: named argument `precision` is not used by name
   --> $DIR/issue-99265.rs:23:57
    |
 LL |     println!("Hello {:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
-   |                          --                             ^^^^^^^^^ this named argument is only referred to by position in formatting string
+   |                          --                             ^^^^^^^^^ this named argument is referred to by position in formatting string
    |                          |
-   |                          this formatting argument uses named argument `precision$` by position
+   |                          this formatting argument uses named argument `precision` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -107,9 +107,9 @@ warning: named argument `f` is not used by name
   --> $DIR/issue-99265.rs:23:33
    |
 LL |     println!("Hello {:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
-   |                      -          ^ this named argument is only referred to by position in formatting string
-   |                      |
-   |                      this formatting argument uses named argument `f` by position
+   |                     --          ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `f` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -120,9 +120,9 @@ warning: named argument `width` is not used by name
   --> $DIR/issue-99265.rs:31:47
    |
 LL |     println!("Hello {0:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
-   |                        --                     ^^^^^ this named argument is only referred to by position in formatting string
+   |                        --                     ^^^^^ this named argument is referred to by position in formatting string
    |                        |
-   |                        this formatting argument uses named argument `width$` by position
+   |                        this formatting argument uses named argument `width` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -133,9 +133,9 @@ warning: named argument `precision` is not used by name
   --> $DIR/issue-99265.rs:31:58
    |
 LL |     println!("Hello {0:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
-   |                           --                             ^^^^^^^^^ this named argument is only referred to by position in formatting string
+   |                           --                             ^^^^^^^^^ this named argument is referred to by position in formatting string
    |                           |
-   |                           this formatting argument uses named argument `precision$` by position
+   |                           this formatting argument uses named argument `precision` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -146,7 +146,7 @@ warning: named argument `f` is not used by name
   --> $DIR/issue-99265.rs:31:34
    |
 LL |     println!("Hello {0:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
-   |                      -           ^ this named argument is only referred to by position in formatting string
+   |                      -           ^ this named argument is referred to by position in formatting string
    |                      |
    |                      this formatting argument uses named argument `f` by position
    |
@@ -159,10 +159,10 @@ warning: named argument `width` is not used by name
   --> $DIR/issue-99265.rs:52:9
    |
 LL |         "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
-   |                       -- this formatting argument uses named argument `width$` by position
+   |                       -- this formatting argument uses named argument `width` by position
 ...
 LL |         width = 5,
-   |         ^^^^^ this named argument is only referred to by position in formatting string
+   |         ^^^^^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -173,10 +173,10 @@ warning: named argument `precision` is not used by name
   --> $DIR/issue-99265.rs:54:9
    |
 LL |         "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
-   |                          -- this formatting argument uses named argument `precision$` by position
+   |                          -- this formatting argument uses named argument `precision` by position
 ...
 LL |         precision = 2,
-   |         ^^^^^^^^^ this named argument is only referred to by position in formatting string
+   |         ^^^^^^^^^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -190,7 +190,7 @@ LL |         "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
    |                     - this formatting argument uses named argument `f` by position
 ...
 LL |         f = 0.02f32,
-   |         ^ this named argument is only referred to by position in formatting string
+   |         ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -201,10 +201,10 @@ warning: named argument `width2` is not used by name
   --> $DIR/issue-99265.rs:58:9
    |
 LL |         "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
-   |                                 -- this formatting argument uses named argument `width2$` by position
+   |                                 -- this formatting argument uses named argument `width2` by position
 ...
 LL |         width2 = 5,
-   |         ^^^^^^ this named argument is only referred to by position in formatting string
+   |         ^^^^^^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -215,10 +215,10 @@ warning: named argument `precision2` is not used by name
   --> $DIR/issue-99265.rs:60:9
    |
 LL |         "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
-   |                                    -- this formatting argument uses named argument `precision2$` by position
+   |                                    -- this formatting argument uses named argument `precision2` by position
 ...
 LL |         precision2 = 2
-   |         ^^^^^^^^^^ this named argument is only referred to by position in formatting string
+   |         ^^^^^^^^^^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -232,7 +232,7 @@ LL |         "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
    |                               - this formatting argument uses named argument `g` by position
 ...
 LL |         g = 0.02f32,
-   |         ^ this named argument is only referred to by position in formatting string
+   |         ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -246,7 +246,7 @@ LL |         "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
    |                                          - this formatting argument uses named argument `f` by position
 ...
 LL |         f = 0.02f32,
-   |         ^ this named argument is only referred to by position in formatting string
+   |         ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -257,9 +257,9 @@ warning: named argument `f` is not used by name
   --> $DIR/issue-99265.rs:64:31
    |
 LL |     println!("Hello {:0.1}!", f = 0.02f32);
-   |                      -        ^ this named argument is only referred to by position in formatting string
-   |                      |
-   |                      this formatting argument uses named argument `f` by position
+   |                     --        ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `f` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -270,7 +270,7 @@ warning: named argument `f` is not used by name
   --> $DIR/issue-99265.rs:68:32
    |
 LL |     println!("Hello {0:0.1}!", f = 0.02f32);
-   |                      -         ^ this named argument is only referred to by position in formatting string
+   |                      -         ^ this named argument is referred to by position in formatting string
    |                      |
    |                      this formatting argument uses named argument `f` by position
    |
@@ -283,9 +283,9 @@ warning: named argument `v` is not used by name
   --> $DIR/issue-99265.rs:79:23
    |
 LL |     println!("{:0$}", v = val);
-   |                 --    ^ this named argument is only referred to by position in formatting string
+   |                 --    ^ this named argument is referred to by position in formatting string
    |                 |
-   |                 this formatting argument uses named argument `v$` by position
+   |                 this formatting argument uses named argument `v` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -296,9 +296,9 @@ warning: named argument `v` is not used by name
   --> $DIR/issue-99265.rs:79:23
    |
 LL |     println!("{:0$}", v = val);
-   |                -      ^ this named argument is only referred to by position in formatting string
-   |                |
-   |                this formatting argument uses named argument `v` by position
+   |               --      ^ this named argument is referred to by position in formatting string
+   |               |
+   |               this formatting argument uses named argument `v` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -309,9 +309,9 @@ warning: named argument `v` is not used by name
   --> $DIR/issue-99265.rs:84:24
    |
 LL |     println!("{0:0$}", v = val);
-   |                  --    ^ this named argument is only referred to by position in formatting string
+   |                  --    ^ this named argument is referred to by position in formatting string
    |                  |
-   |                  this formatting argument uses named argument `v$` by position
+   |                  this formatting argument uses named argument `v` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -322,7 +322,7 @@ warning: named argument `v` is not used by name
   --> $DIR/issue-99265.rs:84:24
    |
 LL |     println!("{0:0$}", v = val);
-   |                -       ^ this named argument is only referred to by position in formatting string
+   |                -       ^ this named argument is referred to by position in formatting string
    |                |
    |                this formatting argument uses named argument `v` by position
    |
@@ -335,9 +335,9 @@ warning: named argument `v` is not used by name
   --> $DIR/issue-99265.rs:89:26
    |
 LL |     println!("{:0$.0$}", v = val);
-   |                 --       ^ this named argument is only referred to by position in formatting string
+   |                 --       ^ this named argument is referred to by position in formatting string
    |                 |
-   |                 this formatting argument uses named argument `v$` by position
+   |                 this formatting argument uses named argument `v` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -348,9 +348,9 @@ warning: named argument `v` is not used by name
   --> $DIR/issue-99265.rs:89:26
    |
 LL |     println!("{:0$.0$}", v = val);
-   |                    --    ^ this named argument is only referred to by position in formatting string
+   |                    --    ^ this named argument is referred to by position in formatting string
    |                    |
-   |                    this formatting argument uses named argument `v$` by position
+   |                    this formatting argument uses named argument `v` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -361,9 +361,9 @@ warning: named argument `v` is not used by name
   --> $DIR/issue-99265.rs:89:26
    |
 LL |     println!("{:0$.0$}", v = val);
-   |                -         ^ this named argument is only referred to by position in formatting string
-   |                |
-   |                this formatting argument uses named argument `v` by position
+   |               --         ^ this named argument is referred to by position in formatting string
+   |               |
+   |               this formatting argument uses named argument `v` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -374,9 +374,9 @@ warning: named argument `v` is not used by name
   --> $DIR/issue-99265.rs:96:27
    |
 LL |     println!("{0:0$.0$}", v = val);
-   |                  --       ^ this named argument is only referred to by position in formatting string
+   |                  --       ^ this named argument is referred to by position in formatting string
    |                  |
-   |                  this formatting argument uses named argument `v$` by position
+   |                  this formatting argument uses named argument `v` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -387,9 +387,9 @@ warning: named argument `v` is not used by name
   --> $DIR/issue-99265.rs:96:27
    |
 LL |     println!("{0:0$.0$}", v = val);
-   |                     --    ^ this named argument is only referred to by position in formatting string
+   |                     --    ^ this named argument is referred to by position in formatting string
    |                     |
-   |                     this formatting argument uses named argument `v$` by position
+   |                     this formatting argument uses named argument `v` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -400,7 +400,7 @@ warning: named argument `v` is not used by name
   --> $DIR/issue-99265.rs:96:27
    |
 LL |     println!("{0:0$.0$}", v = val);
-   |                -          ^ this named argument is only referred to by position in formatting string
+   |                -          ^ this named argument is referred to by position in formatting string
    |                |
    |                this formatting argument uses named argument `v` by position
    |
@@ -413,9 +413,9 @@ warning: named argument `a` is not used by name
   --> $DIR/issue-99265.rs:104:28
    |
 LL |     println!("{} {a} {0}", a = 1);
-   |                -           ^ this named argument is only referred to by position in formatting string
-   |                |
-   |                this formatting argument uses named argument `a` by position
+   |               --           ^ this named argument is referred to by position in formatting string
+   |               |
+   |               this formatting argument uses named argument `a` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -426,7 +426,7 @@ warning: named argument `a` is not used by name
   --> $DIR/issue-99265.rs:104:28
    |
 LL |     println!("{} {a} {0}", a = 1);
-   |                       -    ^ this named argument is only referred to by position in formatting string
+   |                       -    ^ this named argument is referred to by position in formatting string
    |                       |
    |                       this formatting argument uses named argument `a` by position
    |
@@ -439,10 +439,10 @@ warning: named argument `b` is not used by name
   --> $DIR/issue-99265.rs:115:23
    |
 LL |                 {:1$.2$}",
-   |                   -- this formatting argument uses named argument `b$` by position
+   |                   -- this formatting argument uses named argument `b` by position
 ...
 LL |              a = 1.0, b = 1, c = 2,
-   |                       ^ this named argument is only referred to by position in formatting string
+   |                       ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -453,10 +453,10 @@ warning: named argument `c` is not used by name
   --> $DIR/issue-99265.rs:115:30
    |
 LL |                 {:1$.2$}",
-   |                      -- this formatting argument uses named argument `c$` by position
+   |                      -- this formatting argument uses named argument `c` by position
 ...
 LL |              a = 1.0, b = 1, c = 2,
-   |                              ^ this named argument is only referred to by position in formatting string
+   |                              ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -467,10 +467,10 @@ warning: named argument `a` is not used by name
   --> $DIR/issue-99265.rs:115:14
    |
 LL |                 {:1$.2$}",
-   |                  - this formatting argument uses named argument `a` by position
+   |                 -- this formatting argument uses named argument `a` by position
 ...
 LL |              a = 1.0, b = 1, c = 2,
-   |              ^ this named argument is only referred to by position in formatting string
+   |              ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -481,10 +481,10 @@ warning: named argument `b` is not used by name
   --> $DIR/issue-99265.rs:126:23
    |
 LL |                 {0:1$.2$}",
-   |                    -- this formatting argument uses named argument `b$` by position
+   |                    -- this formatting argument uses named argument `b` by position
 ...
 LL |              a = 1.0, b = 1, c = 2,
-   |                       ^ this named argument is only referred to by position in formatting string
+   |                       ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -495,10 +495,10 @@ warning: named argument `c` is not used by name
   --> $DIR/issue-99265.rs:126:30
    |
 LL |                 {0:1$.2$}",
-   |                       -- this formatting argument uses named argument `c$` by position
+   |                       -- this formatting argument uses named argument `c` by position
 ...
 LL |              a = 1.0, b = 1, c = 2,
-   |                              ^ this named argument is only referred to by position in formatting string
+   |                              ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -512,7 +512,7 @@ LL |                 {0:1$.2$}",
    |                  - this formatting argument uses named argument `a` by position
 ...
 LL |              a = 1.0, b = 1, c = 2,
-   |              ^ this named argument is only referred to by position in formatting string
+   |              ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -523,9 +523,9 @@ warning: named argument `width` is not used by name
   --> $DIR/issue-99265.rs:132:39
    |
 LL |     println!("{{{:1$.2$}}}", x = 1.0, width = 3, precision = 2);
-   |                   --                  ^^^^^ this named argument is only referred to by position in formatting string
+   |                   --                  ^^^^^ this named argument is referred to by position in formatting string
    |                   |
-   |                   this formatting argument uses named argument `width$` by position
+   |                   this formatting argument uses named argument `width` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -536,9 +536,9 @@ warning: named argument `precision` is not used by name
   --> $DIR/issue-99265.rs:132:50
    |
 LL |     println!("{{{:1$.2$}}}", x = 1.0, width = 3, precision = 2);
-   |                      --                          ^^^^^^^^^ this named argument is only referred to by position in formatting string
+   |                      --                          ^^^^^^^^^ this named argument is referred to by position in formatting string
    |                      |
-   |                      this formatting argument uses named argument `precision$` by position
+   |                      this formatting argument uses named argument `precision` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -549,9 +549,9 @@ warning: named argument `x` is not used by name
   --> $DIR/issue-99265.rs:132:30
    |
 LL |     println!("{{{:1$.2$}}}", x = 1.0, width = 3, precision = 2);
-   |                  -           ^ this named argument is only referred to by position in formatting string
-   |                  |
-   |                  this formatting argument uses named argument `x` by position
+   |                 --           ^ this named argument is referred to by position in formatting string
+   |                 |
+   |                 this formatting argument uses named argument `x` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
diff --git a/src/test/ui/macros/issue-99907.fixed b/src/test/ui/macros/issue-99907.fixed
new file mode 100644 (file)
index 0000000..9e0e1b8
--- /dev/null
@@ -0,0 +1,24 @@
+// check-pass
+// run-rustfix
+
+fn main() {
+    println!("Hello {f:.1}!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello {f:1.1}!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello {f}!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello {f}!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello {f}!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+}
diff --git a/src/test/ui/macros/issue-99907.rs b/src/test/ui/macros/issue-99907.rs
new file mode 100644 (file)
index 0000000..eebcfc2
--- /dev/null
@@ -0,0 +1,24 @@
+// check-pass
+// run-rustfix
+
+fn main() {
+    println!("Hello {:.1}!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello {:1.1}!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello {}!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello { }!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello {  }!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+}
diff --git a/src/test/ui/macros/issue-99907.stderr b/src/test/ui/macros/issue-99907.stderr
new file mode 100644 (file)
index 0000000..4786ce0
--- /dev/null
@@ -0,0 +1,68 @@
+warning: named argument `f` is not used by name
+  --> $DIR/issue-99907.rs:5:30
+   |
+LL |     println!("Hello {:.1}!", f = 0.02f32);
+   |                     --       ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `f` by position
+   |
+   = note: `#[warn(named_arguments_used_positionally)]` on by default
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("Hello {f:.1}!", f = 0.02f32);
+   |                      +
+
+warning: named argument `f` is not used by name
+  --> $DIR/issue-99907.rs:9:31
+   |
+LL |     println!("Hello {:1.1}!", f = 0.02f32);
+   |                     --        ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `f` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("Hello {f:1.1}!", f = 0.02f32);
+   |                      +
+
+warning: named argument `f` is not used by name
+  --> $DIR/issue-99907.rs:13:27
+   |
+LL |     println!("Hello {}!", f = 0.02f32);
+   |                     --    ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `f` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("Hello {f}!", f = 0.02f32);
+   |                      +
+
+warning: named argument `f` is not used by name
+  --> $DIR/issue-99907.rs:17:28
+   |
+LL |     println!("Hello { }!", f = 0.02f32);
+   |                     ---    ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `f` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("Hello {f}!", f = 0.02f32);
+   |                      +
+
+warning: named argument `f` is not used by name
+  --> $DIR/issue-99907.rs:21:29
+   |
+LL |     println!("Hello {  }!", f = 0.02f32);
+   |                     ----    ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `f` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("Hello {f}!", f = 0.02f32);
+   |                      +
+
+warning: 5 warnings emitted
+
index 90131ebd9203c54c24ef86bdc936dd614e50b9c5..080dbcfdd41dbc0cf88acd91b78c18eb29f7e2ad 100644 (file)
@@ -5,6 +5,7 @@
 use self::Join::*;
 
 #[derive(Debug)]
+#[allow(unused_tuple_struct_fields)]
 enum Join<A,B> {
   Keep(A,B),
   Skip(A,B),
index f246aa26a9d039586271a095083f10ac24c9905b..8e71ed7c1120f0342ea6176da719cf0495f58c36 100644 (file)
@@ -865,8 +865,9 @@ fn test_vis() {
     assert_eq!(stringify_vis!(pub(crate)), "pub(crate) ");
     assert_eq!(stringify_vis!(pub(self)), "pub(self) ");
     assert_eq!(stringify_vis!(pub(super)), "pub(super) ");
-    assert_eq!(stringify_vis!(pub(in self)), "pub(self) ");
-    assert_eq!(stringify_vis!(pub(in super)), "pub(super) ");
+    assert_eq!(stringify_vis!(pub(in crate)), "pub(in crate) ");
+    assert_eq!(stringify_vis!(pub(in self)), "pub(in self) ");
+    assert_eq!(stringify_vis!(pub(in super)), "pub(in super) ");
     assert_eq!(stringify_vis!(pub(in path::to)), "pub(in path::to) ");
     assert_eq!(stringify_vis!(pub(in ::path::to)), "pub(in ::path::to) ");
     assert_eq!(stringify_vis!(pub(in self::path::to)), "pub(in self::path::to) ");
index 596309f25683349fc14ba1841a2a34e2a4df52ca..46a0bd35d6ada6a8ec036267cdf6c9cbed3272a9 100644 (file)
@@ -1,5 +1,4 @@
 // run-pass
-#![feature(box_syntax)]
 #![feature(box_patterns)]
 
 #[derive(Debug, PartialEq)]
@@ -9,13 +8,13 @@ enum Test {
 }
 
 fn main() {
-    let a = box Test::Foo(10);
-    let b = box Test::Bar(-20);
+    let a = Box::new(Test::Foo(10));
+    let b = Box::new(Test::Bar(-20));
     match (a, b) {
         (_, box Test::Foo(_)) => unreachable!(),
         (box Test::Foo(x), b) => {
             assert_eq!(x, 10);
-            assert_eq!(b, box Test::Bar(-20));
+            assert_eq!(b, Box::new(Test::Bar(-20)));
         },
         _ => unreachable!(),
     }
index acd4a8465b0757dcec4aa982b4b90d93fb11f6ed..a3c31fab1c2c8c0b4028640b1f0424d202fa5366 100644 (file)
@@ -7,7 +7,7 @@ pub trait Service {
     fn call(&self, _req: Self::Request);
 }
 
-pub struct S<T>(T);
+pub struct S<T>(#[allow(unused_tuple_struct_fields)] T);
 
 impl Service for ClientMap {
     type Request = S<Box<dyn Fn(i32)>>;
index af362efe15c358c5919ca98cde0fd9460aca425e..ec41b7117097077234baf94bfea5b108a375eeae 100644 (file)
@@ -15,7 +15,7 @@ fn my_fn(&self) {}
 
 impl MyTrait1 for Foo<u32> {}
 
-struct Foo<T>(T);
+struct Foo<T>(#[allow(unused_tuple_struct_fields)] T);
 
 impl Deref for Foo<()> {
     type Target = dyn MyTrait1 + 'static;
@@ -33,7 +33,7 @@ fn my_fn2(&self) {}
 }
 
 impl MyTrait2 for u32 {}
-struct Bar<T>(T, u32);
+struct Bar<T>(#[allow(unused_tuple_struct_fields)] T, u32);
 impl Deref for Bar<u8> {
     type Target = dyn MyTrait2 + 'static;
     fn deref(&self) -> &(dyn MyTrait2 + 'static) {
index d2589ae4ad297780e5da7eadb2d3c5854d6177c7..9c93499d948036b81bffa40a181805a82be487fc 100644 (file)
@@ -1,7 +1,7 @@
 // run-pass
 enum Abc {
-    A(u8),
-    B(i8),
+    A(#[allow(unused_tuple_struct_fields)] u8),
+    B(#[allow(unused_tuple_struct_fields)] i8),
     C,
     D,
 }
index fb34de62f3113191c7b39370ce1ee5f73f7653e5..7c3e07c9e346fb4ef52d9bf98148f525e0e37442 100644 (file)
@@ -1,7 +1,7 @@
 // run-pass
 // test that ordinary fat pointer operations work.
 
-struct Wrapper<T: ?Sized>(u32, T);
+struct Wrapper<T: ?Sized>(#[allow(unused_tuple_struct_fields)] u32, T);
 
 struct FatPtrContainer<'a> {
     ptr: &'a [u8]
index aa2b499b027dc32125d9564dd064e33504379e00..6aceefbe7159dccf8fa72700c059467306cf7db6 100644 (file)
@@ -103,6 +103,7 @@ fn foo(&self) -> usize {
     }
 }
 
+#[allow(unused_tuple_struct_fields)]
 struct S<T:?Sized>(u32, T);
 
 fn main_ref() {
index 729db2d25f5afd0337bc4528c45f179931362ba2..6cd9526b749f3f06b12568d70ea2c315b62d0d31 100644 (file)
@@ -3,7 +3,7 @@
 
 extern crate mir_external_refs as ext;
 
-struct S(u8);
+struct S(#[allow(unused_tuple_struct_fields)] u8);
 #[derive(Debug, PartialEq, Eq)]
 struct Unit;
 
@@ -46,7 +46,7 @@ impl<I, O> T<I, O> for O {}
 impl X for S {}
 
 enum E {
-    U(u8)
+    U(#[allow(unused_tuple_struct_fields)] u8)
 }
 
 #[derive(PartialEq, Debug, Eq)]
index ef03b67b1b0b19db03bec5b038bdc717c315cb8b..7fec6ecd72573727ba2829869da3d4f6192d44ca 100644 (file)
@@ -17,6 +17,10 @@ LL |         (0, ref y) | (y, 0) => {}
    |             first introduced with type `&{integer}` here
    |
    = note: in the same arm, a binding must have the same type in all alternatives
+help: consider adding `ref`
+   |
+LL |         (0, ref y) | (ref y, 0) => {}
+   |                       +++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/mismatched_types/do-not-suggest-boxed-trait-objects-instead-of-impl-trait.rs b/src/test/ui/mismatched_types/do-not-suggest-boxed-trait-objects-instead-of-impl-trait.rs
new file mode 100644 (file)
index 0000000..d302dc9
--- /dev/null
@@ -0,0 +1,23 @@
+struct S;
+struct Y;
+
+trait Trait {}
+
+impl Trait for Y {}
+
+fn foo() -> impl Trait {
+    if true {
+        S
+    } else {
+        Y //~ ERROR `if` and `else` have incompatible types
+    }
+}
+
+fn bar() -> impl Trait {
+    match true {
+        true => S,
+        false => Y, //~ ERROR `match` arms have incompatible types
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/mismatched_types/do-not-suggest-boxed-trait-objects-instead-of-impl-trait.stderr b/src/test/ui/mismatched_types/do-not-suggest-boxed-trait-objects-instead-of-impl-trait.stderr
new file mode 100644 (file)
index 0000000..2f81444
--- /dev/null
@@ -0,0 +1,26 @@
+error[E0308]: `if` and `else` have incompatible types
+  --> $DIR/do-not-suggest-boxed-trait-objects-instead-of-impl-trait.rs:12:9
+   |
+LL | /     if true {
+LL | |         S
+   | |         - expected because of this
+LL | |     } else {
+LL | |         Y
+   | |         ^ expected struct `S`, found struct `Y`
+LL | |     }
+   | |_____- `if` and `else` have incompatible types
+
+error[E0308]: `match` arms have incompatible types
+  --> $DIR/do-not-suggest-boxed-trait-objects-instead-of-impl-trait.rs:19:18
+   |
+LL | /     match true {
+LL | |         true => S,
+   | |                 - this is found to be of type `S`
+LL | |         false => Y,
+   | |                  ^ expected struct `S`, found struct `Y`
+LL | |     }
+   | |_____- `match` arms have incompatible types
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/mismatched_types/dont-point-return-on-E0308.rs b/src/test/ui/mismatched_types/dont-point-return-on-E0308.rs
new file mode 100644 (file)
index 0000000..f2ba610
--- /dev/null
@@ -0,0 +1,18 @@
+// edition:2021
+
+async fn f(_: &()) {}
+//~^ NOTE function defined here
+//~| NOTE
+// Second note is the span of the underlined argument, I think...
+
+fn main() {
+    (|| async {
+        Err::<(), ()>(())?;
+        f(());
+        //~^ ERROR mismatched types
+        //~| NOTE arguments to this function are incorrect
+        //~| NOTE expected `&()`, found `()`
+        //~| HELP consider borrowing here
+        Ok::<(), ()>(())
+    })();
+}
diff --git a/src/test/ui/mismatched_types/dont-point-return-on-E0308.stderr b/src/test/ui/mismatched_types/dont-point-return-on-E0308.stderr
new file mode 100644 (file)
index 0000000..1394268
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0308]: mismatched types
+  --> $DIR/dont-point-return-on-E0308.rs:11:11
+   |
+LL |         f(());
+   |         - ^^
+   |         | |
+   |         | expected `&()`, found `()`
+   |         | help: consider borrowing here: `&()`
+   |         arguments to this function are incorrect
+   |
+note: function defined here
+  --> $DIR/dont-point-return-on-E0308.rs:3:10
+   |
+LL | async fn f(_: &()) {}
+   |          ^ ------
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
index f8f2b1f0f57204c9120a693b43852f7e441d73f8..9157566e3a79bfa7e150a2ac1e88db723a39b2b3 100644 (file)
@@ -3,6 +3,11 @@ error[E0308]: mismatched types
    |
 LL |     length = { foo(&length) };
    |                ^^^^^^^^^^^^ expected `u32`, found `i32`
+   |
+help: you can convert an `i32` to a `u32` and panic if the converted value doesn't fit
+   |
+LL |     length = { foo(&length).try_into().unwrap() };
+   |                            ++++++++++++++++++++
 
 error[E0308]: mismatched types
   --> $DIR/issue-84976.rs:17:14
diff --git a/src/test/ui/mismatched_types/suggest-adding-or-removing-ref-for-binding-pattern.fixed b/src/test/ui/mismatched_types/suggest-adding-or-removing-ref-for-binding-pattern.fixed
new file mode 100644 (file)
index 0000000..56f93cf
--- /dev/null
@@ -0,0 +1,21 @@
+// run-rustfix
+#![allow(dead_code, unused_variables)]
+
+fn main() {
+    enum Blah {
+        A(isize, isize, usize),
+        B(isize, usize),
+    }
+
+    match Blah::A(1, 1, 2) {
+        Blah::A(_, x, ref y) | Blah::B(x, ref y) => {}
+        //~^ ERROR mismatched types
+        //~| ERROR variable `y` is bound inconsistently across alternatives separated by `|`
+    }
+
+    match Blah::A(1, 1, 2) {
+        Blah::A(_, x, y) | Blah::B(x, y) => {}
+        //~^ ERROR mismatched types
+        //~| variable `y` is bound inconsistently across alternatives separated by `|`
+    }
+}
diff --git a/src/test/ui/mismatched_types/suggest-adding-or-removing-ref-for-binding-pattern.rs b/src/test/ui/mismatched_types/suggest-adding-or-removing-ref-for-binding-pattern.rs
new file mode 100644 (file)
index 0000000..0c33f99
--- /dev/null
@@ -0,0 +1,21 @@
+// run-rustfix
+#![allow(dead_code, unused_variables)]
+
+fn main() {
+    enum Blah {
+        A(isize, isize, usize),
+        B(isize, usize),
+    }
+
+    match Blah::A(1, 1, 2) {
+        Blah::A(_, x, ref y) | Blah::B(x, y) => {}
+        //~^ ERROR mismatched types
+        //~| ERROR variable `y` is bound inconsistently across alternatives separated by `|`
+    }
+
+    match Blah::A(1, 1, 2) {
+        Blah::A(_, x, y) | Blah::B(x, ref y) => {}
+        //~^ ERROR mismatched types
+        //~| variable `y` is bound inconsistently across alternatives separated by `|`
+    }
+}
diff --git a/src/test/ui/mismatched_types/suggest-adding-or-removing-ref-for-binding-pattern.stderr b/src/test/ui/mismatched_types/suggest-adding-or-removing-ref-for-binding-pattern.stderr
new file mode 100644 (file)
index 0000000..e8357f9
--- /dev/null
@@ -0,0 +1,49 @@
+error[E0409]: variable `y` is bound inconsistently across alternatives separated by `|`
+  --> $DIR/suggest-adding-or-removing-ref-for-binding-pattern.rs:11:43
+   |
+LL |         Blah::A(_, x, ref y) | Blah::B(x, y) => {}
+   |                           - first binding ^ bound in different ways
+
+error[E0409]: variable `y` is bound inconsistently across alternatives separated by `|`
+  --> $DIR/suggest-adding-or-removing-ref-for-binding-pattern.rs:17:43
+   |
+LL |         Blah::A(_, x, y) | Blah::B(x, ref y) => {}
+   |                       - first binding     ^ bound in different ways
+
+error[E0308]: mismatched types
+  --> $DIR/suggest-adding-or-removing-ref-for-binding-pattern.rs:11:43
+   |
+LL |     match Blah::A(1, 1, 2) {
+   |           ---------------- this expression has type `Blah`
+LL |         Blah::A(_, x, ref y) | Blah::B(x, y) => {}
+   |                       -----               ^ expected `&usize`, found `usize`
+   |                       |
+   |                       first introduced with type `&usize` here
+   |
+   = note: in the same arm, a binding must have the same type in all alternatives
+help: consider adding `ref`
+   |
+LL |         Blah::A(_, x, ref y) | Blah::B(x, ref y) => {}
+   |                                           +++
+
+error[E0308]: mismatched types
+  --> $DIR/suggest-adding-or-removing-ref-for-binding-pattern.rs:17:39
+   |
+LL |     match Blah::A(1, 1, 2) {
+   |           ---------------- this expression has type `Blah`
+LL |         Blah::A(_, x, y) | Blah::B(x, ref y) => {}
+   |                       -               ^^^^^ expected `usize`, found `&usize`
+   |                       |
+   |                       first introduced with type `usize` here
+   |
+   = note: in the same arm, a binding must have the same type in all alternatives
+help: consider removing `ref`
+   |
+LL -         Blah::A(_, x, y) | Blah::B(x, ref y) => {}
+LL +         Blah::A(_, x, y) | Blah::B(x, y) => {}
+   |
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0308, E0409.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/mismatched_types/suggest-boxed-trait-objects-instead-of-impl-trait.fixed b/src/test/ui/mismatched_types/suggest-boxed-trait-objects-instead-of-impl-trait.fixed
new file mode 100644 (file)
index 0000000..f30feae
--- /dev/null
@@ -0,0 +1,28 @@
+// run-rustfix
+
+#![allow(dead_code)]
+
+struct S;
+struct Y;
+
+trait Trait {}
+
+impl Trait for S {}
+impl Trait for Y {}
+
+fn foo() -> Box<dyn Trait> {
+    if true {
+        Box::new(S)
+    } else {
+        Box::new(Y) //~ ERROR `if` and `else` have incompatible types
+    }
+}
+
+fn bar() -> Box<dyn Trait> {
+    match true {
+        true => Box::new(S),
+        false => Box::new(Y), //~ ERROR `match` arms have incompatible types
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/mismatched_types/suggest-boxed-trait-objects-instead-of-impl-trait.rs b/src/test/ui/mismatched_types/suggest-boxed-trait-objects-instead-of-impl-trait.rs
new file mode 100644 (file)
index 0000000..2bd8146
--- /dev/null
@@ -0,0 +1,28 @@
+// run-rustfix
+
+#![allow(dead_code)]
+
+struct S;
+struct Y;
+
+trait Trait {}
+
+impl Trait for S {}
+impl Trait for Y {}
+
+fn foo() -> impl Trait {
+    if true {
+        S
+    } else {
+        Y //~ ERROR `if` and `else` have incompatible types
+    }
+}
+
+fn bar() -> impl Trait {
+    match true {
+        true => S,
+        false => Y, //~ ERROR `match` arms have incompatible types
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/mismatched_types/suggest-boxed-trait-objects-instead-of-impl-trait.stderr b/src/test/ui/mismatched_types/suggest-boxed-trait-objects-instead-of-impl-trait.stderr
new file mode 100644 (file)
index 0000000..f58b9c3
--- /dev/null
@@ -0,0 +1,47 @@
+error[E0308]: `if` and `else` have incompatible types
+  --> $DIR/suggest-boxed-trait-objects-instead-of-impl-trait.rs:17:9
+   |
+LL | /     if true {
+LL | |         S
+   | |         - expected because of this
+LL | |     } else {
+LL | |         Y
+   | |         ^ expected struct `S`, found struct `Y`
+LL | |     }
+   | |_____- `if` and `else` have incompatible types
+   |
+help: you could change the return type to be a boxed trait object
+   |
+LL | fn foo() -> Box<dyn Trait> {
+   |             ~~~~~~~      +
+help: if you change the return type to expect trait objects, box the returned expressions
+   |
+LL ~         Box::new(S)
+LL |     } else {
+LL ~         Box::new(Y)
+   |
+
+error[E0308]: `match` arms have incompatible types
+  --> $DIR/suggest-boxed-trait-objects-instead-of-impl-trait.rs:24:18
+   |
+LL | /     match true {
+LL | |         true => S,
+   | |                 - this is found to be of type `S`
+LL | |         false => Y,
+   | |                  ^ expected struct `S`, found struct `Y`
+LL | |     }
+   | |_____- `match` arms have incompatible types
+   |
+help: you could change the return type to be a boxed trait object
+   |
+LL | fn bar() -> Box<dyn Trait> {
+   |             ~~~~~~~      +
+help: if you change the return type to expect trait objects, box the returned expressions
+   |
+LL ~         true => Box::new(S),
+LL ~         false => Box::new(Y),
+   |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/moves/issue-99470-move-out-of-some.rs b/src/test/ui/moves/issue-99470-move-out-of-some.rs
new file mode 100644 (file)
index 0000000..f404cd3
--- /dev/null
@@ -0,0 +1,9 @@
+fn main() {
+    let x: &Option<Box<i32>> = &Some(Box::new(0));
+
+    match x {
+    //~^ ERROR cannot move out of `x` as enum variant `Some` which is behind a shared reference
+        &Some(_y) => (),
+        &None => (),
+    }
+}
diff --git a/src/test/ui/moves/issue-99470-move-out-of-some.stderr b/src/test/ui/moves/issue-99470-move-out-of-some.stderr
new file mode 100644 (file)
index 0000000..6e4a4e5
--- /dev/null
@@ -0,0 +1,16 @@
+error[E0507]: cannot move out of `x` as enum variant `Some` which is behind a shared reference
+  --> $DIR/issue-99470-move-out-of-some.rs:4:11
+   |
+LL |     match x {
+   |           ^
+LL |
+LL |         &Some(_y) => (),
+   |         ---------
+   |         |     |
+   |         |     data moved here
+   |         |     move occurs because `_y` has type `Box<i32>`, which does not implement the `Copy` trait
+   |         help: consider removing the `&`: `Some(_y)`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0507`.
index a9ac9d63a95139e6eba6b4d32a34e60b7a84167d..5ed91a0d5596340888162fbf5dcef12579104f49 100644 (file)
@@ -1,4 +1,4 @@
-error[E0507]: cannot move out of `hellothere.x.0` which is behind a shared reference
+error[E0507]: cannot move out of `hellothere.x` as enum variant `Bar` which is behind a shared reference
   --> $DIR/moves-based-on-type-block-bad.rs:22:19
    |
 LL |             match hellothere.x {
index 2acf44432c65fde1073d4a4748fab12e4c612e8e..45cf3723483f3a05f0ca60546bc6c949bb7df68a 100644 (file)
@@ -1,4 +1,4 @@
-error[E0271]: type mismatch resolving `<[closure@$DIR/fallback-closure-wrap.rs:18:40: 18:47] as FnOnce<()>>::Output == ()`
+error[E0271]: expected `[closure@$DIR/fallback-closure-wrap.rs:18:40: 18:47]` to be a closure that returns `()`, but it returns `!`
   --> $DIR/fallback-closure-wrap.rs:18:31
    |
 LL |       let error = Closure::wrap(Box::new(move || {
index af0577ac0609fcb24d9eaad0302819b6f5787771..35052da6760b64ecfe443cbc67eed82304b30aba 100644 (file)
@@ -16,7 +16,7 @@
 
 fn main() {
     let error = Closure::wrap(Box::new(move || {
-        //[fallback]~^ ERROR type mismatch resolving
+        //[fallback]~^ to be a closure that returns `()`, but it returns `!`
         panic!("Can't connect to server.");
     }) as Box<dyn FnMut()>);
 }
diff --git a/src/test/ui/nll/issue-98589-closures-relate-named-regions.rs b/src/test/ui/nll/issue-98589-closures-relate-named-regions.rs
new file mode 100644 (file)
index 0000000..6cc4340
--- /dev/null
@@ -0,0 +1,36 @@
+// Regression test for #98589.
+// Previously, named lifetime `'a` that appears in the closure was unrelated to `'a`
+// that appears in the parent function iff `'a` is early-bound.
+// This made the following tests pass borrowck.
+
+// check-fail
+
+// The bound `'a: 'a` ensures that `'a` is early-bound.
+fn test_early_early<'a: 'a, 'b: 'b>() {
+    || { None::<&'a &'b ()>; };
+    //~^ ERROR lifetime may not live long enough
+}
+
+fn test_early_late<'a: 'a, 'b>() {
+    || { None::<&'a &'b ()>; };
+    //~^ ERROR lifetime may not live long enough
+}
+
+// No early-bound lifetime; included for completeness.
+fn test_late_late<'a, 'b>() {
+    || { None::<&'a &'b ()>; };
+    //~^ ERROR lifetime may not live long enough
+}
+
+fn test_early_type<'a: 'a, T>() {
+    || { None::<&'a T>; };
+    //~^ ERROR the parameter type `T` may not live long enough
+}
+
+// No early-bound lifetime; included for completeness.
+fn test_late_type<'a, T>() {
+    || { None::<&'a T>; };
+    //~^ ERROR the parameter type `T` may not live long enough
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/issue-98589-closures-relate-named-regions.stderr b/src/test/ui/nll/issue-98589-closures-relate-named-regions.stderr
new file mode 100644 (file)
index 0000000..6def560
--- /dev/null
@@ -0,0 +1,61 @@
+error: lifetime may not live long enough
+  --> $DIR/issue-98589-closures-relate-named-regions.rs:10:5
+   |
+LL | fn test_early_early<'a: 'a, 'b: 'b>() {
+   |                     --      -- lifetime `'b` defined here
+   |                     |
+   |                     lifetime `'a` defined here
+LL |     || { None::<&'a &'b ()>; };
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+
+error: lifetime may not live long enough
+  --> $DIR/issue-98589-closures-relate-named-regions.rs:15:10
+   |
+LL | fn test_early_late<'a: 'a, 'b>() {
+   |                    --      -- lifetime `'b` defined here
+   |                    |
+   |                    lifetime `'a` defined here
+LL |     || { None::<&'a &'b ()>; };
+   |          ^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+
+error: lifetime may not live long enough
+  --> $DIR/issue-98589-closures-relate-named-regions.rs:21:10
+   |
+LL | fn test_late_late<'a, 'b>() {
+   |                   --  -- lifetime `'b` defined here
+   |                   |
+   |                   lifetime `'a` defined here
+LL |     || { None::<&'a &'b ()>; };
+   |          ^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+
+error[E0309]: the parameter type `T` may not live long enough
+  --> $DIR/issue-98589-closures-relate-named-regions.rs:26:5
+   |
+LL |     || { None::<&'a T>; };
+   |     ^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn test_early_type<'a: 'a, T: 'a>() {
+   |                             ++++
+
+error[E0309]: the parameter type `T` may not live long enough
+  --> $DIR/issue-98589-closures-relate-named-regions.rs:32:5
+   |
+LL |     || { None::<&'a T>; };
+   |     ^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn test_late_type<'a, T: 'a>() {
+   |                        ++++
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0309`.
index 0df326425ad9c60ca035007ba74b75f4ffaf39c2..b03fcf70babe25850fcc3d068e15a4e282b63dda 100644 (file)
@@ -45,7 +45,7 @@ LL |     let a = [A("".to_string())][0];
    |             move occurs because value has type `A`, which does not implement the `Copy` trait
    |             help: consider borrowing here: `&[A("".to_string())][0]`
 
-error[E0507]: cannot move out of `a.0` which is behind a shared reference
+error[E0507]: cannot move out of `a` which is behind a shared reference
   --> $DIR/move-errors.rs:38:16
    |
 LL |     let A(s) = *a;
@@ -134,7 +134,7 @@ LL |         F(s, mut t) => (),
    |
    = note: move occurs because these variables have types that don't implement the `Copy` trait
 
-error[E0507]: cannot move out of `x.0` which is behind a shared reference
+error[E0507]: cannot move out of `x` as enum variant `Err` which is behind a shared reference
   --> $DIR/move-errors.rs:110:11
    |
 LL |     match *x {
index c4db6fc97dc32468798403b8f7505acb3cac0e44..05e2ea047f65af722c5f6d59cde97252dde32839 100644 (file)
@@ -30,4 +30,5 @@ fn main() {
     let _x = <fn(&())>::make_f();
     //~^ ERROR implementation of `Y` is not general enough
     //~| ERROR implementation of `Y` is not general enough
+    //~| ERROR implementation of `Y` is not general enough
 }
index 51adfca3e79f488dc0dc753a4ed6e20cd356b36f..8c47379886d2a8a873b79f0246502b2d055007d5 100644 (file)
@@ -16,5 +16,14 @@ LL |     let _x = <fn(&())>::make_f();
    = note: `Y` would have to be implemented for the type `for<'r> fn(&'r ())`
    = note: ...but `Y` is actually implemented for the type `fn(&'0 ())`, for some specific lifetime `'0`
 
-error: aborting due to 2 previous errors
+error: implementation of `Y` is not general enough
+  --> $DIR/impl-fn-ignore-binder-via-bottom.rs:30:14
+   |
+LL |     let _x = <fn(&())>::make_f();
+   |              ^^^^^^^^^^^^^^^^^^^ implementation of `Y` is not general enough
+   |
+   = note: `Y` would have to be implemented for the type `for<'r> fn(&'r ())`
+   = note: ...but `Y` is actually implemented for the type `fn(&'0 ())`, for some specific lifetime `'0`
+
+error: aborting due to 3 previous errors
 
index 0c696163a26c5cba2737b6bf51ae504c1e84af26..15e22e946da8a1da79630526c7f82f0fff9b02cb 100644 (file)
@@ -10,6 +10,14 @@ LL |     let _y = x.clone();
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `clone`, perhaps you need to implement it:
            candidate #1: `Clone`
+help: one of the expressions' fields has a method of the same name
+   |
+LL |     let _y = x.i.clone();
+   |                ++
+help: one of the expressions' fields has a method of the same name
+   |
+LL |     let _y = x.j.x.clone();
+   |                ++++
 
 error: aborting due to previous error
 
index f9edba6743499dddcfe13e4ea0e8b5095cf3a2bf..d345fec811854890fdbaa09ab69d8f0fca29778d 100644 (file)
@@ -8,7 +8,7 @@
 // trying to get assert failure messages that at least identify which case
 // failed.
 
-enum E<T> { Thing(isize, T), Nothing((), ((), ()), [i8; 0]) }
+enum E<T> { Thing(isize, T), #[allow(unused_tuple_struct_fields)] Nothing((), ((), ()), [i8; 0]) }
 impl<T> E<T> {
     fn is_none(&self) -> bool {
         match *self {
index a97c5750f94c34a2fd8eab648e1386b65e493e05..2643dbea1c4347f4112066fe0397a3567663c033 100644 (file)
@@ -6,7 +6,9 @@
 
 // compile-flags: -Z fuel=foo=0
 
+#[allow(unused_tuple_struct_fields)]
 struct S1(u8, u16, u8);
+#[allow(unused_tuple_struct_fields)]
 struct S2(u8, u16, u8);
 
 fn main() {
index a09f91c68abe7b6309b6650f52b84bc7fe3d1d53..d5e2255d9f06fdfbdccfaf17a08aec0caf7681e7 100644 (file)
@@ -6,7 +6,9 @@
 
 // compile-flags: -Z fuel=foo=1
 
+#[allow(unused_tuple_struct_fields)]
 struct S1(u8, u16, u8);
+#[allow(unused_tuple_struct_fields)]
 struct S2(u8, u16, u8);
 
 fn main() {
index b95cdbbbaad3b2e857774c69c96df9c64fb76950..9f9f41e251564608a9fe60431daed988e65ef5f6 100644 (file)
@@ -24,7 +24,7 @@ fn drop(&mut self) {
 }
 
 #[repr(transparent)]
-struct NotCopy(u8);
+struct NotCopy(#[allow(unused_tuple_struct_fields)] u8);
 
 #[repr(packed)]
 struct Packed<'a>(NotCopy, Aligned<'a>);
index 7ce62464ef02c097889fd23236d182f2cc988f45..5e1a1f518c57049f15f4e1cc53c7d9b97533e29c 100644 (file)
@@ -1,6 +1,6 @@
 // run-pass
 #[repr(packed)]
-struct Packed<T: Copy>(T);
+struct Packed<T: Copy>(#[allow(unused_tuple_struct_fields)] T);
 
 impl<T: Copy> Copy for Packed<T> {}
 impl<T: Copy> Clone for Packed<T> {
index b88637fbe5658d2a6d2795f7e69949daae6e6650..931be5b941443420854d3f89a9316d8f42ae7af3 100644 (file)
@@ -2,9 +2,11 @@
 use std::mem;
 
 #[repr(packed)]
+#[allow(unused_tuple_struct_fields)]
 struct S4(u8,[u8; 3]);
 
 #[repr(packed)]
+#[allow(unused_tuple_struct_fields)]
 struct S5(u8,u32);
 
 pub fn main() {
diff --git a/src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.rs b/src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.rs
new file mode 100644 (file)
index 0000000..7ebf3f6
--- /dev/null
@@ -0,0 +1,8 @@
+fn foo() {}
+
+fn bar() -> [u8; 2] {
+    foo()
+    [1, 3) //~ ERROR expected one of `.`, `?`, `]`, or an operator, found `,`
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.stderr b/src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.stderr
new file mode 100644 (file)
index 0000000..d6e8db8
--- /dev/null
@@ -0,0 +1,10 @@
+error: expected one of `.`, `?`, `]`, or an operator, found `,`
+  --> $DIR/do-not-suggest-suggest-semicolon-before-array.rs:5:5
+   |
+LL |     [1, 3)
+   |     ^ ^ help: `]` may belong here
+   |     |
+   |     unclosed delimiter
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/issue-99625-enum-struct-mutually-exclusive.fixed b/src/test/ui/parser/issue-99625-enum-struct-mutually-exclusive.fixed
new file mode 100644 (file)
index 0000000..4b4a416
--- /dev/null
@@ -0,0 +1,13 @@
+// run-rustfix
+
+pub enum Range {
+    //~^ ERROR `enum` and `struct` are mutually exclusive
+    Valid {
+        begin: u32,
+        len: u32,
+    },
+    Out,
+}
+
+fn main() {
+}
diff --git a/src/test/ui/parser/issue-99625-enum-struct-mutually-exclusive.rs b/src/test/ui/parser/issue-99625-enum-struct-mutually-exclusive.rs
new file mode 100644 (file)
index 0000000..9cc8866
--- /dev/null
@@ -0,0 +1,13 @@
+// run-rustfix
+
+pub enum struct Range {
+    //~^ ERROR `enum` and `struct` are mutually exclusive
+    Valid {
+        begin: u32,
+        len: u32,
+    },
+    Out,
+}
+
+fn main() {
+}
diff --git a/src/test/ui/parser/issue-99625-enum-struct-mutually-exclusive.stderr b/src/test/ui/parser/issue-99625-enum-struct-mutually-exclusive.stderr
new file mode 100644 (file)
index 0000000..edc640b
--- /dev/null
@@ -0,0 +1,8 @@
+error: `enum` and `struct` are mutually exclusive
+  --> $DIR/issue-99625-enum-struct-mutually-exclusive.rs:3:5
+   |
+LL | pub enum struct Range {
+   |     ^^^^^^^^^^^ help: replace `enum struct` with: `enum`
+
+error: aborting due to previous error
+
index 464e78fd0359534e0bd9bdcf11cddd3e6f94cd94..8d981405ea1ca344466bf2a6c1ffad5e2bc18575 100644 (file)
@@ -1,7 +1,7 @@
 // run-rustfix
 // This is for checking if we can apply suggestions as-is.
 
-pub struct Foo(i32);
+pub struct Foo(#[allow(unused_tuple_struct_fields)] i32);
 
 fn main() {
     let Foo(..) = Foo(0); //~ ERROR unexpected `...`
index 9e35e4c38aa871b5deb0aeb96f918ffce93c6440..bf36073083a39ee48d75e455d69ccd19b5f8c631 100644 (file)
@@ -1,7 +1,7 @@
 // run-rustfix
 // This is for checking if we can apply suggestions as-is.
 
-pub struct Foo(i32);
+pub struct Foo(#[allow(unused_tuple_struct_fields)] i32);
 
 fn main() {
     let Foo(...) = Foo(0); //~ ERROR unexpected `...`
index bf89033f560e9da8b477a44384b31d04eabf4328..bb69951c7b4eaca0f13ac0c095d914498b6ce385 100644 (file)
@@ -3,7 +3,7 @@
 // error-pattern:this file contains an unclosed delimiter
 // error-pattern:expected one of
 // error-pattern:missing `in` in `for` loop
-// error-pattern:expected `;`, found `e`
+// error-pattern:expected one of `!`, `)`, `,`, `.`, `::`, `;`, `?`, `{`, or an operator, found `e`
 
 fn m(){print!("",(c for&g
 u
index c7e24155d16929fbb5c02b8fe0b5bba0549bddc7..4e3a21613ec7869010b106e6d3a018f14595c448 100644 (file)
@@ -48,19 +48,13 @@ error: expected one of `!`, `)`, `,`, `.`, `::`, `?`, `{`, or an operator, found
 LL | fn m(){print!("",(c for&g
    |                     ^^^ expected one of 8 possible tokens
 
-error: expected `;`, found `e`
-  --> $DIR/issue-88770.rs:10:2
+error: expected one of `!`, `)`, `,`, `.`, `::`, `;`, `?`, `{`, or an operator, found `e`
+  --> $DIR/issue-88770.rs:11:1
    |
 LL | e
-   |  ^ help: add `;` here
+   |  - expected one of 9 possible tokens
 LL | e
-   | - unexpected token
+   | ^ unexpected token
 
-error: expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `)`
-  --> $DIR/issue-88770.rs:11:3
-   |
-LL | e
-   |   ^ expected one of 7 possible tokens
-
-error: aborting due to 7 previous errors
+error: aborting due to 6 previous errors
 
index cbee3d35155c7925e3228986dbc54ac77f180978..fb1312c782aab95fe0d3ad607486324c38311bec 100644 (file)
@@ -1,8 +1,8 @@
 error: missing type for `const` item
-  --> $DIR/issue-89574.rs:2:11
+  --> $DIR/issue-89574.rs:2:22
    |
 LL |     const EMPTY_ARRAY = [];
-   |           ^^^^^^^^^^^ help: provide a type for the item: `EMPTY_ARRAY: <type>`
+   |                      ^ help: provide a type for the item: `: <type>`
 
 error: aborting due to previous error
 
index c340e958ee58556d5972b0de59857bbfadbe3963..5365b0a1f824264dcc5179720ea00b2e9863b25e 100644 (file)
@@ -15,10 +15,10 @@ LL | const B;
    |        help: provide a definition for the constant: `= <expr>;`
 
 error: missing type for `const` item
-  --> $DIR/item-free-const-no-body-semantic-fail.rs:6:7
+  --> $DIR/item-free-const-no-body-semantic-fail.rs:6:8
    |
 LL | const B;
-   |       ^ help: provide a type for the item: `B: <type>`
+   |        ^ help: provide a type for the item: `: <type>`
 
 error: aborting due to 3 previous errors
 
index 4d542b79861fd468b883381e72f2b97e3e1640bc..1b61e430546e0de76e4a53c27209740de9af8ab0 100644 (file)
@@ -31,16 +31,16 @@ LL | static mut D;
    |             help: provide a definition for the static: `= <expr>;`
 
 error: missing type for `static` item
-  --> $DIR/item-free-static-no-body-semantic-fail.rs:6:8
+  --> $DIR/item-free-static-no-body-semantic-fail.rs:6:9
    |
 LL | static B;
-   |        ^ help: provide a type for the item: `B: <type>`
+   |         ^ help: provide a type for the item: `: <type>`
 
 error: missing type for `static mut` item
-  --> $DIR/item-free-static-no-body-semantic-fail.rs:10:12
+  --> $DIR/item-free-static-no-body-semantic-fail.rs:10:13
    |
 LL | static mut D;
-   |            ^ help: provide a type for the item: `D: <type>`
+   |             ^ help: provide a type for the item: `: <type>`
 
 error: aborting due to 6 previous errors
 
index 04e34dc16a84209f06e2cd9ec5abfef665fabdce..52e0658949d3dd64e5144f392de1cc68a6089e9c 100644 (file)
@@ -16,10 +16,10 @@ LL | }
    | - the item list ends here
 
 error: missing type for `static` item
-  --> $DIR/removed-syntax-static-fn.rs:4:12
+  --> $DIR/removed-syntax-static-fn.rs:4:14
    |
 LL |     static fn f() {}
-   |            ^^ help: provide a type for the item: `r#fn: <type>`
+   |              ^ help: provide a type for the item: `: <type>`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/parser/suggest-semi-in-array.rs b/src/test/ui/parser/suggest-semi-in-array.rs
new file mode 100644 (file)
index 0000000..9ce2e59
--- /dev/null
@@ -0,0 +1,5 @@
+fn main() {
+    let v = [1
+    2];
+    //~^ ERROR expected one of `,`, `.`, `;`, `?`, `]`, or an operator, found `2`
+}
diff --git a/src/test/ui/parser/suggest-semi-in-array.stderr b/src/test/ui/parser/suggest-semi-in-array.stderr
new file mode 100644 (file)
index 0000000..d7cd6ef
--- /dev/null
@@ -0,0 +1,10 @@
+error: expected one of `,`, `.`, `;`, `?`, `]`, or an operator, found `2`
+  --> $DIR/suggest-semi-in-array.rs:3:5
+   |
+LL |     let v = [1
+   |               - expected one of `,`, `.`, `;`, `?`, `]`, or an operator
+LL |     2];
+   |     ^ unexpected token
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/suggest-suggest-semicolon-before-array.fixed b/src/test/ui/parser/suggest-suggest-semicolon-before-array.fixed
new file mode 100644 (file)
index 0000000..a06b58b
--- /dev/null
@@ -0,0 +1,11 @@
+// run-rustfix
+#![allow(dead_code)]
+
+fn foo() {}
+
+fn bar() -> [u8; 2] {
+    foo();
+    [1, 3] //~ ERROR expected `;`, found `[`
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/suggest-suggest-semicolon-before-array.rs b/src/test/ui/parser/suggest-suggest-semicolon-before-array.rs
new file mode 100644 (file)
index 0000000..f601ca2
--- /dev/null
@@ -0,0 +1,11 @@
+// run-rustfix
+#![allow(dead_code)]
+
+fn foo() {}
+
+fn bar() -> [u8; 2] {
+    foo()
+    [1, 3] //~ ERROR expected `;`, found `[`
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/suggest-suggest-semicolon-before-array.stderr b/src/test/ui/parser/suggest-suggest-semicolon-before-array.stderr
new file mode 100644 (file)
index 0000000..bf86b43
--- /dev/null
@@ -0,0 +1,13 @@
+error: expected `;`, found `[`
+  --> $DIR/suggest-suggest-semicolon-before-array.rs:8:5
+   |
+LL |     [1, 3]
+   |     ^
+   |
+help: consider adding `;` here
+   |
+LL |     foo();
+   |          +
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.fixed b/src/test/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.fixed
new file mode 100644 (file)
index 0000000..b28dce8
--- /dev/null
@@ -0,0 +1,10 @@
+// run-rustfix
+
+fn main() {
+    match Some(1) { //~ ERROR non-exhaustive patterns: `None` not covered
+        Some(1) => {}
+        // hello
+        Some(_) => {}
+        None => todo!()
+    }
+}
diff --git a/src/test/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.rs b/src/test/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.rs
new file mode 100644 (file)
index 0000000..42493a6
--- /dev/null
@@ -0,0 +1,9 @@
+// run-rustfix
+
+fn main() {
+    match Some(1) { //~ ERROR non-exhaustive patterns: `None` not covered
+        Some(1) => {}
+        // hello
+        Some(_) => {}
+    }
+}
diff --git a/src/test/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.stderr b/src/test/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.stderr
new file mode 100644 (file)
index 0000000..f3dca9b
--- /dev/null
@@ -0,0 +1,24 @@
+error[E0004]: non-exhaustive patterns: `None` not covered
+  --> $DIR/suggest-adding-appropriate-missing-pattern-excluding-comments.rs:4:11
+   |
+LL |     match Some(1) {
+   |           ^^^^^^^ pattern `None` not covered
+   |
+note: `Option<i32>` defined here
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+   |
+LL | pub enum Option<T> {
+   | ------------------
+...
+LL |     None,
+   |     ^^^^ not covered
+   = note: the matched value is of type `Option<i32>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         Some(_) => {}
+LL +         None => todo!()
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/src/test/ui/proc-macro/auxiliary/re-export.rs b/src/test/ui/proc-macro/auxiliary/re-export.rs
new file mode 100644 (file)
index 0000000..e8e9c9d
--- /dev/null
@@ -0,0 +1,19 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro]
+pub fn cause_ice(_: TokenStream) -> TokenStream {
+    "
+        enum IceCause {
+            Variant,
+        }
+
+        pub use IceCause::Variant;
+    ".parse().unwrap()
+}
diff --git a/src/test/ui/proc-macro/issue-79148.rs b/src/test/ui/proc-macro/issue-79148.rs
new file mode 100644 (file)
index 0000000..3f01187
--- /dev/null
@@ -0,0 +1,10 @@
+// aux-build:re-export.rs
+// edition:2018
+
+extern crate re_export;
+
+use re_export::cause_ice;
+
+cause_ice!(); //~ ERROR `Variant` is only public within the crate, and cannot be re-exported outside
+
+fn main() {}
diff --git a/src/test/ui/proc-macro/issue-79148.stderr b/src/test/ui/proc-macro/issue-79148.stderr
new file mode 100644 (file)
index 0000000..a3b2de0
--- /dev/null
@@ -0,0 +1,16 @@
+error[E0364]: `Variant` is only public within the crate, and cannot be re-exported outside
+  --> $DIR/issue-79148.rs:8:1
+   |
+LL | cause_ice!();
+   | ^^^^^^^^^^^^
+   |
+note: consider marking `Variant` as `pub` in the imported module
+  --> $DIR/issue-79148.rs:8:1
+   |
+LL | cause_ice!();
+   | ^^^^^^^^^^^^
+   = note: this error originates in the macro `cause_ice` (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 E0364`.
index 7e7a15924b7653128c9c5a2db10d6d7e28fd88f9..c9107d24ed092f791c23be804c0f6d8a8aa3ec18 100644 (file)
@@ -11,7 +11,7 @@ fn foo() -> isize { 42 }
 pub fn return_range_to() -> RangeToInclusive<i32> { return ..=1; }
 
 #[derive(Debug)]
-struct P(u8);
+struct P(#[allow(unused_tuple_struct_fields)] u8);
 
 pub fn main() {
     let mut count = 0;
index 366ea7d3b3fdaabb3f268704ba8ca36708cf4a30..91958dffcf4df4cc7fc5102b52666897b7c865cb 100644 (file)
@@ -1,9 +1,8 @@
-//~ ERROR cycle detected when computing layout of `S`
+//~ ERROR cycle detected when computing layout of `core::option::Option<S>`
+//~| NOTE ...which requires computing layout of `S`...
 //~| NOTE ...which requires computing layout of `core::option::Option<<S as Mirror>::It>`...
-//~| NOTE ...which requires computing layout of `core::option::Option<S>`...
-//~| NOTE ...which again requires computing layout of `S`, completing the cycle
-
-// build-fail
+//~| NOTE ...which again requires computing layout of `core::option::Option<S>`, completing the cycle
+//~| NOTE cycle used when computing layout of `core::option::Option<<S as Mirror>::It>`
 
 trait Mirror {
     type It: ?Sized;
@@ -14,6 +13,5 @@ impl<T: ?Sized> Mirror for T {
 struct S(Option<<S as Mirror>::It>);
 
 fn main() {
-    //~^ NOTE cycle used when elaborating drops for `main`
     let _s = S(None);
 }
index 5b675dc9f81fc7a6da6be9837e538e9d0ce01491..a75097cdbfbdadad273f41634b3a7298559a210f 100644 (file)
@@ -1,13 +1,9 @@
-error[E0391]: cycle detected when computing layout of `S`
+error[E0391]: cycle detected when computing layout of `core::option::Option<S>`
    |
+   = note: ...which requires computing layout of `S`...
    = note: ...which requires computing layout of `core::option::Option<<S as Mirror>::It>`...
-   = note: ...which requires computing layout of `core::option::Option<S>`...
-   = note: ...which again requires computing layout of `S`, completing the cycle
-note: cycle used when elaborating drops for `main`
-  --> $DIR/issue-26548-recursion-via-normalize.rs:16:1
-   |
-LL | fn main() {
-   | ^^^^^^^^^
+   = note: ...which again requires computing layout of `core::option::Option<S>`, completing the cycle
+   = note: cycle used when computing layout of `core::option::Option<<S as Mirror>::It>`
 
 error: aborting due to previous error
 
index 360557fb5201daca66ff89e027f140d566efcbe3..f78f1d822bf608849b0343cfa8189c53ea035888 100644 (file)
@@ -23,6 +23,9 @@ LL |         std::intrinsics::unlikely,
    |
    = note: expected fn item `extern "rust-intrinsic" fn(_) -> _ {likely}`
               found fn item `extern "rust-intrinsic" fn(_) -> _ {unlikely}`
+   = note: different `fn` items always have unique types, even if their signatures are the same
+   = help: change the expected type to be function pointer `extern "rust-intrinsic" fn(bool) -> bool`
+   = help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `likely as extern "rust-intrinsic" fn(bool) -> bool`
 
 error: aborting due to 3 previous errors
 
index f839bd4243229d7d46109ab44bf0e883ae51b31c..20aeb7b995a6195b46c2b27429e55a0c8531c1e1 100644 (file)
@@ -8,8 +8,14 @@ LL | impl dyn ToNbt<Self> {}
 note: cycle used when collecting item types in top-level module
   --> $DIR/issue-23305.rs:1:1
    |
-LL | pub trait ToNbt<T> {
-   | ^^^^^^^^^^^^^^^^^^
+LL | / pub trait ToNbt<T> {
+LL | |     fn new(val: T) -> Self;
+LL | | }
+LL | |
+...  |
+LL | |
+LL | | fn main() {}
+   | |____________^
 
 error: aborting due to previous error
 
index 96c1869b4e726c3aaf679ac7c1d95be863cb7d06..c805c9eb125c882638b94eb3c7d7b20ee7072ff0 100644 (file)
@@ -31,6 +31,10 @@ LL |         Opts::A(ref i) | Opts::B(i) => {}
    |                 first introduced with type `&isize` here
    |
    = note: in the same arm, a binding must have the same type in all alternatives
+help: consider adding `ref`
+   |
+LL |         Opts::A(ref i) | Opts::B(ref i) => {}
+   |                                  +++
 
 error[E0308]: mismatched types
   --> $DIR/resolve-inconsistent-binding-mode.rs:18:34
@@ -43,6 +47,10 @@ LL |         Opts::A(ref i) | Opts::B(i) => {}
    |                 first introduced with type `&isize` here
    |
    = note: in the same arm, a binding must have the same type in all alternatives
+help: consider adding `ref`
+   |
+LL |         Opts::A(ref i) | Opts::B(ref i) => {}
+   |                                  +++
 
 error[E0308]: mismatched types
   --> $DIR/resolve-inconsistent-binding-mode.rs:27:38
index 989d2d4523099c4ba2066f1fd82e3caa866e3645..9a40b20346c95e78539e07793260769e3a9f6f48 100644 (file)
@@ -23,6 +23,7 @@ fn main() {
         //~| ERROR mismatched types
         //~| ERROR variable `c` is not bound in all patterns
         //~| HELP if you meant to match on unit variant `E::A`, use the full path in the pattern
+        //~| HELP consider removing `ref`
     }
 
     let z = (10, 20);
index 9de191f7d327ac40294239a30b81795d05f134b3..773c9f6cd1114800768a1c43b55f97210b5ff78b 100644 (file)
@@ -55,7 +55,7 @@ LL |         (A, B) | (ref B, c) | (c, A) => ()
    |             first binding
 
 error[E0408]: variable `CONST1` is not bound in all patterns
-  --> $DIR/resolve-inconsistent-names.rs:30:23
+  --> $DIR/resolve-inconsistent-names.rs:31:23
    |
 LL |         (CONST1, _) | (_, Const2) => ()
    |          ------       ^^^^^^^^^^^ pattern doesn't bind `CONST1`
@@ -69,7 +69,7 @@ LL |     const CONST1: usize = 10;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ not accessible
 
 error[E0408]: variable `Const2` is not bound in all patterns
-  --> $DIR/resolve-inconsistent-names.rs:30:9
+  --> $DIR/resolve-inconsistent-names.rs:31:9
    |
 LL |         (CONST1, _) | (_, Const2) => ()
    |         ^^^^^^^^^^^       ------ variable not in all patterns
@@ -92,6 +92,11 @@ LL |         (A, B) | (ref B, c) | (c, A) => ()
    |             first introduced with type `E` here
    |
    = note: in the same arm, a binding must have the same type in all alternatives
+help: consider removing `ref`
+   |
+LL -         (A, B) | (ref B, c) | (c, A) => ()
+LL +         (A, B) | (B, c) | (c, A) => ()
+   |
 
 error: aborting due to 9 previous errors
 
index c6d7166e74065bde8a2c5ca1fc42619a8193a632..1914e15549307227e1f5da5d06f8c0ff60af84a6 100644 (file)
@@ -5,7 +5,7 @@
 
 #![warn(pointer_structural_match)]
 
-struct NoDerive(i32);
+struct NoDerive(#[allow(unused_tuple_struct_fields)] i32);
 
 // This impl makes NoDerive irreflexive
 // (which doesn't matter here because `<*const T>::eq` won't recur on `T`).
index cc7ea6cde8d7f3bea786f4460fc9a2f0197dac34..e713b003b0059c98ee6fc8e1763b13e45e61a5dc 100644 (file)
@@ -5,7 +5,7 @@
 
 #![warn(pointer_structural_match)]
 
-struct NoDerive(i32);
+struct NoDerive(#[allow(unused_tuple_struct_fields)] i32);
 
 // This impl makes NoDerive irreflexive
 // (which doesn't matter here because `<*const T>::eq` won't recur on `T`).
index 86db09cc08fc8a0194f16c0dc92ba14fbb1ab02f..04da14c54194ae0d8dcdf4c731db6b0e532863b1 100644 (file)
@@ -5,7 +5,7 @@
 
 #![warn(pointer_structural_match)]
 
-struct NoDerive(i32);
+struct NoDerive(#[allow(unused_tuple_struct_fields)] i32);
 
 // This impl makes NoDerive irreflexive
 // (which doesn't matter here because `<*const T>::eq` won't recur on `T`).
index 99c574d0780457345a05e8d9387df403d39b142d..8313c25e7538db40ec230df49388cfb6625d7fd2 100644 (file)
@@ -5,7 +5,7 @@
 
 #![warn(pointer_structural_match)]
 
-struct NoDerive(i32);
+struct NoDerive(#[allow(unused_tuple_struct_fields)] i32);
 
 // This impl makes NoDerive irreflexive
 // (which doesn't matter here because `<*const T>::eq` won't recur on `T`).
index 4a8a09493798eb33ae463005dfef96d95b74ecbe..7623839fdd13a9ce270112f53e006d5b5cad9c49 100644 (file)
@@ -5,7 +5,7 @@
 //
 // See discussion on rust-lang/rust#62307 and rust-lang/rust#62339
 
-struct NoDerive(i32);
+struct NoDerive(#[allow(unused_tuple_struct_fields)] i32);
 
 // This impl makes NoDerive irreflexive.
 impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
index fe62774d220d4efe825d320b60cab4a143c9278c..894739ff705c317f50ae7b94cd8f519f49551d73 100644 (file)
@@ -7,7 +7,7 @@
 #![warn(indirect_structural_match)]
 // run-pass
 
-struct NoDerive(i32);
+struct NoDerive(#[allow(unused_tuple_struct_fields)] i32);
 
 // This impl makes NoDerive irreflexive.
 impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
index c3a30674ea3878b766306c5692bad45266ca35ae..1699dae46247e748f16e7804b04639f941eb5123 100644 (file)
@@ -7,7 +7,7 @@
 #![warn(indirect_structural_match)]
 // run-pass
 
-struct NoDerive(i32);
+struct NoDerive(#[allow(unused_tuple_struct_fields)] i32);
 
 // This impl makes NoDerive irreflexive.
 impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
index 4d0e80d5af31235f237855afa3839a5f2b0125e2..2672bdd9e5669dd8695ccc30d0175dc599b6230e 100644 (file)
@@ -7,7 +7,7 @@
 #![warn(indirect_structural_match)]
 // run-pass
 
-struct NoDerive(i32);
+struct NoDerive(#[allow(unused_tuple_struct_fields)] i32);
 
 // This impl makes NoDerive irreflexive.
 impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
index 432f196ec81279fd82854e5449661beef1004fa8..3489995ae71a01ad99f13f8f9735fe65d34f35fc 100644 (file)
@@ -7,7 +7,7 @@
 #![warn(indirect_structural_match)]
 // run-pass
 
-struct NoDerive(i32);
+struct NoDerive(#[allow(unused_tuple_struct_fields)] i32);
 
 // This impl makes NoDerive irreflexive.
 impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
index d9657bac776850916b972c148ce2b56bb18421e2..5dce8180f59206ecd1968ebdb635cdacee400c36 100644 (file)
@@ -1,5 +1,4 @@
 // aux-build:enums.rs
-// run-pass
 
 extern crate enums;
 
@@ -7,11 +6,6 @@
 
 fn main() {
     let e = FieldLessWithNonExhaustiveVariant::default();
-    // FIXME: https://github.com/rust-lang/rust/issues/91161
-    // This `as` cast *should* be an error, since it would fail
-    // if the non-exhaustive variant got fields.  But today it
-    // doesn't.  The fix for that will update this test to
-    // show an error (and not be run-pass any more).
-    let d = e as u8;
+    let d = e as u8; //~ ERROR casting `FieldLessWithNonExhaustiveVariant` as `u8` is invalid [E0606]
     assert_eq!(d, 0);
 }
diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum-as-cast.stderr b/src/test/ui/rfc-2008-non-exhaustive/enum-as-cast.stderr
new file mode 100644 (file)
index 0000000..a61dcf8
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0606]: casting `FieldLessWithNonExhaustiveVariant` as `u8` is invalid
+  --> $DIR/enum-as-cast.rs:9:13
+   |
+LL |     let d = e as u8;
+   |             ^^^^^^^
+   |
+   = note: cannot cast an enum with a non-exhaustive variant when it's defined in another crate
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0606`.
index 689fdcebbfba4d4391a904bab317954887ee62e3..0fe50932b4bbc0c5724bb43fe231db4260c31d5b 100644 (file)
@@ -32,6 +32,8 @@ fn _if_let_guard() {
         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
         //~^ ERROR `if let` guards are experimental
         //~| ERROR expected expression, found `let` statement
+        //~| ERROR expected expression, found `let` statement
+        //~| ERROR expected expression, found `let` statement
 
         () if let Range { start: _, end: _ } = (true..true) && false => {}
         //~^ ERROR `if let` guards are experimental
index b61041050a8a1bd7908a5ecb88d207e6b6d0ad8e..35db84a6cb79ab55cdd6373f7dc827f6adb7461f 100644 (file)
@@ -41,19 +41,31 @@ LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
    |                                          ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/feature-gate.rs:52:16
+  --> $DIR/feature-gate.rs:32:55
+   |
+LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
+   |                                                       ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/feature-gate.rs:32:68
+   |
+LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
+   |                                                                    ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/feature-gate.rs:54:16
    |
 LL |     use_expr!((let 0 = 1 && 0 == 0));
    |                ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/feature-gate.rs:54:16
+  --> $DIR/feature-gate.rs:56:16
    |
 LL |     use_expr!((let 0 = 1));
    |                ^^^
 
 error: no rules expected the token `let`
-  --> $DIR/feature-gate.rs:62:15
+  --> $DIR/feature-gate.rs:64:15
    |
 LL |     macro_rules! use_expr {
    |     --------------------- when calling this macro
@@ -102,7 +114,7 @@ LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
    = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
 
 error[E0658]: `if let` guards are experimental
-  --> $DIR/feature-gate.rs:36:12
+  --> $DIR/feature-gate.rs:38:12
    |
 LL |         () if let Range { start: _, end: _ } = (true..true) && false => {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -112,7 +124,7 @@ LL |         () if let Range { start: _, end: _ } = (true..true) && false => {}
    = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
 
 error[E0658]: `if let` guards are experimental
-  --> $DIR/feature-gate.rs:58:12
+  --> $DIR/feature-gate.rs:60:12
    |
 LL |         () if let 0 = 1 => {}
    |            ^^^^^^^^^^^^
@@ -121,6 +133,6 @@ LL |         () if let 0 = 1 => {}
    = help: add `#![feature(if_let_guard)]` to the crate attributes to enable
    = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
 
-error: aborting due to 16 previous errors
+error: aborting due to 18 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
index a89c58785e3586979dfdb699bf202c206a304fe4..e8f1ff9c3fdd251b50bf73993c4dd33126f775e4 100644 (file)
@@ -51,6 +51,8 @@ fn _if() {
     //~| ERROR `let` expressions are not supported here
     //~| ERROR `let` expressions are not supported here
     //~| ERROR expected expression, found `let` statement
+    //~| ERROR expected expression, found `let` statement
+    //~| ERROR expected expression, found `let` statement
 }
 
 fn _while() {
@@ -81,6 +83,8 @@ fn _while() {
     //~| ERROR `let` expressions are not supported here
     //~| ERROR `let` expressions are not supported here
     //~| ERROR expected expression, found `let` statement
+    //~| ERROR expected expression, found `let` statement
+    //~| ERROR expected expression, found `let` statement
 }
 
 fn _macros() {
@@ -146,6 +150,7 @@ fn _check_try_binds_tighter() -> Result<(), ()> {
     //~| ERROR expected expression, found `let` statement
     if true || (true && let 0 = 0) {}
     //~^ ERROR `let` expressions are not supported here
+    //~| ERROR expected expression, found `let` statement
 
     let mut x = true;
     if x = let 0 = 0 {}
@@ -237,6 +242,7 @@ fn _check_try_binds_tighter() -> Result<(), ()> {
     //~| ERROR expected expression, found `let` statement
     while true || (true && let 0 = 0) {}
     //~^ ERROR `let` expressions are not supported here
+    //~| ERROR expected expression, found `let` statement
 
     let mut x = true;
     while x = let 0 = 0 {}
@@ -388,16 +394,19 @@ fn inside_const_generic_arguments() {
     if let A::<{
         true && let 1 = 1
         //~^ ERROR `let` expressions are not supported here
+        //~| ERROR expected expression, found `let` statement
     }>::O = 5 {}
 
     while let A::<{
         true && let 1 = 1
         //~^ ERROR `let` expressions are not supported here
+        //~| ERROR expected expression, found `let` statement
     }>::O = 5 {}
 
     if A::<{
         true && let 1 = 1
         //~^ ERROR `let` expressions are not supported here
+        //~| ERROR expected expression, found `let` statement
     }>::O == 5 {}
 
     // In the cases above we have `ExprKind::Block` to help us out.
@@ -409,7 +418,8 @@ fn inside_const_generic_arguments() {
     if A::<
         true && let 1 = 1
         //~^ ERROR `let` expressions are not supported here
-        //~| ERROR  expressions must be enclosed in braces
+        //~| ERROR expressions must be enclosed in braces
+        //~| ERROR expected expression, found `let` statement
     >::O == 5 {}
 }
 
index 5e5289f169331a74a419101ab90b268a82add065..d5d82166a4ac4c5104cec8c2560ec370aa824def 100644 (file)
@@ -41,313 +41,373 @@ LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                   ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:57:12
+  --> $DIR/disallowed-positions.rs:49:48
+   |
+LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                                ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:49:61
+   |
+LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                                             ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:59:12
    |
 LL |     while (let 0 = 1) {}
    |            ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:61:14
+  --> $DIR/disallowed-positions.rs:63:14
    |
 LL |     while (((let 0 = 1))) {}
    |              ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:65:12
+  --> $DIR/disallowed-positions.rs:67:12
    |
 LL |     while (let 0 = 1) && true {}
    |            ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:69:20
+  --> $DIR/disallowed-positions.rs:71:20
    |
 LL |     while true && (let 0 = 1) {}
    |                    ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:73:12
+  --> $DIR/disallowed-positions.rs:75:12
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
    |            ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:73:27
+  --> $DIR/disallowed-positions.rs:75:27
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
    |                           ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:79:38
+  --> $DIR/disallowed-positions.rs:81:38
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                      ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:110:9
+  --> $DIR/disallowed-positions.rs:81:51
+   |
+LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                                   ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:81:64
+   |
+LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                                                ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:114:9
    |
 LL |     if &let 0 = 0 {}
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:115:9
+  --> $DIR/disallowed-positions.rs:119:9
    |
 LL |     if !let 0 = 0 {}
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:118:9
+  --> $DIR/disallowed-positions.rs:122:9
    |
 LL |     if *let 0 = 0 {}
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:122:9
+  --> $DIR/disallowed-positions.rs:126:9
    |
 LL |     if -let 0 = 0 {}
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:132:9
+  --> $DIR/disallowed-positions.rs:136:9
    |
 LL |     if (let 0 = 0)? {}
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:138:16
+  --> $DIR/disallowed-positions.rs:142:16
    |
 LL |     if true || let 0 = 0 {}
    |                ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:141:17
+  --> $DIR/disallowed-positions.rs:145:17
    |
 LL |     if (true || let 0 = 0) {}
    |                 ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:144:25
+  --> $DIR/disallowed-positions.rs:148:25
    |
 LL |     if true && (true || let 0 = 0) {}
    |                         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:151:12
+  --> $DIR/disallowed-positions.rs:151:25
+   |
+LL |     if true || (true && let 0 = 0) {}
+   |                         ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:156:12
    |
 LL |     if x = let 0 = 0 {}
    |            ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:156:15
+  --> $DIR/disallowed-positions.rs:161:15
    |
 LL |     if true..(let 0 = 0) {}
    |               ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:160:11
+  --> $DIR/disallowed-positions.rs:165:11
    |
 LL |     if ..(let 0 = 0) {}
    |           ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:164:9
+  --> $DIR/disallowed-positions.rs:169:9
    |
 LL |     if (let 0 = 0).. {}
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:195:19
+  --> $DIR/disallowed-positions.rs:200:19
    |
 LL |     if let true = let true = true {}
    |                   ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:201:12
+  --> $DIR/disallowed-positions.rs:206:12
    |
 LL |     while &let 0 = 0 {}
    |            ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:206:12
+  --> $DIR/disallowed-positions.rs:211:12
    |
 LL |     while !let 0 = 0 {}
    |            ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:209:12
+  --> $DIR/disallowed-positions.rs:214:12
    |
 LL |     while *let 0 = 0 {}
    |            ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:213:12
+  --> $DIR/disallowed-positions.rs:218:12
    |
 LL |     while -let 0 = 0 {}
    |            ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:223:12
+  --> $DIR/disallowed-positions.rs:228:12
    |
 LL |     while (let 0 = 0)? {}
    |            ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:229:19
+  --> $DIR/disallowed-positions.rs:234:19
    |
 LL |     while true || let 0 = 0 {}
    |                   ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:232:20
+  --> $DIR/disallowed-positions.rs:237:20
    |
 LL |     while (true || let 0 = 0) {}
    |                    ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:235:28
+  --> $DIR/disallowed-positions.rs:240:28
    |
 LL |     while true && (true || let 0 = 0) {}
    |                            ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:242:15
+  --> $DIR/disallowed-positions.rs:243:28
+   |
+LL |     while true || (true && let 0 = 0) {}
+   |                            ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:248:15
    |
 LL |     while x = let 0 = 0 {}
    |               ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:247:18
+  --> $DIR/disallowed-positions.rs:253:18
    |
 LL |     while true..(let 0 = 0) {}
    |                  ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:251:14
+  --> $DIR/disallowed-positions.rs:257:14
    |
 LL |     while ..(let 0 = 0) {}
    |              ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:255:12
+  --> $DIR/disallowed-positions.rs:261:12
    |
 LL |     while (let 0 = 0).. {}
    |            ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:286:22
+  --> $DIR/disallowed-positions.rs:292:22
    |
 LL |     while let true = let true = true {}
    |                      ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:302:6
+  --> $DIR/disallowed-positions.rs:308:6
    |
 LL |     &let 0 = 0;
    |      ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:306:6
+  --> $DIR/disallowed-positions.rs:312:6
    |
 LL |     !let 0 = 0;
    |      ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:309:6
+  --> $DIR/disallowed-positions.rs:315:6
    |
 LL |     *let 0 = 0;
    |      ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:313:6
+  --> $DIR/disallowed-positions.rs:319:6
    |
 LL |     -let 0 = 0;
    |      ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:323:6
+  --> $DIR/disallowed-positions.rs:329:6
    |
 LL |     (let 0 = 0)?;
    |      ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:329:13
+  --> $DIR/disallowed-positions.rs:335:13
    |
 LL |     true || let 0 = 0;
    |             ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:332:14
+  --> $DIR/disallowed-positions.rs:338:14
    |
 LL |     (true || let 0 = 0);
    |              ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:335:22
+  --> $DIR/disallowed-positions.rs:341:22
    |
 LL |     true && (true || let 0 = 0);
    |                      ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:340:9
+  --> $DIR/disallowed-positions.rs:346:9
    |
 LL |     x = let 0 = 0;
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:344:12
+  --> $DIR/disallowed-positions.rs:350:12
    |
 LL |     true..(let 0 = 0);
    |            ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:347:8
+  --> $DIR/disallowed-positions.rs:353:8
    |
 LL |     ..(let 0 = 0);
    |        ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:350:6
+  --> $DIR/disallowed-positions.rs:356:6
    |
 LL |     (let 0 = 0)..;
    |      ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:354:6
+  --> $DIR/disallowed-positions.rs:360:6
    |
 LL |     (let Range { start: _, end: _ } = true..true || false);
    |      ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:359:6
+  --> $DIR/disallowed-positions.rs:365:6
    |
 LL |     (let true = let true = true);
    |      ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:359:17
+  --> $DIR/disallowed-positions.rs:365:17
    |
 LL |     (let true = let true = true);
    |                 ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:366:25
+  --> $DIR/disallowed-positions.rs:372:25
    |
 LL |         let x = true && let y = 1;
    |                         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:372:19
+  --> $DIR/disallowed-positions.rs:378:19
    |
 LL |         [1, 2, 3][let _ = ()]
    |                   ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:377:6
+  --> $DIR/disallowed-positions.rs:383:6
    |
 LL |     &let 0 = 0
    |      ^^^
 
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:395:17
+   |
+LL |         true && let 1 = 1
+   |                 ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:401:17
+   |
+LL |         true && let 1 = 1
+   |                 ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:407:17
+   |
+LL |         true && let 1 = 1
+   |                 ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:419:17
+   |
+LL |         true && let 1 = 1
+   |                 ^^^
+
 error: expressions must be enclosed in braces to be used as const generic arguments
-  --> $DIR/disallowed-positions.rs:410:9
+  --> $DIR/disallowed-positions.rs:419:9
    |
 LL |         true && let 1 = 1
    |         ^^^^^^^^^^^^^^^^^
@@ -358,97 +418,97 @@ LL |         { true && let 1 = 1 }
    |         +                   +
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:419:9
+  --> $DIR/disallowed-positions.rs:429:9
    |
 LL |     if (let Some(a) = opt && true) {
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:424:9
+  --> $DIR/disallowed-positions.rs:434:9
    |
 LL |     if (let Some(a) = opt) && true {
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:428:9
+  --> $DIR/disallowed-positions.rs:438:9
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:428:32
+  --> $DIR/disallowed-positions.rs:438:32
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |                                ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:437:9
+  --> $DIR/disallowed-positions.rs:447:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:437:31
+  --> $DIR/disallowed-positions.rs:447:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |                               ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:443:9
+  --> $DIR/disallowed-positions.rs:453:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:443:31
+  --> $DIR/disallowed-positions.rs:453:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |                               ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:449:9
+  --> $DIR/disallowed-positions.rs:459:9
    |
 LL |     if (let Some(a) = opt && (true)) && true {
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:466:22
+  --> $DIR/disallowed-positions.rs:476:22
    |
 LL |     let x = (true && let y = 1);
    |                      ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:471:20
+  --> $DIR/disallowed-positions.rs:481:20
    |
 LL |         ([1, 2, 3][let _ = ()])
    |                    ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:475:20
+  --> $DIR/disallowed-positions.rs:485:20
    |
 LL |     #[cfg(FALSE)] (let 0 = 1);
    |                    ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:93:16
+  --> $DIR/disallowed-positions.rs:97:16
    |
 LL |     use_expr!((let 0 = 1 && 0 == 0));
    |                ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:97:16
+  --> $DIR/disallowed-positions.rs:101:16
    |
 LL |     use_expr!((let 0 = 1));
    |                ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:101:23
+  --> $DIR/disallowed-positions.rs:105:23
    |
 LL |     use_expr!(true && let 0 = 1);
    |                       ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:105:17
+  --> $DIR/disallowed-positions.rs:109:17
    |
 LL |     noop_expr!((let 0 = 1));
    |                 ^^^
@@ -571,176 +631,176 @@ LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:57:12
+  --> $DIR/disallowed-positions.rs:59:12
    |
 LL |     while (let 0 = 1) {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:57:12
+  --> $DIR/disallowed-positions.rs:59:12
    |
 LL |     while (let 0 = 1) {}
    |            ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:61:14
+  --> $DIR/disallowed-positions.rs:63:14
    |
 LL |     while (((let 0 = 1))) {}
    |              ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:61:14
+  --> $DIR/disallowed-positions.rs:63:14
    |
 LL |     while (((let 0 = 1))) {}
    |              ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:65:12
+  --> $DIR/disallowed-positions.rs:67:12
    |
 LL |     while (let 0 = 1) && true {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:65:12
+  --> $DIR/disallowed-positions.rs:67:12
    |
 LL |     while (let 0 = 1) && true {}
    |            ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:69:20
+  --> $DIR/disallowed-positions.rs:71:20
    |
 LL |     while true && (let 0 = 1) {}
    |                    ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:69:20
+  --> $DIR/disallowed-positions.rs:71:20
    |
 LL |     while true && (let 0 = 1) {}
    |                    ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:73:12
+  --> $DIR/disallowed-positions.rs:75:12
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:73:12
+  --> $DIR/disallowed-positions.rs:75:12
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
    |            ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:73:27
+  --> $DIR/disallowed-positions.rs:75:27
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
    |                           ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:73:27
+  --> $DIR/disallowed-positions.rs:75:27
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
    |                           ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:79:38
+  --> $DIR/disallowed-positions.rs:81:38
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                      ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:79:38
+  --> $DIR/disallowed-positions.rs:81:38
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:79:51
+  --> $DIR/disallowed-positions.rs:81:51
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                                   ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:79:38
+  --> $DIR/disallowed-positions.rs:81:38
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:79:64
+  --> $DIR/disallowed-positions.rs:81:64
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                                                ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:79:38
+  --> $DIR/disallowed-positions.rs:81:38
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:93:16
+  --> $DIR/disallowed-positions.rs:97:16
    |
 LL |     use_expr!((let 0 = 1 && 0 == 0));
    |                ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:93:16
+  --> $DIR/disallowed-positions.rs:97:16
    |
 LL |     use_expr!((let 0 = 1 && 0 == 0));
    |                ^^^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:93:16
+  --> $DIR/disallowed-positions.rs:97:16
    |
 LL |     use_expr!((let 0 = 1 && 0 == 0));
    |                ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:93:16
+  --> $DIR/disallowed-positions.rs:97:16
    |
 LL |     use_expr!((let 0 = 1 && 0 == 0));
    |                ^^^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:97:16
+  --> $DIR/disallowed-positions.rs:101:16
    |
 LL |     use_expr!((let 0 = 1));
    |                ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:97:16
+  --> $DIR/disallowed-positions.rs:101:16
    |
 LL |     use_expr!((let 0 = 1));
    |                ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:97:16
+  --> $DIR/disallowed-positions.rs:101:16
    |
 LL |     use_expr!((let 0 = 1));
    |                ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:97:16
+  --> $DIR/disallowed-positions.rs:101:16
    |
 LL |     use_expr!((let 0 = 1));
    |                ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:110:9
+  --> $DIR/disallowed-positions.rs:114:9
    |
 LL |     if &let 0 = 0 {}
    |         ^^^^^^^^^
@@ -748,7 +808,7 @@ LL |     if &let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:115:9
+  --> $DIR/disallowed-positions.rs:119:9
    |
 LL |     if !let 0 = 0 {}
    |         ^^^^^^^^^
@@ -756,7 +816,7 @@ LL |     if !let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:118:9
+  --> $DIR/disallowed-positions.rs:122:9
    |
 LL |     if *let 0 = 0 {}
    |         ^^^^^^^^^
@@ -764,7 +824,7 @@ LL |     if *let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:122:9
+  --> $DIR/disallowed-positions.rs:126:9
    |
 LL |     if -let 0 = 0 {}
    |         ^^^^^^^^^
@@ -772,72 +832,72 @@ LL |     if -let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:132:9
+  --> $DIR/disallowed-positions.rs:136:9
    |
 LL |     if (let 0 = 0)? {}
    |         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:132:9
+  --> $DIR/disallowed-positions.rs:136:9
    |
 LL |     if (let 0 = 0)? {}
    |         ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:138:16
+  --> $DIR/disallowed-positions.rs:142:16
    |
 LL |     if true || let 0 = 0 {}
    |                ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `||` operators are not supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:138:13
+  --> $DIR/disallowed-positions.rs:142:13
    |
 LL |     if true || let 0 = 0 {}
    |             ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:141:17
+  --> $DIR/disallowed-positions.rs:145:17
    |
 LL |     if (true || let 0 = 0) {}
    |                 ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `||` operators are not supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:141:14
+  --> $DIR/disallowed-positions.rs:145:14
    |
 LL |     if (true || let 0 = 0) {}
    |              ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:144:25
+  --> $DIR/disallowed-positions.rs:148:25
    |
 LL |     if true && (true || let 0 = 0) {}
    |                         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `||` operators are not supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:144:22
+  --> $DIR/disallowed-positions.rs:148:22
    |
 LL |     if true && (true || let 0 = 0) {}
    |                      ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:147:25
+  --> $DIR/disallowed-positions.rs:151:25
    |
 LL |     if true || (true && let 0 = 0) {}
    |                         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:147:17
+  --> $DIR/disallowed-positions.rs:151:17
    |
 LL |     if true || (true && let 0 = 0) {}
    |                 ^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:151:12
+  --> $DIR/disallowed-positions.rs:156:12
    |
 LL |     if x = let 0 = 0 {}
    |            ^^^^^^^^^
@@ -845,46 +905,46 @@ LL |     if x = let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:156:15
+  --> $DIR/disallowed-positions.rs:161:15
    |
 LL |     if true..(let 0 = 0) {}
    |               ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:156:15
+  --> $DIR/disallowed-positions.rs:161:15
    |
 LL |     if true..(let 0 = 0) {}
    |               ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:160:11
+  --> $DIR/disallowed-positions.rs:165:11
    |
 LL |     if ..(let 0 = 0) {}
    |           ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:160:11
+  --> $DIR/disallowed-positions.rs:165:11
    |
 LL |     if ..(let 0 = 0) {}
    |           ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:164:9
+  --> $DIR/disallowed-positions.rs:169:9
    |
 LL |     if (let 0 = 0).. {}
    |         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:164:9
+  --> $DIR/disallowed-positions.rs:169:9
    |
 LL |     if (let 0 = 0).. {}
    |         ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:170:8
+  --> $DIR/disallowed-positions.rs:175:8
    |
 LL |     if let Range { start: _, end: _ } = true..true && false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -892,7 +952,7 @@ LL |     if let Range { start: _, end: _ } = true..true && false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:174:8
+  --> $DIR/disallowed-positions.rs:179:8
    |
 LL |     if let Range { start: _, end: _ } = true..true || false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -900,7 +960,7 @@ LL |     if let Range { start: _, end: _ } = true..true || false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:181:8
+  --> $DIR/disallowed-positions.rs:186:8
    |
 LL |     if let Range { start: F, end } = F..|| true {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -908,7 +968,7 @@ LL |     if let Range { start: F, end } = F..|| true {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:189:8
+  --> $DIR/disallowed-positions.rs:194:8
    |
 LL |     if let Range { start: true, end } = t..&&false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -916,7 +976,7 @@ LL |     if let Range { start: true, end } = t..&&false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:195:19
+  --> $DIR/disallowed-positions.rs:200:19
    |
 LL |     if let true = let true = true {}
    |                   ^^^^^^^^^^^^^^^
@@ -924,7 +984,7 @@ LL |     if let true = let true = true {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:201:12
+  --> $DIR/disallowed-positions.rs:206:12
    |
 LL |     while &let 0 = 0 {}
    |            ^^^^^^^^^
@@ -932,7 +992,7 @@ LL |     while &let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:206:12
+  --> $DIR/disallowed-positions.rs:211:12
    |
 LL |     while !let 0 = 0 {}
    |            ^^^^^^^^^
@@ -940,7 +1000,7 @@ LL |     while !let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:209:12
+  --> $DIR/disallowed-positions.rs:214:12
    |
 LL |     while *let 0 = 0 {}
    |            ^^^^^^^^^
@@ -948,7 +1008,7 @@ LL |     while *let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:213:12
+  --> $DIR/disallowed-positions.rs:218:12
    |
 LL |     while -let 0 = 0 {}
    |            ^^^^^^^^^
@@ -956,72 +1016,72 @@ LL |     while -let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:223:12
+  --> $DIR/disallowed-positions.rs:228:12
    |
 LL |     while (let 0 = 0)? {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:223:12
+  --> $DIR/disallowed-positions.rs:228:12
    |
 LL |     while (let 0 = 0)? {}
    |            ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:229:19
+  --> $DIR/disallowed-positions.rs:234:19
    |
 LL |     while true || let 0 = 0 {}
    |                   ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `||` operators are not supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:229:16
+  --> $DIR/disallowed-positions.rs:234:16
    |
 LL |     while true || let 0 = 0 {}
    |                ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:232:20
+  --> $DIR/disallowed-positions.rs:237:20
    |
 LL |     while (true || let 0 = 0) {}
    |                    ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `||` operators are not supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:232:17
+  --> $DIR/disallowed-positions.rs:237:17
    |
 LL |     while (true || let 0 = 0) {}
    |                 ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:235:28
+  --> $DIR/disallowed-positions.rs:240:28
    |
 LL |     while true && (true || let 0 = 0) {}
    |                            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `||` operators are not supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:235:25
+  --> $DIR/disallowed-positions.rs:240:25
    |
 LL |     while true && (true || let 0 = 0) {}
    |                         ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:238:28
+  --> $DIR/disallowed-positions.rs:243:28
    |
 LL |     while true || (true && let 0 = 0) {}
    |                            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:238:20
+  --> $DIR/disallowed-positions.rs:243:20
    |
 LL |     while true || (true && let 0 = 0) {}
    |                    ^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:242:15
+  --> $DIR/disallowed-positions.rs:248:15
    |
 LL |     while x = let 0 = 0 {}
    |               ^^^^^^^^^
@@ -1029,46 +1089,46 @@ LL |     while x = let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:247:18
+  --> $DIR/disallowed-positions.rs:253:18
    |
 LL |     while true..(let 0 = 0) {}
    |                  ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:247:18
+  --> $DIR/disallowed-positions.rs:253:18
    |
 LL |     while true..(let 0 = 0) {}
    |                  ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:251:14
+  --> $DIR/disallowed-positions.rs:257:14
    |
 LL |     while ..(let 0 = 0) {}
    |              ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:251:14
+  --> $DIR/disallowed-positions.rs:257:14
    |
 LL |     while ..(let 0 = 0) {}
    |              ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:255:12
+  --> $DIR/disallowed-positions.rs:261:12
    |
 LL |     while (let 0 = 0).. {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:255:12
+  --> $DIR/disallowed-positions.rs:261:12
    |
 LL |     while (let 0 = 0).. {}
    |            ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:261:11
+  --> $DIR/disallowed-positions.rs:267:11
    |
 LL |     while let Range { start: _, end: _ } = true..true && false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1076,7 +1136,7 @@ LL |     while let Range { start: _, end: _ } = true..true && false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:265:11
+  --> $DIR/disallowed-positions.rs:271:11
    |
 LL |     while let Range { start: _, end: _ } = true..true || false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1084,7 +1144,7 @@ LL |     while let Range { start: _, end: _ } = true..true || false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:272:11
+  --> $DIR/disallowed-positions.rs:278:11
    |
 LL |     while let Range { start: F, end } = F..|| true {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1092,7 +1152,7 @@ LL |     while let Range { start: F, end } = F..|| true {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:280:11
+  --> $DIR/disallowed-positions.rs:286:11
    |
 LL |     while let Range { start: true, end } = t..&&false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1100,7 +1160,7 @@ LL |     while let Range { start: true, end } = t..&&false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:286:22
+  --> $DIR/disallowed-positions.rs:292:22
    |
 LL |     while let true = let true = true {}
    |                      ^^^^^^^^^^^^^^^
@@ -1108,7 +1168,7 @@ LL |     while let true = let true = true {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:302:6
+  --> $DIR/disallowed-positions.rs:308:6
    |
 LL |     &let 0 = 0;
    |      ^^^^^^^^^
@@ -1116,7 +1176,7 @@ LL |     &let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:306:6
+  --> $DIR/disallowed-positions.rs:312:6
    |
 LL |     !let 0 = 0;
    |      ^^^^^^^^^
@@ -1124,7 +1184,7 @@ LL |     !let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:309:6
+  --> $DIR/disallowed-positions.rs:315:6
    |
 LL |     *let 0 = 0;
    |      ^^^^^^^^^
@@ -1132,7 +1192,7 @@ LL |     *let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:313:6
+  --> $DIR/disallowed-positions.rs:319:6
    |
 LL |     -let 0 = 0;
    |      ^^^^^^^^^
@@ -1140,59 +1200,59 @@ LL |     -let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:323:6
+  --> $DIR/disallowed-positions.rs:329:6
    |
 LL |     (let 0 = 0)?;
    |      ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:323:6
+  --> $DIR/disallowed-positions.rs:329:6
    |
 LL |     (let 0 = 0)?;
    |      ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:329:13
+  --> $DIR/disallowed-positions.rs:335:13
    |
 LL |     true || let 0 = 0;
    |             ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `||` operators are not supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:329:10
+  --> $DIR/disallowed-positions.rs:335:10
    |
 LL |     true || let 0 = 0;
    |          ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:332:14
+  --> $DIR/disallowed-positions.rs:338:14
    |
 LL |     (true || let 0 = 0);
    |              ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `||` operators are not supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:332:11
+  --> $DIR/disallowed-positions.rs:338:11
    |
 LL |     (true || let 0 = 0);
    |           ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:335:22
+  --> $DIR/disallowed-positions.rs:341:22
    |
 LL |     true && (true || let 0 = 0);
    |                      ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `||` operators are not supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:335:19
+  --> $DIR/disallowed-positions.rs:341:19
    |
 LL |     true && (true || let 0 = 0);
    |                   ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:340:9
+  --> $DIR/disallowed-positions.rs:346:9
    |
 LL |     x = let 0 = 0;
    |         ^^^^^^^^^
@@ -1200,46 +1260,46 @@ LL |     x = let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:344:12
+  --> $DIR/disallowed-positions.rs:350:12
    |
 LL |     true..(let 0 = 0);
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:344:12
+  --> $DIR/disallowed-positions.rs:350:12
    |
 LL |     true..(let 0 = 0);
    |            ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:347:8
+  --> $DIR/disallowed-positions.rs:353:8
    |
 LL |     ..(let 0 = 0);
    |        ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:347:8
+  --> $DIR/disallowed-positions.rs:353:8
    |
 LL |     ..(let 0 = 0);
    |        ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:350:6
+  --> $DIR/disallowed-positions.rs:356:6
    |
 LL |     (let 0 = 0)..;
    |      ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:350:6
+  --> $DIR/disallowed-positions.rs:356:6
    |
 LL |     (let 0 = 0)..;
    |      ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:354:6
+  --> $DIR/disallowed-positions.rs:360:6
    |
 LL |     (let Range { start: _, end: _ } = true..true || false);
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1247,20 +1307,20 @@ LL |     (let Range { start: _, end: _ } = true..true || false);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:359:6
+  --> $DIR/disallowed-positions.rs:365:6
    |
 LL |     (let true = let true = true);
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:359:6
+  --> $DIR/disallowed-positions.rs:365:6
    |
 LL |     (let true = let true = true);
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:377:6
+  --> $DIR/disallowed-positions.rs:383:6
    |
 LL |     &let 0 = 0
    |      ^^^^^^^^^
@@ -1268,7 +1328,7 @@ LL |     &let 0 = 0
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:389:17
+  --> $DIR/disallowed-positions.rs:395:17
    |
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
@@ -1276,7 +1336,7 @@ LL |         true && let 1 = 1
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:394:17
+  --> $DIR/disallowed-positions.rs:401:17
    |
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
@@ -1284,7 +1344,7 @@ LL |         true && let 1 = 1
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:399:17
+  --> $DIR/disallowed-positions.rs:407:17
    |
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
@@ -1292,7 +1352,7 @@ LL |         true && let 1 = 1
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:410:17
+  --> $DIR/disallowed-positions.rs:419:17
    |
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
@@ -1300,124 +1360,124 @@ LL |         true && let 1 = 1
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:419:9
+  --> $DIR/disallowed-positions.rs:429:9
    |
 LL |     if (let Some(a) = opt && true) {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:419:9
+  --> $DIR/disallowed-positions.rs:429:9
    |
 LL |     if (let Some(a) = opt && true) {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:424:9
+  --> $DIR/disallowed-positions.rs:434:9
    |
 LL |     if (let Some(a) = opt) && true {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:424:9
+  --> $DIR/disallowed-positions.rs:434:9
    |
 LL |     if (let Some(a) = opt) && true {
    |         ^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:428:9
+  --> $DIR/disallowed-positions.rs:438:9
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:428:9
+  --> $DIR/disallowed-positions.rs:438:9
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |         ^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:428:32
+  --> $DIR/disallowed-positions.rs:438:32
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |                                ^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:428:32
+  --> $DIR/disallowed-positions.rs:438:32
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |                                ^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:437:9
+  --> $DIR/disallowed-positions.rs:447:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:437:9
+  --> $DIR/disallowed-positions.rs:447:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:437:31
+  --> $DIR/disallowed-positions.rs:447:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |                               ^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:437:31
+  --> $DIR/disallowed-positions.rs:447:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |                               ^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:443:9
+  --> $DIR/disallowed-positions.rs:453:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:443:9
+  --> $DIR/disallowed-positions.rs:453:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:443:31
+  --> $DIR/disallowed-positions.rs:453:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |                               ^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:443:31
+  --> $DIR/disallowed-positions.rs:453:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |                               ^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:449:9
+  --> $DIR/disallowed-positions.rs:459:9
    |
 LL |     if (let Some(a) = opt && (true)) && true {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:449:9
+  --> $DIR/disallowed-positions.rs:459:9
    |
 LL |     if (let Some(a) = opt && (true)) && true {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:110:8
+  --> $DIR/disallowed-positions.rs:114:8
    |
 LL |     if &let 0 = 0 {}
    |        ^^^^^^^^^^ expected `bool`, found `&bool`
@@ -1429,19 +1489,19 @@ LL +     if let 0 = 0 {}
    |
 
 error[E0614]: type `bool` cannot be dereferenced
-  --> $DIR/disallowed-positions.rs:118:8
+  --> $DIR/disallowed-positions.rs:122:8
    |
 LL |     if *let 0 = 0 {}
    |        ^^^^^^^^^^
 
 error[E0600]: cannot apply unary operator `-` to type `bool`
-  --> $DIR/disallowed-positions.rs:122:8
+  --> $DIR/disallowed-positions.rs:126:8
    |
 LL |     if -let 0 = 0 {}
    |        ^^^^^^^^^^ cannot apply unary operator `-`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:132:8
+  --> $DIR/disallowed-positions.rs:136:8
    |
 LL |     if (let 0 = 0)? {}
    |        ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
@@ -1449,7 +1509,7 @@ LL |     if (let 0 = 0)? {}
    = help: the trait `Try` is not implemented for `bool`
 
 error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
-  --> $DIR/disallowed-positions.rs:132:19
+  --> $DIR/disallowed-positions.rs:136:19
    |
 LL | / fn nested_within_if_expr() {
 LL | |     if &let 0 = 0 {}
@@ -1466,7 +1526,7 @@ LL | | }
    = help: the trait `FromResidual<_>` is not implemented for `()`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:151:8
+  --> $DIR/disallowed-positions.rs:156:8
    |
 LL |     if x = let 0 = 0 {}
    |        ^^^^^^^^^^^^^ expected `bool`, found `()`
@@ -1477,7 +1537,7 @@ LL |     if x == let 0 = 0 {}
    |          ~~
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:156:8
+  --> $DIR/disallowed-positions.rs:161:8
    |
 LL |     if true..(let 0 = 0) {}
    |        ^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -1486,7 +1546,7 @@ LL |     if true..(let 0 = 0) {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:160:8
+  --> $DIR/disallowed-positions.rs:165:8
    |
 LL |     if ..(let 0 = 0) {}
    |        ^^^^^^^^^^^^^ expected `bool`, found struct `RangeTo`
@@ -1495,7 +1555,7 @@ LL |     if ..(let 0 = 0) {}
             found struct `RangeTo<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:164:8
+  --> $DIR/disallowed-positions.rs:169:8
    |
 LL |     if (let 0 = 0).. {}
    |        ^^^^^^^^^^^^^ expected `bool`, found struct `RangeFrom`
@@ -1504,7 +1564,7 @@ LL |     if (let 0 = 0).. {}
             found struct `RangeFrom<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:170:12
+  --> $DIR/disallowed-positions.rs:175:12
    |
 LL |     if let Range { start: _, end: _ } = true..true && false {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -1515,7 +1575,7 @@ LL |     if let Range { start: _, end: _ } = true..true && false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:170:8
+  --> $DIR/disallowed-positions.rs:175:8
    |
 LL |     if let Range { start: _, end: _ } = true..true && false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -1524,7 +1584,7 @@ LL |     if let Range { start: _, end: _ } = true..true && false {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:174:12
+  --> $DIR/disallowed-positions.rs:179:12
    |
 LL |     if let Range { start: _, end: _ } = true..true || false {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -1535,7 +1595,7 @@ LL |     if let Range { start: _, end: _ } = true..true || false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:174:8
+  --> $DIR/disallowed-positions.rs:179:8
    |
 LL |     if let Range { start: _, end: _ } = true..true || false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -1544,7 +1604,7 @@ LL |     if let Range { start: _, end: _ } = true..true || false {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:181:12
+  --> $DIR/disallowed-positions.rs:186:12
    |
 LL |     if let Range { start: F, end } = F..|| true {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `fn() -> bool`
@@ -1555,20 +1615,20 @@ LL |     if let Range { start: F, end } = F..|| true {}
                   found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:181:41
+  --> $DIR/disallowed-positions.rs:186:41
    |
 LL |     if let Range { start: F, end } = F..|| true {}
    |                                         ^^^^^^^ expected `bool`, found closure
    |
    = note: expected type `bool`
-           found closure `[closure@$DIR/disallowed-positions.rs:181:41: 181:43]`
+           found closure `[closure@$DIR/disallowed-positions.rs:186:41: 186:43]`
 help: use parentheses to call this closure
    |
 LL |     if let Range { start: F, end } = F..(|| true)() {}
    |                                         +       +++
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:181:8
+  --> $DIR/disallowed-positions.rs:186:8
    |
 LL |     if let Range { start: F, end } = F..|| true {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -1577,7 +1637,7 @@ LL |     if let Range { start: F, end } = F..|| true {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:189:12
+  --> $DIR/disallowed-positions.rs:194:12
    |
 LL |     if let Range { start: true, end } = t..&&false {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `&&bool`
@@ -1588,7 +1648,7 @@ LL |     if let Range { start: true, end } = t..&&false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:189:44
+  --> $DIR/disallowed-positions.rs:194:44
    |
 LL |     if let Range { start: true, end } = t..&&false {}
    |                                            ^^^^^^^ expected `bool`, found `&&bool`
@@ -1600,7 +1660,7 @@ LL +     if let Range { start: true, end } = t..false {}
    |
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:189:8
+  --> $DIR/disallowed-positions.rs:194:8
    |
 LL |     if let Range { start: true, end } = t..&&false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -1609,7 +1669,7 @@ LL |     if let Range { start: true, end } = t..&&false {}
             found struct `std::ops::Range<bool>`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:128:20
+  --> $DIR/disallowed-positions.rs:132:20
    |
 LL |         if let 0 = 0? {}
    |                    ^^ the `?` operator cannot be applied to type `{integer}`
@@ -1617,7 +1677,7 @@ LL |         if let 0 = 0? {}
    = help: the trait `Try` is not implemented for `{integer}`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:201:11
+  --> $DIR/disallowed-positions.rs:206:11
    |
 LL |     while &let 0 = 0 {}
    |           ^^^^^^^^^^ expected `bool`, found `&bool`
@@ -1629,19 +1689,19 @@ LL +     while let 0 = 0 {}
    |
 
 error[E0614]: type `bool` cannot be dereferenced
-  --> $DIR/disallowed-positions.rs:209:11
+  --> $DIR/disallowed-positions.rs:214:11
    |
 LL |     while *let 0 = 0 {}
    |           ^^^^^^^^^^
 
 error[E0600]: cannot apply unary operator `-` to type `bool`
-  --> $DIR/disallowed-positions.rs:213:11
+  --> $DIR/disallowed-positions.rs:218:11
    |
 LL |     while -let 0 = 0 {}
    |           ^^^^^^^^^^ cannot apply unary operator `-`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:223:11
+  --> $DIR/disallowed-positions.rs:228:11
    |
 LL |     while (let 0 = 0)? {}
    |           ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
@@ -1649,7 +1709,7 @@ LL |     while (let 0 = 0)? {}
    = help: the trait `Try` is not implemented for `bool`
 
 error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
-  --> $DIR/disallowed-positions.rs:223:22
+  --> $DIR/disallowed-positions.rs:228:22
    |
 LL | / fn nested_within_while_expr() {
 LL | |     while &let 0 = 0 {}
@@ -1666,7 +1726,7 @@ LL | | }
    = help: the trait `FromResidual<_>` is not implemented for `()`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:242:11
+  --> $DIR/disallowed-positions.rs:248:11
    |
 LL |     while x = let 0 = 0 {}
    |           ^^^^^^^^^^^^^ expected `bool`, found `()`
@@ -1677,7 +1737,7 @@ LL |     while x == let 0 = 0 {}
    |             ~~
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:247:11
+  --> $DIR/disallowed-positions.rs:253:11
    |
 LL |     while true..(let 0 = 0) {}
    |           ^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -1686,7 +1746,7 @@ LL |     while true..(let 0 = 0) {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:251:11
+  --> $DIR/disallowed-positions.rs:257:11
    |
 LL |     while ..(let 0 = 0) {}
    |           ^^^^^^^^^^^^^ expected `bool`, found struct `RangeTo`
@@ -1695,7 +1755,7 @@ LL |     while ..(let 0 = 0) {}
             found struct `RangeTo<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:255:11
+  --> $DIR/disallowed-positions.rs:261:11
    |
 LL |     while (let 0 = 0).. {}
    |           ^^^^^^^^^^^^^ expected `bool`, found struct `RangeFrom`
@@ -1704,7 +1764,7 @@ LL |     while (let 0 = 0).. {}
             found struct `RangeFrom<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:261:15
+  --> $DIR/disallowed-positions.rs:267:15
    |
 LL |     while let Range { start: _, end: _ } = true..true && false {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -1715,7 +1775,7 @@ LL |     while let Range { start: _, end: _ } = true..true && false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:261:11
+  --> $DIR/disallowed-positions.rs:267:11
    |
 LL |     while let Range { start: _, end: _ } = true..true && false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -1724,7 +1784,7 @@ LL |     while let Range { start: _, end: _ } = true..true && false {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:265:15
+  --> $DIR/disallowed-positions.rs:271:15
    |
 LL |     while let Range { start: _, end: _ } = true..true || false {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -1735,7 +1795,7 @@ LL |     while let Range { start: _, end: _ } = true..true || false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:265:11
+  --> $DIR/disallowed-positions.rs:271:11
    |
 LL |     while let Range { start: _, end: _ } = true..true || false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -1744,7 +1804,7 @@ LL |     while let Range { start: _, end: _ } = true..true || false {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:272:15
+  --> $DIR/disallowed-positions.rs:278:15
    |
 LL |     while let Range { start: F, end } = F..|| true {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `fn() -> bool`
@@ -1755,20 +1815,20 @@ LL |     while let Range { start: F, end } = F..|| true {}
                   found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:272:44
+  --> $DIR/disallowed-positions.rs:278:44
    |
 LL |     while let Range { start: F, end } = F..|| true {}
    |                                            ^^^^^^^ expected `bool`, found closure
    |
    = note: expected type `bool`
-           found closure `[closure@$DIR/disallowed-positions.rs:272:44: 272:46]`
+           found closure `[closure@$DIR/disallowed-positions.rs:278:44: 278:46]`
 help: use parentheses to call this closure
    |
 LL |     while let Range { start: F, end } = F..(|| true)() {}
    |                                            +       +++
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:272:11
+  --> $DIR/disallowed-positions.rs:278:11
    |
 LL |     while let Range { start: F, end } = F..|| true {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -1777,7 +1837,7 @@ LL |     while let Range { start: F, end } = F..|| true {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:280:15
+  --> $DIR/disallowed-positions.rs:286:15
    |
 LL |     while let Range { start: true, end } = t..&&false {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `&&bool`
@@ -1788,7 +1848,7 @@ LL |     while let Range { start: true, end } = t..&&false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:280:47
+  --> $DIR/disallowed-positions.rs:286:47
    |
 LL |     while let Range { start: true, end } = t..&&false {}
    |                                               ^^^^^^^ expected `bool`, found `&&bool`
@@ -1800,7 +1860,7 @@ LL +     while let Range { start: true, end } = t..false {}
    |
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:280:11
+  --> $DIR/disallowed-positions.rs:286:11
    |
 LL |     while let Range { start: true, end } = t..&&false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -1809,7 +1869,7 @@ LL |     while let Range { start: true, end } = t..&&false {}
             found struct `std::ops::Range<bool>`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:219:23
+  --> $DIR/disallowed-positions.rs:224:23
    |
 LL |         while let 0 = 0? {}
    |                       ^^ the `?` operator cannot be applied to type `{integer}`
@@ -1817,19 +1877,19 @@ LL |         while let 0 = 0? {}
    = help: the trait `Try` is not implemented for `{integer}`
 
 error[E0614]: type `bool` cannot be dereferenced
-  --> $DIR/disallowed-positions.rs:309:5
+  --> $DIR/disallowed-positions.rs:315:5
    |
 LL |     *let 0 = 0;
    |     ^^^^^^^^^^
 
 error[E0600]: cannot apply unary operator `-` to type `bool`
-  --> $DIR/disallowed-positions.rs:313:5
+  --> $DIR/disallowed-positions.rs:319:5
    |
 LL |     -let 0 = 0;
    |     ^^^^^^^^^^ cannot apply unary operator `-`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:323:5
+  --> $DIR/disallowed-positions.rs:329:5
    |
 LL |     (let 0 = 0)?;
    |     ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
@@ -1837,7 +1897,7 @@ LL |     (let 0 = 0)?;
    = help: the trait `Try` is not implemented for `bool`
 
 error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
-  --> $DIR/disallowed-positions.rs:323:16
+  --> $DIR/disallowed-positions.rs:329:16
    |
 LL | / fn outside_if_and_while_expr() {
 LL | |     &let 0 = 0;
@@ -1854,7 +1914,7 @@ LL | | }
    = help: the trait `FromResidual<_>` is not implemented for `()`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:354:10
+  --> $DIR/disallowed-positions.rs:360:10
    |
 LL |     (let Range { start: _, end: _ } = true..true || false);
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -1865,7 +1925,7 @@ LL |     (let Range { start: _, end: _ } = true..true || false);
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:377:5
+  --> $DIR/disallowed-positions.rs:383:5
    |
 LL | fn outside_if_and_while_expr() {
    |                                - help: try adding a return type: `-> &bool`
@@ -1874,14 +1934,14 @@ LL |     &let 0 = 0
    |     ^^^^^^^^^^ expected `()`, found `&bool`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:319:17
+  --> $DIR/disallowed-positions.rs:325:17
    |
 LL |         let 0 = 0?;
    |                 ^^ the `?` operator cannot be applied to type `{integer}`
    |
    = help: the trait `Try` is not implemented for `{integer}`
 
-error: aborting due to 208 previous errors
+error: aborting due to 218 previous errors
 
 Some errors have detailed explanations: E0277, E0308, E0600, E0614.
 For more information about an error, try `rustc --explain E0277`.
index 42685cad9482bb125fe95444caa043c0c151d854..77f425c3e4530200e234caaa7b56c807b3367e79 100644 (file)
@@ -7,6 +7,10 @@
     #[link_ordinal(42)]
     //~^ ERROR cannot use `#[link_name]` with `#[link_ordinal]`
     fn foo();
+    #[link_name="foo"]
+    #[link_ordinal(5)]
+    //~^ ERROR cannot use `#[link_name]` with `#[link_ordinal]`
+    static mut imported_variable: i32;
 }
 
 fn main() {}
index 5d8545b506204698ec33cf2ca5b52b5f54105577..dfe9d031c776d7faec47c722bfb18010663d9934 100644 (file)
@@ -13,5 +13,11 @@ error: cannot use `#[link_name]` with `#[link_ordinal]`
 LL |     #[link_ordinal(42)]
    |     ^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error; 1 warning emitted
+error: cannot use `#[link_name]` with `#[link_ordinal]`
+  --> $DIR/link-ordinal-and-name.rs:11:5
+   |
+LL |     #[link_ordinal(5)]
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors; 1 warning emitted
 
index 135f5909ea130001a79895c5492d97dffd5df9d1..4687fe47f906e0124905f80c74bb4667c0518fc9 100644 (file)
@@ -6,6 +6,9 @@
     #[link_ordinal("JustMonika")]
     //~^ ERROR illegal ordinal format in `link_ordinal`
     fn foo();
+    #[link_ordinal("JustMonika")]
+    //~^ ERROR illegal ordinal format in `link_ordinal`
+    static mut imported_variable: i32;
 }
 
 fn main() {}
index 8453a3966bee5f90cbd578222fdc7ce9d194d140..1d0fad6cb49db11d804eadd71d0bddbf49d1ea3d 100644 (file)
@@ -15,5 +15,13 @@ LL |     #[link_ordinal("JustMonika")]
    |
    = note: an unsuffixed integer value, e.g., `1`, is expected
 
-error: aborting due to previous error; 1 warning emitted
+error: illegal ordinal format in `link_ordinal`
+  --> $DIR/link-ordinal-invalid-format.rs:9:5
+   |
+LL |     #[link_ordinal("JustMonika")]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: an unsuffixed integer value, e.g., `1`, is expected
+
+error: aborting due to 2 previous errors; 1 warning emitted
 
index c391ccd1c822766543bd273b475c76602ab14f1b..becf2700aebc55518133d133e7e72baa29dd7998 100644 (file)
@@ -6,6 +6,9 @@
     #[link_ordinal()]
     //~^ ERROR incorrect number of arguments to `#[link_ordinal]`
     fn foo();
+    #[link_ordinal()]
+    //~^ ERROR incorrect number of arguments to `#[link_ordinal]`
+    static mut imported_variable: i32;
 }
 
 fn main() {}
index 8e9edfb9d20ac6553d60646237ce26dccc1e4d78..5b0ec869d03b8225995fa9b6d8d3cd3ec0c33261 100644 (file)
@@ -15,5 +15,13 @@ LL |     #[link_ordinal()]
    |
    = note: the attribute requires exactly one argument
 
-error: aborting due to previous error; 1 warning emitted
+error: incorrect number of arguments to `#[link_ordinal]`
+  --> $DIR/link-ordinal-missing-argument.rs:9:5
+   |
+LL |     #[link_ordinal()]
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: the attribute requires exactly one argument
+
+error: aborting due to 2 previous errors; 1 warning emitted
 
index 2a15b1d799f846fc7379d8d28ec7a4c84d46a63c..7b07d09e72a5d3b64258a6807c362067cbfef28e 100644 (file)
@@ -7,6 +7,9 @@
     #[link_ordinal(1)] //~ ERROR multiple `link_ordinal` attributes
     #[link_ordinal(2)]
     fn foo();
+    #[link_ordinal(1)] //~ ERROR multiple `link_ordinal` attributes
+    #[link_ordinal(2)]
+    static mut imported_variable: i32;
 }
 
 fn main() {}
index 4772533ab2f07199b99dc35e377a3f3fde044b8f..92a39b3d1b09951672a895cc5e570b72530e9186 100644 (file)
@@ -19,5 +19,17 @@ note: attribute also specified here
 LL |     #[link_ordinal(2)]
    |     ^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error; 1 warning emitted
+error: multiple `link_ordinal` attributes
+  --> $DIR/link-ordinal-multiple.rs:10:5
+   |
+LL |     #[link_ordinal(1)]
+   |     ^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   |
+note: attribute also specified here
+  --> $DIR/link-ordinal-multiple.rs:11:5
+   |
+LL |     #[link_ordinal(2)]
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors; 1 warning emitted
 
diff --git a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.rs b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.rs
new file mode 100644 (file)
index 0000000..5d273d5
--- /dev/null
@@ -0,0 +1,25 @@
+#![feature(raw_dylib)]
+//~^ WARN the feature `raw_dylib` is incomplete
+
+#[link_ordinal(123)]
+//~^ ERROR attribute should be applied to a foreign function or static
+struct Foo {}
+
+#[link_ordinal(123)]
+//~^ ERROR attribute should be applied to a foreign function or static
+fn test() {}
+
+#[link_ordinal(42)]
+//~^ ERROR attribute should be applied to a foreign function or static
+static mut imported_val: i32 = 123;
+
+#[link(name = "exporter", kind = "raw-dylib")]
+extern {
+    #[link_ordinal(13)]
+    fn imported_function();
+
+    #[link_ordinal(42)]
+    static mut imported_variable: i32;
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.stderr b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.stderr
new file mode 100644 (file)
index 0000000..8fa2f16
--- /dev/null
@@ -0,0 +1,29 @@
+warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/link-ordinal-not-foreign-fn.rs:1:12
+   |
+LL | #![feature(raw_dylib)]
+   |            ^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
+
+error: attribute should be applied to a foreign function or static
+  --> $DIR/link-ordinal-not-foreign-fn.rs:4:1
+   |
+LL | #[link_ordinal(123)]
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: attribute should be applied to a foreign function or static
+  --> $DIR/link-ordinal-not-foreign-fn.rs:8:1
+   |
+LL | #[link_ordinal(123)]
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: attribute should be applied to a foreign function or static
+  --> $DIR/link-ordinal-not-foreign-fn.rs:12:1
+   |
+LL | #[link_ordinal(42)]
+   | ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors; 1 warning emitted
+
index b6089d27e7ab731e2e15429d498b361fdb6a9765..99d7d9d0b7edabb06785e145dcf4566dee329eeb 100644 (file)
@@ -6,6 +6,9 @@
     #[link_ordinal(72436)]
     //~^ ERROR ordinal value in `link_ordinal` is too large: `72436`
     fn foo();
+    #[link_ordinal(72436)]
+    //~^ ERROR ordinal value in `link_ordinal` is too large: `72436`
+    static mut imported_variable: i32;
 }
 
 fn main() {}
index bbe985fa10ada35d30e2c687603a89df52f51c43..36f278bd85645e09391e9cd488f587b436db270e 100644 (file)
@@ -15,5 +15,13 @@ LL |     #[link_ordinal(72436)]
    |
    = note: the value may not exceed `u16::MAX`
 
-error: aborting due to previous error; 1 warning emitted
+error: ordinal value in `link_ordinal` is too large: `72436`
+  --> $DIR/link-ordinal-too-large.rs:9:5
+   |
+LL |     #[link_ordinal(72436)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the value may not exceed `u16::MAX`
+
+error: aborting due to 2 previous errors; 1 warning emitted
 
index 93286c616c5ac55ada64fc3ddc75dbf3cb5e58fc..eca4186e593e82c4180b5bb4addaf656c14a4ff4 100644 (file)
@@ -6,6 +6,9 @@
     #[link_ordinal(3, 4)]
     //~^ ERROR incorrect number of arguments to `#[link_ordinal]`
     fn foo();
+    #[link_ordinal(3, 4)]
+    //~^ ERROR incorrect number of arguments to `#[link_ordinal]`
+    static mut imported_variable: i32;
 }
 
 fn main() {}
index 484c85a0f422a9bada710f70b6531bc6e213a8b8..745aab24dc768ce6a498757807920192e44ded1d 100644 (file)
@@ -15,5 +15,13 @@ LL |     #[link_ordinal(3, 4)]
    |
    = note: the attribute requires exactly one argument
 
-error: aborting due to previous error; 1 warning emitted
+error: incorrect number of arguments to `#[link_ordinal]`
+  --> $DIR/link-ordinal-too-many-arguments.rs:9:5
+   |
+LL |     #[link_ordinal(3, 4)]
+   |     ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the attribute requires exactly one argument
+
+error: aborting due to 2 previous errors; 1 warning emitted
 
diff --git a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.rs b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.rs
new file mode 100644 (file)
index 0000000..99f3173
--- /dev/null
@@ -0,0 +1,18 @@
+#![feature(raw_dylib)]
+//~^ WARN the feature `raw_dylib` is incomplete
+
+#[link(name = "foo")]
+extern "C" {
+    #[link_ordinal(3)]
+    //~^ ERROR `#[link_ordinal]` is only supported if link kind is `raw-dylib`
+    fn foo();
+}
+
+#[link(name = "bar", kind = "static")]
+extern "C" {
+    #[link_ordinal(3)]
+    //~^ ERROR `#[link_ordinal]` is only supported if link kind is `raw-dylib`
+    fn bar();
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.stderr b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.stderr
new file mode 100644 (file)
index 0000000..f1eeb22
--- /dev/null
@@ -0,0 +1,23 @@
+warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/link-ordinal-unsupported-link-kind.rs:1:12
+   |
+LL | #![feature(raw_dylib)]
+   |            ^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
+
+error: `#[link_ordinal]` is only supported if link kind is `raw-dylib`
+  --> $DIR/link-ordinal-unsupported-link-kind.rs:6:5
+   |
+LL |     #[link_ordinal(3)]
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: `#[link_ordinal]` is only supported if link kind is `raw-dylib`
+  --> $DIR/link-ordinal-unsupported-link-kind.rs:13:5
+   |
+LL |     #[link_ordinal(3)]
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors; 1 warning emitted
+
index f50e70939dfd58bc2d9bc6907e64972684d3d832..04462c0a11b89f24cb947ac9ab2548f3e0836532 100644 (file)
@@ -96,7 +96,7 @@ fn drop(&mut self) {
 }
 
 fn main() {
-    struct HasDropGlue(Box<u8>);
+    struct HasDropGlue(#[allow(unused_tuple_struct_fields)] Box<u8>);
     struct HasDropImpl;
     impl Drop for HasDropImpl {
         fn drop(&mut self) {
index 2fe1e05e509f8ae17229713249bcbcd5e70a6557..d359067f627e3dcd1a51999e7c311e05c4c98660 100644 (file)
@@ -7,7 +7,7 @@ struct Test {
 }
 
 #[r#derive(r#Debug)]
-struct Test2(u32);
+struct Test2(#[allow(unused_tuple_struct_fields)] u32);
 
 pub fn main() {
     assert_eq!(mem::size_of::<Test>(), 9);
index 4738e5116b4274c982fcc92b296670670e692a24..10609e5d8f4d99661e962928ed32bc4516510c5f 100644 (file)
@@ -21,6 +21,12 @@ impl Foo for Bar {
     type X = i32;
     fn foo(#[doc(alias = "qux")] _x: u32) -> Self::X {
         //~^ ERROR
-        0
+        #[doc(alias = "stmt")] //~ ERROR
+        let x = 0;
+        #[doc(alias = "expr")] //~ ERROR
+        match x {
+            #[doc(alias = "arm")] //~ ERROR
+            _ => 0
+        }
     }
 }
index 650a82a23a981c07263bb906eabe0ea801d730ba..23c93a4ed8bdb248a867de0ddae844175e3f80c7 100644 (file)
@@ -4,7 +4,7 @@ error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed
 LL |     fn foo(#[doc(alias = "qux")] _x: u32) -> Self::X {
    |            ^^^^^^^^^^^^^^^^^^^^^
 
-error: `#[doc(alias = "...")]` isn't allowed on extern block
+error: `#[doc(alias = "...")]` isn't allowed on foreign module
   --> $DIR/check-doc-alias-attr-location.rs:9:7
    |
 LL | #[doc(alias = "foo")]
@@ -28,5 +28,23 @@ error: `#[doc(alias = "...")]` isn't allowed on type alias in implementation blo
 LL |     #[doc(alias = "assoc")]
    |           ^^^^^^^^^^^^^^^
 
-error: aborting due to 5 previous errors
+error: `#[doc(alias = "...")]` isn't allowed on statement
+  --> $DIR/check-doc-alias-attr-location.rs:24:15
+   |
+LL |         #[doc(alias = "stmt")]
+   |               ^^^^^^^^^^^^^^
+
+error: `#[doc(alias = "...")]` isn't allowed on expression
+  --> $DIR/check-doc-alias-attr-location.rs:26:15
+   |
+LL |         #[doc(alias = "expr")]
+   |               ^^^^^^^^^^^^^^
+
+error: `#[doc(alias = "...")]` isn't allowed on match arm
+  --> $DIR/check-doc-alias-attr-location.rs:28:19
+   |
+LL |             #[doc(alias = "arm")]
+   |                   ^^^^^^^^^^^^^
+
+error: aborting due to 8 previous errors
 
diff --git a/src/test/ui/specialization/issue-43037.rs b/src/test/ui/specialization/issue-43037.rs
new file mode 100644 (file)
index 0000000..c49119f
--- /dev/null
@@ -0,0 +1,20 @@
+#![feature(specialization)]
+#![allow(incomplete_features)]
+
+trait X {}
+trait Y: X {}
+trait Z {
+    type Assoc: Y;
+}
+struct A<T>(T);
+
+impl<T> Y for T where T: X {}
+impl<T: X> Z for A<T> {
+    type Assoc = T;
+}
+
+// this impl is invalid, but causes an ICE anyway
+impl<T> From<<A<T> as Z>::Assoc> for T {}
+//~^ ERROR type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
+
+fn main() {}
diff --git a/src/test/ui/specialization/issue-43037.stderr b/src/test/ui/specialization/issue-43037.stderr
new file mode 100644 (file)
index 0000000..4249cd8
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
+  --> $DIR/issue-43037.rs:17:6
+   |
+LL | impl<T> From<<A<T> as Z>::Assoc> for T {}
+   |      ^ type parameter `T` must be used as the type parameter for some local type
+   |
+   = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
+   = note: only traits defined in the current crate can be implemented for a type parameter
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0210`.
diff --git a/src/test/ui/specialization/issue-45814.rs b/src/test/ui/specialization/issue-45814.rs
new file mode 100644 (file)
index 0000000..8ee5d3e
--- /dev/null
@@ -0,0 +1,12 @@
+//~ ERROR overflow evaluating the requirement `T: Trait<_>`
+
+#![feature(specialization)]
+#![allow(incomplete_features)]
+
+pub trait Trait<T> {}
+
+default impl<T, U> Trait<T> for U {}
+
+impl<T> Trait<<T as Iterator>::Item> for T {}
+
+fn main() {}
diff --git a/src/test/ui/specialization/issue-45814.stderr b/src/test/ui/specialization/issue-45814.stderr
new file mode 100644 (file)
index 0000000..ab6adf4
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0275]: overflow evaluating the requirement `T: Trait<_>`
+   |
+   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_45814`)
+note: required because of the requirements on the impl of `Trait<_>` for `T`
+  --> $DIR/issue-45814.rs:8:20
+   |
+LL | default impl<T, U> Trait<T> for U {}
+   |                    ^^^^^^^^     ^
+   = note: 128 redundant requirements hidden
+   = note: required because of the requirements on the impl of `Trait<_>` for `T`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0275`.
index 4171505aa374c7d1066450bf9c73fb27789d08de..d9381d66152260a82d92754f5ff2f4abcde0d98f 100644 (file)
@@ -14,7 +14,7 @@
 struct MarkedAndClone;
 impl MyMarker for MarkedAndClone {}
 
-struct MyType<T>(T);
+struct MyType<T>(#[allow(unused_tuple_struct_fields)] T);
 impl<T> Foo for MyType<T> {
     default fn foo(&self) -> &'static str {
         "generic MyType"
index 5c2781a9c63a6eb4267ed4bb53f5d0dfb874f1ac..904aeaa088b769eff4095c7c7e7b66007a18a4d3 100644 (file)
@@ -14,7 +14,7 @@ impl<'a> WithAssoc for &'a () {
     type Item = &'a u32;
 }
 
-struct Cloned<I>(I);
+struct Cloned<I>(#[allow(unused_tuple_struct_fields)] I);
 
 impl<'a, I, T: 'a> Iterator for Cloned<I>
     where I: WithAssoc<Item=&'a T>, T: Clone
diff --git a/src/test/ui/stability-attribute/auxiliary/default_body.rs b/src/test/ui/stability-attribute/auxiliary/default_body.rs
new file mode 100644 (file)
index 0000000..3a17741
--- /dev/null
@@ -0,0 +1,29 @@
+#![crate_type = "lib"]
+#![feature(staged_api, rustc_attrs)]
+#![stable(feature = "stable_feature", since = "1.0.0")]
+
+#[stable(feature = "stable_feature", since = "1.0.0")]
+pub trait JustTrait {
+    #[stable(feature = "stable_feature", since = "1.0.0")]
+    #[rustc_default_body_unstable(feature = "constant_default_body", issue = "none")]
+    const CONSTANT: usize = 0;
+
+    #[rustc_default_body_unstable(feature = "fun_default_body", issue = "none")]
+    #[stable(feature = "stable_feature", since = "1.0.0")]
+    fn fun() {}
+}
+
+#[rustc_must_implement_one_of(eq, neq)]
+#[stable(feature = "stable_feature", since = "1.0.0")]
+pub trait Equal {
+    #[rustc_default_body_unstable(feature = "eq_default_body", issue = "none")]
+    #[stable(feature = "stable_feature", since = "1.0.0")]
+    fn eq(&self, other: &Self) -> bool {
+        !self.neq(other)
+    }
+
+    #[stable(feature = "stable_feature", since = "1.0.0")]
+    fn neq(&self, other: &Self) -> bool {
+        !self.eq(other)
+    }
+}
diff --git a/src/test/ui/stability-attribute/default-body-stability-err.rs b/src/test/ui/stability-attribute/default-body-stability-err.rs
new file mode 100644 (file)
index 0000000..ecb281b
--- /dev/null
@@ -0,0 +1,19 @@
+// aux-build:default_body.rs
+#![crate_type = "lib"]
+
+extern crate default_body;
+
+use default_body::{Equal, JustTrait};
+
+struct Type;
+
+impl JustTrait for Type {}
+//~^ ERROR not all trait items implemented, missing: `CONSTANT` [E0046]
+//~| ERROR not all trait items implemented, missing: `fun` [E0046]
+
+impl Equal for Type {
+    //~^ ERROR not all trait items implemented, missing: `eq` [E0046]
+    fn neq(&self, other: &Self) -> bool {
+        false
+    }
+}
diff --git a/src/test/ui/stability-attribute/default-body-stability-err.stderr b/src/test/ui/stability-attribute/default-body-stability-err.stderr
new file mode 100644 (file)
index 0000000..ef666f3
--- /dev/null
@@ -0,0 +1,38 @@
+error[E0046]: not all trait items implemented, missing: `CONSTANT`
+  --> $DIR/default-body-stability-err.rs:10:1
+   |
+LL | impl JustTrait for Type {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: default implementation of `CONSTANT` is unstable
+   = note: use of unstable library feature 'constant_default_body'
+   = help: add `#![feature(constant_default_body)]` to the crate attributes to enable
+
+error[E0046]: not all trait items implemented, missing: `fun`
+  --> $DIR/default-body-stability-err.rs:10:1
+   |
+LL | impl JustTrait for Type {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: default implementation of `fun` is unstable
+   = note: use of unstable library feature 'fun_default_body'
+   = help: add `#![feature(fun_default_body)]` to the crate attributes to enable
+
+error[E0046]: not all trait items implemented, missing: `eq`
+  --> $DIR/default-body-stability-err.rs:14:1
+   |
+LL | / impl Equal for Type {
+LL | |
+LL | |     fn neq(&self, other: &Self) -> bool {
+LL | |         false
+LL | |     }
+LL | | }
+   | |_^
+   |
+   = note: default implementation of `eq` is unstable
+   = note: use of unstable library feature 'eq_default_body'
+   = help: add `#![feature(eq_default_body)]` to the crate attributes to enable
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0046`.
diff --git a/src/test/ui/stability-attribute/default-body-stability-ok-enables.rs b/src/test/ui/stability-attribute/default-body-stability-ok-enables.rs
new file mode 100644 (file)
index 0000000..bdc7522
--- /dev/null
@@ -0,0 +1,18 @@
+// check-pass
+// aux-build:default_body.rs
+#![crate_type = "lib"]
+#![feature(fun_default_body, eq_default_body, constant_default_body)]
+
+extern crate default_body;
+
+use default_body::{Equal, JustTrait};
+
+struct Type;
+
+impl JustTrait for Type {}
+
+impl Equal for Type {
+    fn neq(&self, other: &Self) -> bool {
+        false
+    }
+}
diff --git a/src/test/ui/stability-attribute/default-body-stability-ok-impls.rs b/src/test/ui/stability-attribute/default-body-stability-ok-impls.rs
new file mode 100644 (file)
index 0000000..e1f5c01
--- /dev/null
@@ -0,0 +1,21 @@
+// check-pass
+// aux-build:default_body.rs
+#![crate_type = "lib"]
+
+extern crate default_body;
+
+use default_body::{Equal, JustTrait};
+
+struct Type;
+
+impl JustTrait for Type {
+    const CONSTANT: usize = 1;
+
+    fn fun() {}
+}
+
+impl Equal for Type {
+    fn eq(&self, other: &Self) -> bool {
+        false
+    }
+}
diff --git a/src/test/ui/stats/hir-stats.rs b/src/test/ui/stats/hir-stats.rs
new file mode 100644 (file)
index 0000000..a24b3ad
--- /dev/null
@@ -0,0 +1,41 @@
+// check-pass
+// compile-flags: -Zhir-stats
+// only-x86_64
+
+// The aim here is to include at least one of every different type of top-level
+// AST/HIR node reported by `-Zhir-stats`.
+
+#![allow(dead_code)]
+
+use std::arch::asm;
+use std::fmt::Debug;
+use std::ffi::c_void;
+
+extern "C" { fn f(p: *mut c_void); }
+
+/// An enum.
+enum E<'a, T: Copy> { A { t: T }, B(&'a u32) }
+
+trait Go {
+    type G: Debug;
+    fn go(self) -> u32;
+}
+
+impl<'a, T: Copy> Go for E<'a, T> {
+    type G = bool;
+    fn go(self) -> u32 {
+        99
+    }
+}
+
+fn f2<T>(t: T) where T: Debug {}
+
+fn main() {
+    let x = E::A { t: 3 };
+    match x {
+        E::A { .. } => {}
+        _ => {}
+    }
+
+    unsafe { asm!("mov rdi, 1"); }
+}
diff --git a/src/test/ui/stats/hir-stats.stderr b/src/test/ui/stats/hir-stats.stderr
new file mode 100644 (file)
index 0000000..f487440
--- /dev/null
@@ -0,0 +1,151 @@
+
+PRE EXPANSION AST STATS
+
+Name                Accumulated Size         Count     Item Size
+----------------------------------------------------------------
+ExprField                 48 ( 0.5%)             1            48
+GenericArgs               64 ( 0.7%)             1            64
+- AngleBracketed            64 ( 0.7%)             1
+Local                     72 ( 0.8%)             1            72
+WherePredicate            72 ( 0.8%)             1            72
+- BoundPredicate            72 ( 0.8%)             1
+Crate                     72 ( 0.8%)             1            72
+Arm                       96 ( 1.0%)             2            48
+FieldDef                 160 ( 1.7%)             2            80
+ForeignItem              160 ( 1.7%)             1           160
+- Fn                       160 ( 1.7%)             1
+Stmt                     160 ( 1.7%)             5            32
+- Local                     32 ( 0.3%)             1
+- MacCall                   32 ( 0.3%)             1
+- Expr                      96 ( 1.0%)             3
+Param                    160 ( 1.7%)             4            40
+FnDecl                   200 ( 2.2%)             5            40
+Variant                  240 ( 2.6%)             2           120
+Block                    288 ( 3.1%)             6            48
+Attribute                304 ( 3.3%)             2           152
+- Normal                   152 ( 1.7%)             1
+- DocComment               152 ( 1.7%)             1
+GenericBound             352 ( 3.8%)             4            88
+- Trait                    352 ( 3.8%)             4
+GenericParam             520 ( 5.7%)             5           104
+AssocItem                640 ( 7.0%)             4           160
+- TyAlias                  320 ( 3.5%)             2
+- Fn                       320 ( 3.5%)             2
+PathSegment              720 ( 7.9%)            30            24
+Expr                     832 ( 9.1%)             8           104
+- Path                     104 ( 1.1%)             1
+- Match                    104 ( 1.1%)             1
+- Struct                   104 ( 1.1%)             1
+- Lit                      208 ( 2.3%)             2
+- Block                    312 ( 3.4%)             3
+Pat                      840 ( 9.2%)             7           120
+- Struct                   120 ( 1.3%)             1
+- Wild                     120 ( 1.3%)             1
+- Ident                    600 ( 6.6%)             5
+Ty                     1_344 (14.7%)            14            96
+- Rptr                      96 ( 1.0%)             1
+- Ptr                       96 ( 1.0%)             1
+- ImplicitSelf             192 ( 2.1%)             2
+- Path                     960 (10.5%)            10
+Item                   1_800 (19.7%)             9           200
+- Trait                    200 ( 2.2%)             1
+- Enum                     200 ( 2.2%)             1
+- ForeignMod               200 ( 2.2%)             1
+- Impl                     200 ( 2.2%)             1
+- Fn                       400 ( 4.4%)             2
+- Use                      600 ( 6.6%)             3
+----------------------------------------------------------------
+Total                  9_144
+
+
+POST EXPANSION AST STATS
+
+Name                Accumulated Size         Count     Item Size
+----------------------------------------------------------------
+ExprField                 48 ( 0.5%)             1            48
+GenericArgs               64 ( 0.6%)             1            64
+- AngleBracketed            64 ( 0.6%)             1
+Local                     72 ( 0.7%)             1            72
+WherePredicate            72 ( 0.7%)             1            72
+- BoundPredicate            72 ( 0.7%)             1
+Crate                     72 ( 0.7%)             1            72
+Arm                       96 ( 0.9%)             2            48
+InlineAsm                120 ( 1.2%)             1           120
+FieldDef                 160 ( 1.6%)             2            80
+ForeignItem              160 ( 1.6%)             1           160
+- Fn                       160 ( 1.6%)             1
+Stmt                     160 ( 1.6%)             5            32
+- Local                     32 ( 0.3%)             1
+- Semi                      32 ( 0.3%)             1
+- Expr                      96 ( 0.9%)             3
+Param                    160 ( 1.6%)             4            40
+FnDecl                   200 ( 2.0%)             5            40
+Variant                  240 ( 2.4%)             2           120
+Block                    288 ( 2.8%)             6            48
+GenericBound             352 ( 3.5%)             4            88
+- Trait                    352 ( 3.5%)             4
+GenericParam             520 ( 5.1%)             5           104
+Attribute                608 ( 6.0%)             4           152
+- DocComment               152 ( 1.5%)             1
+- Normal                   456 ( 4.5%)             3
+AssocItem                640 ( 6.3%)             4           160
+- TyAlias                  320 ( 3.2%)             2
+- Fn                       320 ( 3.2%)             2
+PathSegment              792 ( 7.8%)            33            24
+Pat                      840 ( 8.3%)             7           120
+- Struct                   120 ( 1.2%)             1
+- Wild                     120 ( 1.2%)             1
+- Ident                    600 ( 5.9%)             5
+Expr                     936 ( 9.2%)             9           104
+- Path                     104 ( 1.0%)             1
+- Match                    104 ( 1.0%)             1
+- Struct                   104 ( 1.0%)             1
+- InlineAsm                104 ( 1.0%)             1
+- Lit                      208 ( 2.1%)             2
+- Block                    312 ( 3.1%)             3
+Ty                     1_344 (13.2%)            14            96
+- Rptr                      96 ( 0.9%)             1
+- Ptr                       96 ( 0.9%)             1
+- ImplicitSelf             192 ( 1.9%)             2
+- Path                     960 ( 9.5%)            10
+Item                   2_200 (21.7%)            11           200
+- Trait                    200 ( 2.0%)             1
+- Enum                     200 ( 2.0%)             1
+- ExternCrate              200 ( 2.0%)             1
+- ForeignMod               200 ( 2.0%)             1
+- Impl                     200 ( 2.0%)             1
+- Fn                       400 ( 3.9%)             2
+- Use                      800 ( 7.9%)             4
+----------------------------------------------------------------
+Total                 10_144
+
+
+HIR STATS
+
+Name                Accumulated Size         Count     Item Size
+----------------------------------------------------------------
+Param                     64 ( 0.7%)             2            32
+Local                     64 ( 0.7%)             1            64
+ForeignItem               72 ( 0.7%)             1            72
+FieldDef                  96 ( 1.0%)             2            48
+Arm                       96 ( 1.0%)             2            48
+Stmt                      96 ( 1.0%)             3            32
+FnDecl                   120 ( 1.2%)             3            40
+Lifetime                 128 ( 1.3%)             4            32
+Variant                  160 ( 1.6%)             2            80
+ImplItem                 176 ( 1.8%)             2            88
+GenericBound             192 ( 2.0%)             4            48
+TraitItem                192 ( 2.0%)             2            96
+WherePredicate           216 ( 2.2%)             3            72
+Block                    288 ( 3.0%)             6            48
+QPath                    408 ( 4.2%)            17            24
+Pat                      440 ( 4.5%)             5            88
+Attribute                608 ( 6.2%)             4           152
+Expr                     672 ( 6.9%)            12            56
+Item                     960 ( 9.9%)            12            80
+Ty                     1_152 (11.8%)            16            72
+Path                   1_296 (13.3%)            27            48
+PathSegment            2_240 (23.0%)            40            56
+----------------------------------------------------------------
+Total                  9_736
+
index 07de066b5586382cc676b5e8b02dbc3490657cf9..3f8306baf8a217454028845bac589362015b3163 100644 (file)
@@ -7,8 +7,6 @@
 // compile-flags:-g
 // compile-flags:-Cstrip=none
 
-#![feature(backtrace)]
-
 use std::env;
 use std::process::Command;
 use std::str;
index 9f50659ed60d096a9392087614dc5474e6415832..6b0b09c98945c0edf85cba263dcb1d485805eacb 100644 (file)
@@ -39,6 +39,7 @@ fn foo(&self) -> usize {
     }
 }
 
+#[allow(unused_tuple_struct_fields)]
 struct S<T:?Sized>(u32, T);
 
 fn main() {
index f242cb8457f997b01586d532fea5343098337043..ba6abbf03a539f6d15cc1f4052389b636398b13a 100644 (file)
@@ -4,7 +4,7 @@ fn size_of_val<T>(_: &T) -> usize {
     std::mem::size_of::<T>()
 }
 
-struct Foo(i64);
+struct Foo(#[allow(unused_tuple_struct_fields)] i64);
 
 // Test that the (symbol) mangling of `Foo` (the `struct` type) and that of
 // `typeof Foo` (the function type of the `struct` constructor) don't collide.
index 27ef990aa90df55dd325d7a77d9da2abca050ae0..f5418e754b239a3d5485e32d41cd7488ebbc8218 100644 (file)
@@ -1,6 +1,5 @@
 // run-pass
 #![allow(dead_code)]
-#![feature(box_syntax)]
 
 use std::mem;
 
@@ -232,9 +231,9 @@ pub fn main() {
     assert_eq!(mem::size_of_val(&a), 32);
     assert!(is_aligned_to(&a, 16));
 
-    let mut large = box AlignLarge {
+    let mut large = Box::new(AlignLarge {
         stuff: [0; 0x10000],
-    };
+    });
     large.stuff[0] = 132;
     *large.stuff.last_mut().unwrap() = 102;
     assert_eq!(large.stuff[0], 132);
index 32fdbf620a98d0c73d9acaf203eb9b60a7141f7d..85fa1eac2e2a6fd751b46f8dc7e0532965f0e37d 100644 (file)
@@ -10,8 +10,8 @@
 trait Trait { fn dummy(&self) { } }
 trait Mirror { type Image; }
 impl<T> Mirror for T { type Image = T; }
-struct ParamTypeStruct<T>(T);
-struct AssocTypeStruct<T>(<T as Mirror>::Image);
+struct ParamTypeStruct<T>(#[allow(unused_tuple_struct_fields)] T);
+struct AssocTypeStruct<T>(#[allow(unused_tuple_struct_fields)] <T as Mirror>::Image);
 #[repr(transparent)]
 union MaybeUninitUnion<T: Copy> {
     _value: T,
@@ -46,7 +46,7 @@ fn main() {
     struct Foo {
         _a: Box<isize>
     }
-    struct Bar(Box<isize>);
+    struct Bar(#[allow(unused_tuple_struct_fields)] Box<isize>);
 
     // Should apply through structs
     assert_eq!(size_of::<Foo>(), size_of::<Option<Foo>>());
index 53892a4e0aeb46418848d9ef82f24e4d4a124fbe..a05cf8b93d5bd215787ad88cf96fc36b933ca8ec 100644 (file)
@@ -6,7 +6,7 @@
  * represented with nullable pointers could be misoptimized in some cases.
  */
 
-enum List<X> { Nil, Cons(X, Box<List<X>>) }
+enum List<X> { Nil, Cons(X, #[allow(unused_tuple_struct_fields)] Box<List<X>>) }
 pub fn main() {
     match List::Cons(10, Box::new(List::Nil)) {
         List::Cons(10, _) => {}
index 35a4b14bc3f87d77bc42a88ff44212a370f51823..9613ca62a49e62c75f286c8ded5871b3752293c1 100644 (file)
@@ -25,7 +25,7 @@ fn close_res(i: closable) -> close_res {
     }
 }
 
-enum option<T> { none, some(T), }
+enum option<T> { none, some(#[allow(unused_tuple_struct_fields)] T), }
 
 fn sink(_res: option<close_res>) { }
 
index 972fc9dc04a905ed912bcd7cbc67fb30b0bf0450..fbf97e6b22558152fe41c394d6167e56bf212759 100644 (file)
@@ -1,4 +1,5 @@
 // run-pass
+#[allow(unused_tuple_struct_fields)]
 #[derive(Debug)]
 struct Foo(isize, isize);
 
index b1ef525614ea5566ffa919f24fc3223c7a9b1ae1..b24effe5a9c48d91ddb26ed373f72960824b154e 100644 (file)
@@ -1,4 +1,4 @@
 // run-pass
-pub struct Z(&'static Z);
+pub struct Z(#[allow(unused_tuple_struct_fields)] &'static Z);
 
 pub fn main() {}
index 46d9461538c7857a5aad9fa33e1c41c4168f679c..a053534418589177c93ca04afae81a0cdc9519ca 100644 (file)
@@ -17,4 +17,11 @@ fn main() {
     // note: do not suggest because of `E: usize`
     let x: &Result<usize, usize> = &Ok(3);
     let y: Result<&usize, usize> = x; //~ ERROR mismatched types [E0308]
+
+    let multiple_ref_opt = &&Some(Foo);
+    multiple_ref_opt.map(|arg| takes_ref(arg)); //~ ERROR mismatched types [E0308]
+    multiple_ref_opt.and_then(|arg| Some(takes_ref(arg))); //~ ERROR mismatched types [E0308]
+    let multiple_ref_result = &&Ok(Foo);
+    multiple_ref_result.map(|arg| takes_ref(arg)); //~ ERROR mismatched types [E0308]
+    multiple_ref_result.and_then(|arg| Ok(takes_ref(arg))); //~ ERROR mismatched types [E0308]
 }
index 1efd1b317b7da25de6b895f0b7ee4a981734bc87..deafa9f48d459e65637a79774b3e7007d2342bbb 100644 (file)
@@ -97,6 +97,66 @@ LL |     let y: Result<&usize, usize> = x;
    = note:   expected enum `Result<&usize, usize>`
            found reference `&Result<usize, usize>`
 
-error: aborting due to 7 previous errors
+error[E0308]: mismatched types
+  --> $DIR/as-ref.rs:22:42
+   |
+LL |     multiple_ref_opt.map(|arg| takes_ref(arg));
+   |                      ---       --------- ^^^ expected `&Foo`, found struct `Foo`
+   |                      |         |
+   |                      |         arguments to this function are incorrect
+   |                      help: consider using `as_ref` instead: `as_ref().map`
+   |
+note: function defined here
+  --> $DIR/as-ref.rs:3:4
+   |
+LL | fn takes_ref(_: &Foo) {}
+   |    ^^^^^^^^^ -------
+
+error[E0308]: mismatched types
+  --> $DIR/as-ref.rs:23:52
+   |
+LL |     multiple_ref_opt.and_then(|arg| Some(takes_ref(arg)));
+   |                      --------            --------- ^^^ expected `&Foo`, found struct `Foo`
+   |                      |                   |
+   |                      |                   arguments to this function are incorrect
+   |                      help: consider using `as_ref` instead: `as_ref().and_then`
+   |
+note: function defined here
+  --> $DIR/as-ref.rs:3:4
+   |
+LL | fn takes_ref(_: &Foo) {}
+   |    ^^^^^^^^^ -------
+
+error[E0308]: mismatched types
+  --> $DIR/as-ref.rs:25:45
+   |
+LL |     multiple_ref_result.map(|arg| takes_ref(arg));
+   |                         ---       --------- ^^^ expected `&Foo`, found struct `Foo`
+   |                         |         |
+   |                         |         arguments to this function are incorrect
+   |                         help: consider using `as_ref` instead: `as_ref().map`
+   |
+note: function defined here
+  --> $DIR/as-ref.rs:3:4
+   |
+LL | fn takes_ref(_: &Foo) {}
+   |    ^^^^^^^^^ -------
+
+error[E0308]: mismatched types
+  --> $DIR/as-ref.rs:26:53
+   |
+LL |     multiple_ref_result.and_then(|arg| Ok(takes_ref(arg)));
+   |                         --------          --------- ^^^ expected `&Foo`, found struct `Foo`
+   |                         |                 |
+   |                         |                 arguments to this function are incorrect
+   |                         help: consider using `as_ref` instead: `as_ref().and_then`
+   |
+note: function defined here
+  --> $DIR/as-ref.rs:3:4
+   |
+LL | fn takes_ref(_: &Foo) {}
+   |    ^^^^^^^^^ -------
+
+error: aborting due to 11 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
index 6f46cfdf02467ffa934dc6d46aaedea1f2534ed2..c6fdcdadbeafc22822019764337289151c68180f 100644 (file)
@@ -14,38 +14,38 @@ fn main() {}
 const C2 = 42;
 //~^ ERROR missing type for `const` item
 //~| HELP provide a type for the item
-//~| SUGGESTION C2: <type>
+//~| SUGGESTION : <type>
 
 #[cfg(FALSE)]
 static S2 = "abc";
 //~^ ERROR missing type for `static` item
 //~| HELP provide a type for the item
-//~| SUGGESTION S2: <type>
+//~| SUGGESTION : <type>
 
 #[cfg(FALSE)]
 static mut SM2 = "abc";
 //~^ ERROR missing type for `static mut` item
 //~| HELP provide a type for the item
-//~| SUGGESTION SM2: <type>
+//~| SUGGESTION : <type>
 
 // These will, so the diagnostics should be stolen by typeck:
 
 const C = 42;
 //~^ ERROR missing type for `const` item
 //~| HELP provide a type for the constant
-//~| SUGGESTION C: i32
+//~| SUGGESTION : i32
 
 const D = &&42;
 //~^ ERROR missing type for `const` item
 //~| HELP provide a type for the constant
-//~| SUGGESTION D: &&i32
+//~| SUGGESTION : &&i32
 
 static S = Vec::<String>::new();
 //~^ ERROR missing type for `static` item
 //~| HELP provide a type for the static variable
-//~| SUGGESTION S: Vec<String>
+//~| SUGGESTION : Vec<String>
 
 static mut SM = "abc";
 //~^ ERROR missing type for `static mut` item
 //~| HELP provide a type for the static variable
-//~| SUGGESTION &str
+//~| SUGGESTION &str
index 3b0fd6337f1f15df902909f9493cc36f5b4306f9..bd703992fd4a623445a62f9e2c26b8c585ec223a 100644 (file)
@@ -1,44 +1,44 @@
 error: missing type for `const` item
-  --> $DIR/const-no-type.rs:33:7
+  --> $DIR/const-no-type.rs:33:8
    |
 LL | const C = 42;
-   |       ^ help: provide a type for the constant: `C: i32`
+   |        ^ help: provide a type for the constant: `: i32`
 
 error: missing type for `const` item
-  --> $DIR/const-no-type.rs:38:7
+  --> $DIR/const-no-type.rs:38:8
    |
 LL | const D = &&42;
-   |       ^ help: provide a type for the constant: `D: &&i32`
+   |        ^ help: provide a type for the constant: `: &&i32`
 
 error: missing type for `static` item
-  --> $DIR/const-no-type.rs:43:8
+  --> $DIR/const-no-type.rs:43:9
    |
 LL | static S = Vec::<String>::new();
-   |        ^ help: provide a type for the static variable: `S: Vec<String>`
+   |         ^ help: provide a type for the static variable: `: Vec<String>`
 
 error: missing type for `static mut` item
-  --> $DIR/const-no-type.rs:48:12
+  --> $DIR/const-no-type.rs:48:14
    |
 LL | static mut SM = "abc";
-   |            ^^ help: provide a type for the static variable: `SM: &str`
+   |              ^ help: provide a type for the static variable: `: &str`
 
 error: missing type for `const` item
-  --> $DIR/const-no-type.rs:14:7
+  --> $DIR/const-no-type.rs:14:9
    |
 LL | const C2 = 42;
-   |       ^^ help: provide a type for the item: `C2: <type>`
+   |         ^ help: provide a type for the item: `: <type>`
 
 error: missing type for `static` item
-  --> $DIR/const-no-type.rs:20:8
+  --> $DIR/const-no-type.rs:20:10
    |
 LL | static S2 = "abc";
-   |        ^^ help: provide a type for the item: `S2: <type>`
+   |          ^ help: provide a type for the item: `: <type>`
 
 error: missing type for `static mut` item
-  --> $DIR/const-no-type.rs:26:12
+  --> $DIR/const-no-type.rs:26:15
    |
 LL | static mut SM2 = "abc";
-   |            ^^^ help: provide a type for the item: `SM2: <type>`
+   |               ^ help: provide a type for the item: `: <type>`
 
 error: aborting due to 7 previous errors
 
index ca09c3d5ff1f08489280e723373baf98a667a317..e5443290f9e7a603f60dec3ac74f75d5a3233c47 100644 (file)
@@ -1,4 +1,4 @@
-error[E0507]: cannot move out of `s.0` which is behind a shared reference
+error[E0507]: cannot move out of `s` which is behind a shared reference
   --> $DIR/simple.rs:38:17
    |
 LL |     let X(_t) = *s;
@@ -7,7 +7,7 @@ LL |     let X(_t) = *s;
    |           data moved here
    |           move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
 
-error[E0507]: cannot move out of `r.0` which is behind a shared reference
+error[E0507]: cannot move out of `r` as enum variant `One` which is behind a shared reference
   --> $DIR/simple.rs:42:30
    |
 LL |     if let Either::One(_t) = *r { }
@@ -16,7 +16,7 @@ LL |     if let Either::One(_t) = *r { }
    |                        data moved here
    |                        move occurs because `_t` has type `X`, which does not implement the `Copy` trait
 
-error[E0507]: cannot move out of `r.0` which is behind a shared reference
+error[E0507]: cannot move out of `r` as enum variant `One` which is behind a shared reference
   --> $DIR/simple.rs:46:33
    |
 LL |     while let Either::One(_t) = *r { }
@@ -25,7 +25,7 @@ LL |     while let Either::One(_t) = *r { }
    |                           data moved here
    |                           move occurs because `_t` has type `X`, which does not implement the `Copy` trait
 
-error[E0507]: cannot move out of `r.0` which is behind a shared reference
+error[E0507]: cannot move out of `r` as enum variant `Two` which is behind a shared reference
   --> $DIR/simple.rs:50:11
    |
 LL |     match *r {
@@ -37,7 +37,7 @@ LL |         Either::One(_t)
    |                     data moved here
    |                     move occurs because `_t` has type `X`, which does not implement the `Copy` trait
 
-error[E0507]: cannot move out of `r.0` which is behind a shared reference
+error[E0507]: cannot move out of `r` as enum variant `One` which is behind a shared reference
   --> $DIR/simple.rs:57:11
    |
 LL |     match *r {
@@ -49,7 +49,7 @@ LL |         Either::One(_t) => (),
    |                     data moved here
    |                     move occurs because `_t` has type `X`, which does not implement the `Copy` trait
 
-error[E0507]: cannot move out of `sm.0` which is behind a mutable reference
+error[E0507]: cannot move out of `sm` which is behind a mutable reference
   --> $DIR/simple.rs:66:17
    |
 LL |     let X(_t) = *sm;
@@ -58,7 +58,7 @@ LL |     let X(_t) = *sm;
    |           data moved here
    |           move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
 
-error[E0507]: cannot move out of `rm.0` which is behind a mutable reference
+error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference
   --> $DIR/simple.rs:70:30
    |
 LL |     if let Either::One(_t) = *rm { }
@@ -67,7 +67,7 @@ LL |     if let Either::One(_t) = *rm { }
    |                        data moved here
    |                        move occurs because `_t` has type `X`, which does not implement the `Copy` trait
 
-error[E0507]: cannot move out of `rm.0` which is behind a mutable reference
+error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference
   --> $DIR/simple.rs:74:33
    |
 LL |     while let Either::One(_t) = *rm { }
@@ -76,7 +76,7 @@ LL |     while let Either::One(_t) = *rm { }
    |                           data moved here
    |                           move occurs because `_t` has type `X`, which does not implement the `Copy` trait
 
-error[E0507]: cannot move out of `rm.0` which is behind a mutable reference
+error[E0507]: cannot move out of `rm` as enum variant `Two` which is behind a mutable reference
   --> $DIR/simple.rs:78:11
    |
 LL |     match *rm {
@@ -88,7 +88,7 @@ LL |         Either::One(_t)
    |                     data moved here
    |                     move occurs because `_t` has type `X`, which does not implement the `Copy` trait
 
-error[E0507]: cannot move out of `rm.0` which is behind a mutable reference
+error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference
   --> $DIR/simple.rs:85:11
    |
 LL |     match *rm {
@@ -100,7 +100,7 @@ LL |         Either::One(_t) => (),
    |                     data moved here
    |                     move occurs because `_t` has type `X`, which does not implement the `Copy` trait
 
-error[E0507]: cannot move out of `rm.0` which is behind a mutable reference
+error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference
   --> $DIR/simple.rs:93:11
    |
 LL |     match *rm {
@@ -226,7 +226,7 @@ LL |         Either::One(_t) => (),
    |                     data moved here
    |                     move occurs because `_t` has type `X`, which does not implement the `Copy` trait
 
-error[E0507]: cannot move out of `s.0` which is behind a shared reference
+error[E0507]: cannot move out of `s` which is behind a shared reference
   --> $DIR/simple.rs:168:18
    |
 LL |     let &X(_t) = s;
@@ -236,7 +236,7 @@ LL |     let &X(_t) = s;
    |         |  move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
    |         help: consider removing the `&`: `X(_t)`
 
-error[E0507]: cannot move out of `r.0` which is behind a shared reference
+error[E0507]: cannot move out of `r` as enum variant `One` which is behind a shared reference
   --> $DIR/simple.rs:172:31
    |
 LL |     if let &Either::One(_t) = r { }
@@ -246,7 +246,7 @@ LL |     if let &Either::One(_t) = r { }
    |            |            move occurs because `_t` has type `X`, which does not implement the `Copy` trait
    |            help: consider removing the `&`: `Either::One(_t)`
 
-error[E0507]: cannot move out of `r.0` which is behind a shared reference
+error[E0507]: cannot move out of `r` as enum variant `One` which is behind a shared reference
   --> $DIR/simple.rs:176:34
    |
 LL |     while let &Either::One(_t) = r { }
@@ -256,7 +256,7 @@ LL |     while let &Either::One(_t) = r { }
    |               |            move occurs because `_t` has type `X`, which does not implement the `Copy` trait
    |               help: consider removing the `&`: `Either::One(_t)`
 
-error[E0507]: cannot move out of `r.0` which is behind a shared reference
+error[E0507]: cannot move out of `r` as enum variant `Two` which is behind a shared reference
   --> $DIR/simple.rs:180:11
    |
 LL |     match r {
@@ -276,7 +276,7 @@ LL +
 LL ~         | &Either::Two(_t) => (),
    |
 
-error[E0507]: cannot move out of `r.0` which is behind a shared reference
+error[E0507]: cannot move out of `r` as enum variant `One` which is behind a shared reference
   --> $DIR/simple.rs:188:11
    |
 LL |     match r {
@@ -289,7 +289,7 @@ LL |         &Either::One(_t) => (),
    |         |            move occurs because `_t` has type `X`, which does not implement the `Copy` trait
    |         help: consider removing the `&`: `Either::One(_t)`
 
-error[E0507]: cannot move out of `r.0` which is behind a shared reference
+error[E0507]: cannot move out of `r` as enum variant `One` which is behind a shared reference
   --> $DIR/simple.rs:195:11
    |
 LL |     match r {
@@ -302,7 +302,7 @@ LL |         &Either::One(_t) => (),
    |         |            move occurs because `_t` has type `X`, which does not implement the `Copy` trait
    |         help: consider removing the `&`: `Either::One(_t)`
 
-error[E0507]: cannot move out of `sm.0` which is behind a mutable reference
+error[E0507]: cannot move out of `sm` which is behind a mutable reference
   --> $DIR/simple.rs:207:22
    |
 LL |     let &mut X(_t) = sm;
@@ -312,7 +312,7 @@ LL |     let &mut X(_t) = sm;
    |         |      move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
    |         help: consider removing the `&mut`: `X(_t)`
 
-error[E0507]: cannot move out of `rm.0` which is behind a mutable reference
+error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference
   --> $DIR/simple.rs:211:35
    |
 LL |     if let &mut Either::One(_t) = rm { }
@@ -322,7 +322,7 @@ LL |     if let &mut Either::One(_t) = rm { }
    |            |                move occurs because `_t` has type `X`, which does not implement the `Copy` trait
    |            help: consider removing the `&mut`: `Either::One(_t)`
 
-error[E0507]: cannot move out of `rm.0` which is behind a mutable reference
+error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference
   --> $DIR/simple.rs:215:38
    |
 LL |     while let &mut Either::One(_t) = rm { }
@@ -332,7 +332,7 @@ LL |     while let &mut Either::One(_t) = rm { }
    |               |                move occurs because `_t` has type `X`, which does not implement the `Copy` trait
    |               help: consider removing the `&mut`: `Either::One(_t)`
 
-error[E0507]: cannot move out of `rm.0` which is behind a mutable reference
+error[E0507]: cannot move out of `rm` as enum variant `Two` which is behind a mutable reference
   --> $DIR/simple.rs:219:11
    |
 LL |     match rm {
@@ -354,7 +354,7 @@ help: consider removing the `&mut`
 LL |         Either::Two(_t) => (),
    |         ~~~~~~~~~~~~~~~
 
-error[E0507]: cannot move out of `rm.0` which is behind a mutable reference
+error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference
   --> $DIR/simple.rs:228:11
    |
 LL |     match rm {
@@ -367,7 +367,7 @@ LL |         &mut Either::One(_t) => (),
    |         |                move occurs because `_t` has type `X`, which does not implement the `Copy` trait
    |         help: consider removing the `&mut`: `Either::One(_t)`
 
-error[E0507]: cannot move out of `rm.0` which is behind a mutable reference
+error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference
   --> $DIR/simple.rs:235:11
    |
 LL |     match rm {
@@ -380,7 +380,7 @@ LL |         &mut Either::One(_t) => (),
    |         |                move occurs because `_t` has type `X`, which does not implement the `Copy` trait
    |         help: consider removing the `&mut`: `Either::One(_t)`
 
-error[E0507]: cannot move out of `rm.0` which is behind a mutable reference
+error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference
   --> $DIR/simple.rs:242:11
    |
 LL |     match rm {
diff --git a/src/test/ui/suggestions/field-access-considering-privacy.rs b/src/test/ui/suggestions/field-access-considering-privacy.rs
new file mode 100644 (file)
index 0000000..3de06b2
--- /dev/null
@@ -0,0 +1,35 @@
+use a::TyCtxt;
+
+mod a {
+    use std::ops::Deref;
+    pub struct TyCtxt<'tcx> {
+        gcx: &'tcx GlobalCtxt<'tcx>,
+    }
+
+    impl<'tcx> Deref for TyCtxt<'tcx> {
+        type Target = &'tcx GlobalCtxt<'tcx>;
+
+        fn deref(&self) -> &Self::Target {
+            &self.gcx
+        }
+    }
+
+    pub struct GlobalCtxt<'tcx> {
+        pub sess: &'tcx Session,
+        _t: &'tcx (),
+    }
+
+    pub struct Session {
+        pub opts: (),
+    }
+}
+
+mod b {
+    fn foo<'tcx>(tcx: crate::TyCtxt<'tcx>) {
+        tcx.opts;
+        //~^ ERROR no field `opts` on type `TyCtxt<'tcx>`
+        //~| HELP one of the expressions' fields has a field of the same name
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/field-access-considering-privacy.stderr b/src/test/ui/suggestions/field-access-considering-privacy.stderr
new file mode 100644 (file)
index 0000000..cbf6f3d
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0609]: no field `opts` on type `TyCtxt<'tcx>`
+  --> $DIR/field-access-considering-privacy.rs:29:13
+   |
+LL |         tcx.opts;
+   |             ^^^^ unknown field
+   |
+help: one of the expressions' fields has a field of the same name
+   |
+LL |         tcx.sess.opts;
+   |             +++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0609`.
index de64269d1f191de29783161554364d28693b2d88..ede3ebfa739c4f3ce3ca5e584799f62652aac022 100644 (file)
@@ -1,8 +1,8 @@
 error: missing type for `const` item
-  --> $DIR/unnamable-types.rs:6:7
+  --> $DIR/unnamable-types.rs:6:8
    |
 LL | const A = 5;
-   |       ^ help: provide a type for the constant: `A: i32`
+   |        ^ help: provide a type for the constant: `: i32`
 
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables
   --> $DIR/unnamable-types.rs:10:11
@@ -26,10 +26,10 @@ LL | const C: _ = || 42;
    |              ^^^^^
 
 error: missing type for `const` item
-  --> $DIR/unnamable-types.rs:23:7
+  --> $DIR/unnamable-types.rs:23:8
    |
 LL | const D = S { t: { let i = 0; move || -> i32 { i } } };
-   |       ^
+   |        ^
    |
 note: however, the inferred type `S<[closure@$DIR/unnamable-types.rs:23:31: 23:45]>` cannot be named
   --> $DIR/unnamable-types.rs:23:11
@@ -38,22 +38,22 @@ LL | const D = S { t: { let i = 0; move || -> i32 { i } } };
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing type for `const` item
-  --> $DIR/unnamable-types.rs:29:7
+  --> $DIR/unnamable-types.rs:29:8
    |
 LL | const E = foo;
-   |       ^ help: provide a type for the constant: `E: fn() -> i32`
+   |        ^ help: provide a type for the constant: `: fn() -> i32`
 
 error: missing type for `const` item
-  --> $DIR/unnamable-types.rs:32:7
+  --> $DIR/unnamable-types.rs:32:8
    |
 LL | const F = S { t: foo };
-   |       ^ help: provide a type for the constant: `F: S<fn() -> i32>`
+   |        ^ help: provide a type for the constant: `: S<fn() -> i32>`
 
 error: missing type for `const` item
-  --> $DIR/unnamable-types.rs:37:7
+  --> $DIR/unnamable-types.rs:37:8
    |
 LL | const G = || -> i32 { yield 0; return 1; };
-   |       ^
+   |        ^
    |
 note: however, the inferred type `[generator@$DIR/unnamable-types.rs:37:11: 37:20]` cannot be named
   --> $DIR/unnamable-types.rs:37:11
diff --git a/src/test/ui/tag-variant-disr-dup.rs b/src/test/ui/tag-variant-disr-dup.rs
deleted file mode 100644 (file)
index e497f99..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-// Black and White have the same discriminator value ...
-
-enum Color {
-    //~^ ERROR discriminant value `0` assigned more than once
-    Red = 0xff0000,
-    Green = 0x00ff00,
-    Blue = 0x0000ff,
-    Black = 0x000000,
-    White = 0x000000,
-}
-
-fn main() { }
diff --git a/src/test/ui/tag-variant-disr-dup.stderr b/src/test/ui/tag-variant-disr-dup.stderr
deleted file mode 100644 (file)
index 6b1ba43..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-error[E0081]: discriminant value `0` assigned more than once
-  --> $DIR/tag-variant-disr-dup.rs:3:1
-   |
-LL | enum Color {
-   | ^^^^^^^^^^
-...
-LL |     Black = 0x000000,
-   |             -------- first assignment of `0`
-LL |     White = 0x000000,
-   |             -------- second assignment of `0`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0081`.
index 97006ae50a0bf3a509f95e73f425ddc549d0c97d..90adba99e542bc8abdba5aa5758b0b5d4bdad5f1 100644 (file)
@@ -3,7 +3,7 @@
 
 fn f<T,>(_: T,) {}
 
-struct Foo<T,>(T);
+struct Foo<T,>(#[allow(unused_tuple_struct_fields)] T);
 
 struct Bar;
 
@@ -14,7 +14,7 @@ fn h(self,) {}
 }
 
 enum Baz {
-    Qux(isize,),
+    Qux(#[allow(unused_tuple_struct_fields)] isize,),
 }
 
 #[allow(unused,)]
index 579ce7cf70669c9f55c96078d84460a2c45d551d..d7d6241ef708cda1a68a922940d7a3963417a6ba 100644 (file)
@@ -4,13 +4,13 @@
 
 use std::vec::IntoIter;
 
-pub trait Foo: Iterator<Item=<Self as Foo>::Key> {
+pub trait Foo: Iterator<Item = <Self as Foo>::Key> {
     type Key;
 }
 
 impl Foo for IntoIter<i32> {
-    type Key = u32; //~ ERROR type mismatch
+    type Key = u32;
+    //~^ ERROR expected `std::vec::IntoIter<i32>` to be an iterator that yields `u32`, but it yields `i32`
 }
 
-fn main() {
-}
+fn main() {}
index f36947914179cc45e0f017f6dc32ef4ceb6e35c5..3e2d9d9038aa7c1e6b8655cd3fdf668cc42f6190 100644 (file)
@@ -1,4 +1,4 @@
-error[E0271]: type mismatch resolving `<std::vec::IntoIter<i32> as Iterator>::Item == u32`
+error[E0271]: expected `std::vec::IntoIter<i32>` to be an iterator that yields `u32`, but it yields `i32`
   --> $DIR/assoc-type-in-superbad.rs:12:16
    |
 LL |     type Key = u32;
@@ -7,8 +7,8 @@ LL |     type Key = u32;
 note: required by a bound in `Foo`
   --> $DIR/assoc-type-in-superbad.rs:7:25
    |
-LL | pub trait Foo: Iterator<Item=<Self as Foo>::Key> {
-   |                         ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo`
+LL | pub trait Foo: Iterator<Item = <Self as Foo>::Key> {
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo`
 
 error: aborting due to previous error
 
index 8c418daffdf5e101d5f95cc32ad03086f27c1842..747a5393f125734ae22b6ad4f1a826a3b8cb24fa 100644 (file)
@@ -1,7 +1,7 @@
 // run-pass
 use std::ops::AddAssign;
 
-struct Int(i32);
+struct Int(#[allow(unused_tuple_struct_fields)] i32);
 
 impl AddAssign for Int {
     fn add_assign(&mut self, _: Int) {
index 86dbd0aac0310a3f7439a21d1076c6910f64d232..f5d6d72afc2ca1092fc42c632e812c34944a195d 100644 (file)
@@ -4,11 +4,10 @@ warning: function cannot return without recursing
 LL | / fn recurse<T>(elements: T) -> Vec<char>
 LL | | where
 LL | |     T: Iterator<Item = ()>,
-LL | | {
-LL | |     recurse(IteratorOfWrapped(elements).map(|t| t.0))
-   | |     ------------------------------------------------- recursive call site
-LL | | }
-   | |_^ cannot return without recursing
+   | |___________________________^ cannot return without recursing
+LL |   {
+LL |       recurse(IteratorOfWrapped(elements).map(|t| t.0))
+   |       ------------------------------------------------- recursive call site
    |
    = note: `#[warn(unconditional_recursion)]` on by default
    = help: a `loop` may express intention better if this is on purpose
index 010dbf24664037008911504a4e58bd171bc86e43..a1042f8310a98c29d18b2b93a576fab48ea35018 100644 (file)
@@ -7,7 +7,7 @@
 pub struct WaitToken;
 impl !Send for WaitToken {}
 
-pub struct Test<T>(T);
+pub struct Test<T>(#[allow(unused_tuple_struct_fields)] T);
 unsafe impl<T: 'static> Send for Test<T> {}
 
 pub fn spawn<F>(_: F) -> () where F: FnOnce(), F: Send + 'static {}
index 0b8b0e2f5ef4d48e24c52495b6269f629f62b908..766dceeaffe00413247ddcadab56de69c7ed286e 100644 (file)
@@ -8,7 +8,7 @@ fn forget(self) where Self: Sized {
     }
 }
 
-struct Map<A>(A);
+struct Map<A>(#[allow(unused_tuple_struct_fields)] A);
 impl<A: Future> Future for Map<A> {}
 
 pub struct Promise;
index e5a96af3810de4121ee202554f81721b9b0dd5ca..5a4a6aecc6b957f754c6d88f4f18ed2263cbdc30 100644 (file)
@@ -25,7 +25,7 @@ pub fn step(&self) {
 
 // test for #8601
 
-enum Type<T> { Constant(T) }
+enum Type<T> { Constant(#[allow(unused_tuple_struct_fields)] T) }
 
 trait Trait<K,V> {
     fn method(&self, _: Type<(K,V)>) -> isize;
index f888246967d3dcdb215c21e0a91a7d52aeeb8b27..c333b0129c8d4e309682ab95234c33e79c4a322b 100644 (file)
@@ -13,8 +13,8 @@ impl Foo for () {
     type Bar = ();
 }
 
-struct Wrapper1<T: Foo>(<T as Foo>::Bar);
-struct Wrapper2<T: Foo>(<Wrapper1<T> as Pointee>::Metadata);
+struct Wrapper1<T: Foo>(#[allow(unused_tuple_struct_fields)] <T as Foo>::Bar);
+struct Wrapper2<T: Foo>(#[allow(unused_tuple_struct_fields)] <Wrapper1<T> as Pointee>::Metadata);
 
 fn main() {
     let _: Wrapper2<()> = Wrapper2(());
index 82c76eb693a0d65efb5d29e00eff0357db9b0f73..62bad0d7d77ab95100a9ed9226037c39ee9f1a99 100644 (file)
@@ -7,7 +7,7 @@
 // Array is to make sure the size is not exactly pointer-size, so
 // we can be sure we are measuring the right size in the
 // `size_of_val` test.
-struct SetOnDrop<'a>(&'a AtomicUsize, [u8; 64]);
+struct SetOnDrop<'a>(&'a AtomicUsize, #[allow(unused_tuple_struct_fields)] [u8; 64]);
 impl<'a> Drop for SetOnDrop<'a> {
     fn drop(&mut self) {
         self.0.store(self.0.load(Ordering::Relaxed) + 1, Ordering::Relaxed);
index ac005725ab48527f594766d47df862f6473c1786..15faab16abeaf11376c539af85819312e1c38235 100644 (file)
@@ -14,7 +14,7 @@ note: cycle used when collecting item types in top-level module
   --> $DIR/cyclic-trait-resolution.rs:1:1
    |
 LL | trait A: B + A {}
-   | ^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/transmutability/abstraction/abstracted_assume.rs b/src/test/ui/transmutability/abstraction/abstracted_assume.rs
new file mode 100644 (file)
index 0000000..2abbbf3
--- /dev/null
@@ -0,0 +1,73 @@
+// check-pass
+//! The implementation should behave correctly when the `ASSUME` parameters are
+//! provided indirectly through an abstraction.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+
+    pub fn is_transmutable<
+        Src,
+        Dst,
+        Context,
+        const ASSUME_ALIGNMENT: bool,
+        const ASSUME_LIFETIMES: bool,
+        const ASSUME_VALIDITY: bool,
+        const ASSUME_VISIBILITY: bool,
+    >()
+    where
+        Dst: BikeshedIntrinsicFrom<
+            Src,
+            Context,
+            ASSUME_ALIGNMENT,
+            ASSUME_LIFETIMES,
+            ASSUME_VALIDITY,
+            ASSUME_VISIBILITY,
+        >,
+    {}
+}
+
+fn direct() {
+    struct Context;
+    #[repr(C)] struct Src;
+    #[repr(C)] struct Dst;
+
+    assert::is_transmutable::<Src, Dst, Context, false, false, false, false>();
+}
+
+fn via_const() {
+    struct Context;
+    #[repr(C)] struct Src;
+    #[repr(C)] struct Dst;
+
+    const FALSE: bool = false;
+
+    assert::is_transmutable::<Src, Dst, Context, FALSE, FALSE, FALSE, FALSE>();
+}
+
+fn via_associated_const() {
+    struct Context;
+    #[repr(C)] struct Src;
+    #[repr(C)] struct Dst;
+
+    trait Trait {
+        const FALSE: bool = true;
+    }
+
+    struct Ty;
+
+    impl Trait for Ty {}
+
+    assert::is_transmutable::<
+        Src,
+        Dst,
+        Context,
+        {Ty::FALSE},
+        {Ty::FALSE},
+        {Ty::FALSE},
+        {Ty::FALSE}
+    >();
+}
diff --git a/src/test/ui/transmutability/abstraction/const_generic_fn.rs b/src/test/ui/transmutability/abstraction/const_generic_fn.rs
new file mode 100644 (file)
index 0000000..94c38bb
--- /dev/null
@@ -0,0 +1,41 @@
+// check-pass
+//! An array must have the correct length.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn array_like<T, E, const N: usize>()
+    where
+        T: BikeshedIntrinsicFrom<[E; N], Context, false, false, false, true>,
+        [E; N]: BikeshedIntrinsicFrom<T, Context, false, false, false, true>
+    {}
+}
+
+fn len_0() {
+    type Array = [u8; 0];
+    #[repr(C)] struct Struct();
+    assert::array_like::<Struct, u8, 0>();
+}
+
+fn len_1() {
+    type Array = [u8; 1];
+    #[repr(C)] struct Struct(u8);
+    assert::array_like::<Struct, u8, 1>();
+}
+
+fn len_2() {
+    type Array = [u8; 2];
+    #[repr(C)] struct Struct(u8, u8);
+    assert::array_like::<Struct, u8, 2>();
+}
+
+fn len_3() {
+    type Array = [u8; 3];
+    #[repr(C)] struct Struct(u8, u8, u8);
+    assert::array_like::<Struct, u8, 3>();
+}
diff --git a/src/test/ui/transmutability/arrays/should_have_correct_length.rs b/src/test/ui/transmutability/arrays/should_have_correct_length.rs
new file mode 100644 (file)
index 0000000..bfe6d83
--- /dev/null
@@ -0,0 +1,44 @@
+// check-pass
+//! An array must have the correct length.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_maybe_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+    {}
+}
+
+fn should_have_len_0() {
+    type Array = [u8; 0];
+    #[repr(C)] struct Struct();
+    assert::is_maybe_transmutable::<Array, Struct>();
+    assert::is_maybe_transmutable::<Struct, Array>();
+}
+
+fn should_have_len_1() {
+    type Array = [u8; 1];
+    #[repr(C)] struct Struct(u8);
+    assert::is_maybe_transmutable::<Array, Struct>();
+    assert::is_maybe_transmutable::<Struct, Array>();
+}
+
+fn should_have_len_2() {
+    type Array = [u8; 2];
+    #[repr(C)] struct Struct(u8, u8);
+    assert::is_maybe_transmutable::<Array, Struct>();
+    assert::is_maybe_transmutable::<Struct, Array>();
+}
+
+fn should_have_len_3() {
+    type Array = [u8; 3];
+    #[repr(C)] struct Struct(u8, u8, u8);
+    assert::is_maybe_transmutable::<Array, Struct>();
+    assert::is_maybe_transmutable::<Struct, Array>();
+}
diff --git a/src/test/ui/transmutability/arrays/should_inherit_alignment.rs b/src/test/ui/transmutability/arrays/should_inherit_alignment.rs
new file mode 100644 (file)
index 0000000..fcb1765
--- /dev/null
@@ -0,0 +1,55 @@
+// check-pass
+//! An array must inherit the alignment of its inner type.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_maybe_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+    {}
+}
+
+#[derive(Clone, Copy)] #[repr(u8)] enum Ox00 { V = 0x00 }
+#[derive(Clone, Copy)] #[repr(u8)] enum Ox01 { V = 0x01 }
+#[derive(Clone, Copy)] #[repr(u8)] enum OxFF { V = 0xFF }
+
+#[repr(C)]
+union Uninit {
+    a: (),
+    b: OxFF,
+}
+
+#[repr(C, align(2))] struct align_2(Ox00);
+
+fn len_0() {
+    #[repr(C)] struct ImplicitlyPadded([align_2; 0], Ox01);
+    #[repr(C)] struct ExplicitlyPadded(Ox01, Uninit);
+
+    #[repr(C)] struct Struct();
+    assert::is_maybe_transmutable::<ImplicitlyPadded, ExplicitlyPadded>();
+    assert::is_maybe_transmutable::<ExplicitlyPadded, ImplicitlyPadded>();
+}
+
+fn len_1() {
+    #[repr(C)] struct ImplicitlyPadded([align_2; 1], Ox01);
+    #[repr(C)] struct ExplicitlyPadded(Ox00, Uninit, Ox01, Uninit);
+
+    #[repr(C)] struct Struct();
+    assert::is_maybe_transmutable::<ImplicitlyPadded, ExplicitlyPadded>();
+    assert::is_maybe_transmutable::<ExplicitlyPadded, ImplicitlyPadded>();
+}
+
+fn len_2() {
+    #[repr(C)] struct ImplicitlyPadded([align_2; 2], Ox01);
+    #[repr(C)] struct ExplicitlyPadded(Ox00, Uninit, Ox00, Uninit, Ox01, Uninit);
+
+    #[repr(C)] struct Struct();
+    assert::is_maybe_transmutable::<ImplicitlyPadded, ExplicitlyPadded>();
+    assert::is_maybe_transmutable::<ExplicitlyPadded, ImplicitlyPadded>();
+}
diff --git a/src/test/ui/transmutability/arrays/should_require_well_defined_layout.rs b/src/test/ui/transmutability/arrays/should_require_well_defined_layout.rs
new file mode 100644 (file)
index 0000000..8e69527
--- /dev/null
@@ -0,0 +1,61 @@
+//! An array must have a well-defined layout to participate in a transmutation.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_maybe_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+    {}
+}
+
+fn should_reject_repr_rust()
+{
+    fn unit() {
+        type repr_rust = [String; 0];
+        assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
+        assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+    }
+
+    fn singleton() {
+        type repr_rust = [String; 1];
+        assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
+        assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+    }
+
+    fn duplex() {
+        type repr_rust = [String; 2];
+        assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
+        assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+    }
+}
+
+fn should_accept_repr_C()
+{
+    fn unit() {
+        #[repr(C)] struct repr_c(u8, u16, u8);
+        type array = [repr_c; 0];
+        assert::is_maybe_transmutable::<array, ()>();
+        assert::is_maybe_transmutable::<i128, array>();
+    }
+
+    fn singleton() {
+        #[repr(C)] struct repr_c(u8, u16, u8);
+        type array = [repr_c; 1];
+        assert::is_maybe_transmutable::<array, repr_c>();
+        assert::is_maybe_transmutable::<repr_c, array>();
+    }
+
+    fn duplex() {
+        #[repr(C)] struct repr_c(u8, u16, u8);
+        #[repr(C)] struct duplex(repr_c, repr_c);
+        type array = [repr_c; 2];
+        assert::is_maybe_transmutable::<array, duplex>();
+        assert::is_maybe_transmutable::<duplex, array>();
+    }
+}
diff --git a/src/test/ui/transmutability/arrays/should_require_well_defined_layout.stderr b/src/test/ui/transmutability/arrays/should_require_well_defined_layout.stderr
new file mode 100644 (file)
index 0000000..eae0c94
--- /dev/null
@@ -0,0 +1,99 @@
+error[E0277]: `[String; 0]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:21:52
+   |
+LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
+   |                                                    ^^ `[String; 0]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<[String; 0], assert::Context, true, true, true, true>` is not implemented for `()`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `u128` cannot be safely transmuted into `[String; 0]` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:22:47
+   |
+LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
+   |                                               ^^^^^^^^^ `u128` cannot be safely transmuted into `[String; 0]` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `[String; 0]`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `[String; 1]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:27:52
+   |
+LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
+   |                                                    ^^ `[String; 1]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<[String; 1], assert::Context, true, true, true, true>` is not implemented for `()`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `u128` cannot be safely transmuted into `[String; 1]` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:28:47
+   |
+LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
+   |                                               ^^^^^^^^^ `u128` cannot be safely transmuted into `[String; 1]` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `[String; 1]`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `[String; 2]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:33:52
+   |
+LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
+   |                                                    ^^ `[String; 2]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<[String; 2], assert::Context, true, true, true, true>` is not implemented for `()`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `u128` cannot be safely transmuted into `[String; 2]` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:34:47
+   |
+LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
+   |                                               ^^^^^^^^^ `u128` cannot be safely transmuted into `[String; 2]` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `[String; 2]`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.rs b/src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.rs
new file mode 100644 (file)
index 0000000..18e02b0
--- /dev/null
@@ -0,0 +1,149 @@
+//! An enum with a primitive repr should have exactly the size of that primitive.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+    {}
+}
+
+#[repr(C)]
+struct Zst;
+
+#[derive(Clone, Copy)]
+#[repr(i8)] enum V0i8 { V }
+#[repr(u8)] enum V0u8 { V }
+#[repr(i16)] enum V0i16 { V }
+#[repr(u16)] enum V0u16 { V }
+#[repr(i32)] enum V0i32 { V }
+#[repr(u32)] enum V0u32 { V }
+#[repr(i64)] enum V0i64 { V }
+#[repr(u64)] enum V0u64 { V }
+#[repr(isize)] enum V0isize { V }
+#[repr(usize)] enum V0usize { V }
+
+fn n8() {
+    struct Context;
+
+    type Smaller = Zst;
+    type Analog = u8;
+    type Larger = u16;
+
+    fn i_should_have_correct_length() {
+        type Current = V0i8;
+
+        assert::is_transmutable::<Smaller, Current, Context>(); //~ ERROR cannot be safely transmuted
+        assert::is_transmutable::<Current, Analog, Context>();
+        assert::is_transmutable::<Current, Larger, Context>(); //~ ERROR cannot be safely transmuted
+    }
+
+    fn u_should_have_correct_length() {
+        type Current = V0u8;
+
+        assert::is_transmutable::<Smaller, Current, Context>(); //~ ERROR cannot be safely transmuted
+        assert::is_transmutable::<Current, Analog, Context>();
+        assert::is_transmutable::<Current, Larger, Context>(); //~ ERROR cannot be safely transmuted
+    }
+}
+
+fn n16() {
+    struct Context;
+
+    type Smaller = u8;
+    type Analog = u16;
+    type Larger = u32;
+
+    fn i_should_have_correct_length() {
+        type Current = V0i16;
+
+        assert::is_transmutable::<Smaller, Current, Context>(); //~ ERROR cannot be safely transmuted
+        assert::is_transmutable::<Current, Analog, Context>();
+        assert::is_transmutable::<Current, Larger, Context>(); //~ ERROR cannot be safely transmuted
+    }
+
+    fn u_should_have_correct_length() {
+        type Current = V0u16;
+
+        assert::is_transmutable::<Smaller, Current, Context>(); //~ ERROR cannot be safely transmuted
+        assert::is_transmutable::<Current, Analog, Context>();
+        assert::is_transmutable::<Current, Larger, Context>(); //~ ERROR cannot be safely transmuted
+    }
+}
+
+fn n32() {
+    struct Context;
+
+    type Smaller = u16;
+    type Analog = u32;
+    type Larger = u64;
+
+    fn i_should_have_correct_length() {
+        type Current = V0i32;
+
+        assert::is_transmutable::<Smaller, Current, Context>(); //~ ERROR cannot be safely transmuted
+        assert::is_transmutable::<Current, Analog, Context>();
+        assert::is_transmutable::<Current, Larger, Context>(); //~ ERROR cannot be safely transmuted
+    }
+
+    fn u_should_have_correct_length() {
+        type Current = V0u32;
+
+        assert::is_transmutable::<Smaller, Current, Context>(); //~ ERROR cannot be safely transmuted
+        assert::is_transmutable::<Current, Analog, Context>();
+        assert::is_transmutable::<Current, Larger, Context>(); //~ ERROR cannot be safely transmuted
+    }
+}
+
+fn n64() {
+    struct Context;
+
+    type Smaller = u32;
+    type Analog = u64;
+    type Larger = u128;
+
+    fn i_should_have_correct_length() {
+        type Current = V0i64;
+
+        assert::is_transmutable::<Smaller, Current, Context>(); //~ ERROR cannot be safely transmuted
+        assert::is_transmutable::<Current, Analog, Context>();
+        assert::is_transmutable::<Current, Larger, Context>(); //~ ERROR cannot be safely transmuted
+    }
+
+    fn u_should_have_correct_length() {
+        type Current = V0u64;
+
+        assert::is_transmutable::<Smaller, Current, Context>(); //~ ERROR cannot be safely transmuted
+        assert::is_transmutable::<Current, Analog, Context>();
+        assert::is_transmutable::<Current, Larger, Context>(); //~ ERROR cannot be safely transmuted
+    }
+}
+
+fn nsize() {
+    struct Context;
+
+    type Smaller = u8;
+    type Analog = usize;
+    type Larger = [usize; 2];
+
+    fn i_should_have_correct_length() {
+        type Current = V0isize;
+
+        assert::is_transmutable::<Smaller, Current, Context>(); //~ ERROR cannot be safely transmuted
+        assert::is_transmutable::<Current, Analog, Context>();
+        assert::is_transmutable::<Current, Larger, Context>(); //~ ERROR cannot be safely transmuted
+    }
+
+    fn u_should_have_correct_length() {
+        type Current = V0usize;
+
+        assert::is_transmutable::<Smaller, Current, Context>(); //~ ERROR cannot be safely transmuted
+        assert::is_transmutable::<Current, Analog, Context>();
+        assert::is_transmutable::<Current, Larger, Context>(); //~ ERROR cannot be safely transmuted
+    }
+}
diff --git a/src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.stderr b/src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.stderr
new file mode 100644 (file)
index 0000000..fa2e3b8
--- /dev/null
@@ -0,0 +1,323 @@
+error[E0277]: `Zst` cannot be safely transmuted into `V0i8` in the defining scope of `n8::Context`.
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:41:44
+   |
+LL |         assert::is_transmutable::<Smaller, Current, Context>();
+   |                                            ^^^^^^^ `Zst` cannot be safely transmuted into `V0i8` in the defining scope of `n8::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<Zst, n8::Context, true, true, true, true>` is not implemented for `V0i8`
+note: required by a bound in `is_transmutable`
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `V0i8` cannot be safely transmuted into `u16` in the defining scope of `n8::Context`.
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:43:44
+   |
+LL |         assert::is_transmutable::<Current, Larger, Context>();
+   |                                            ^^^^^^ `V0i8` cannot be safely transmuted into `u16` in the defining scope of `n8::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<V0i8, n8::Context, true, true, true, true>` is not implemented for `u16`
+note: required by a bound in `is_transmutable`
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `Zst` cannot be safely transmuted into `V0u8` in the defining scope of `n8::Context`.
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:49:44
+   |
+LL |         assert::is_transmutable::<Smaller, Current, Context>();
+   |                                            ^^^^^^^ `Zst` cannot be safely transmuted into `V0u8` in the defining scope of `n8::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<Zst, n8::Context, true, true, true, true>` is not implemented for `V0u8`
+note: required by a bound in `is_transmutable`
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `V0u8` cannot be safely transmuted into `u16` in the defining scope of `n8::Context`.
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:51:44
+   |
+LL |         assert::is_transmutable::<Current, Larger, Context>();
+   |                                            ^^^^^^ `V0u8` cannot be safely transmuted into `u16` in the defining scope of `n8::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<V0u8, n8::Context, true, true, true, true>` is not implemented for `u16`
+note: required by a bound in `is_transmutable`
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `V0i16` in the defining scope of `n16::Context`.
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:65:44
+   |
+LL |         assert::is_transmutable::<Smaller, Current, Context>();
+   |                                            ^^^^^^^ `u8` cannot be safely transmuted into `V0i16` in the defining scope of `n16::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u8, n16::Context, true, true, true, true>` is not implemented for `V0i16`
+note: required by a bound in `is_transmutable`
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `V0i16` cannot be safely transmuted into `u32` in the defining scope of `n16::Context`.
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:67:44
+   |
+LL |         assert::is_transmutable::<Current, Larger, Context>();
+   |                                            ^^^^^^ `V0i16` cannot be safely transmuted into `u32` in the defining scope of `n16::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<V0i16, n16::Context, true, true, true, true>` is not implemented for `u32`
+note: required by a bound in `is_transmutable`
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `V0u16` in the defining scope of `n16::Context`.
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:73:44
+   |
+LL |         assert::is_transmutable::<Smaller, Current, Context>();
+   |                                            ^^^^^^^ `u8` cannot be safely transmuted into `V0u16` in the defining scope of `n16::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u8, n16::Context, true, true, true, true>` is not implemented for `V0u16`
+note: required by a bound in `is_transmutable`
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `V0u16` cannot be safely transmuted into `u32` in the defining scope of `n16::Context`.
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:75:44
+   |
+LL |         assert::is_transmutable::<Current, Larger, Context>();
+   |                                            ^^^^^^ `V0u16` cannot be safely transmuted into `u32` in the defining scope of `n16::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<V0u16, n16::Context, true, true, true, true>` is not implemented for `u32`
+note: required by a bound in `is_transmutable`
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u16` cannot be safely transmuted into `V0i32` in the defining scope of `n32::Context`.
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:89:44
+   |
+LL |         assert::is_transmutable::<Smaller, Current, Context>();
+   |                                            ^^^^^^^ `u16` cannot be safely transmuted into `V0i32` in the defining scope of `n32::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u16, n32::Context, true, true, true, true>` is not implemented for `V0i32`
+note: required by a bound in `is_transmutable`
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `V0i32` cannot be safely transmuted into `u64` in the defining scope of `n32::Context`.
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:91:44
+   |
+LL |         assert::is_transmutable::<Current, Larger, Context>();
+   |                                            ^^^^^^ `V0i32` cannot be safely transmuted into `u64` in the defining scope of `n32::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<V0i32, n32::Context, true, true, true, true>` is not implemented for `u64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u16` cannot be safely transmuted into `V0u32` in the defining scope of `n32::Context`.
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:97:44
+   |
+LL |         assert::is_transmutable::<Smaller, Current, Context>();
+   |                                            ^^^^^^^ `u16` cannot be safely transmuted into `V0u32` in the defining scope of `n32::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u16, n32::Context, true, true, true, true>` is not implemented for `V0u32`
+note: required by a bound in `is_transmutable`
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `V0u32` cannot be safely transmuted into `u64` in the defining scope of `n32::Context`.
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:99:44
+   |
+LL |         assert::is_transmutable::<Current, Larger, Context>();
+   |                                            ^^^^^^ `V0u32` cannot be safely transmuted into `u64` in the defining scope of `n32::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<V0u32, n32::Context, true, true, true, true>` is not implemented for `u64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u32` cannot be safely transmuted into `V0i64` in the defining scope of `n64::Context`.
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:113:44
+   |
+LL |         assert::is_transmutable::<Smaller, Current, Context>();
+   |                                            ^^^^^^^ `u32` cannot be safely transmuted into `V0i64` in the defining scope of `n64::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u32, n64::Context, true, true, true, true>` is not implemented for `V0i64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `V0i64` cannot be safely transmuted into `u128` in the defining scope of `n64::Context`.
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:115:44
+   |
+LL |         assert::is_transmutable::<Current, Larger, Context>();
+   |                                            ^^^^^^ `V0i64` cannot be safely transmuted into `u128` in the defining scope of `n64::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<V0i64, n64::Context, true, true, true, true>` is not implemented for `u128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u32` cannot be safely transmuted into `V0u64` in the defining scope of `n64::Context`.
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:121:44
+   |
+LL |         assert::is_transmutable::<Smaller, Current, Context>();
+   |                                            ^^^^^^^ `u32` cannot be safely transmuted into `V0u64` in the defining scope of `n64::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u32, n64::Context, true, true, true, true>` is not implemented for `V0u64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `V0u64` cannot be safely transmuted into `u128` in the defining scope of `n64::Context`.
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:123:44
+   |
+LL |         assert::is_transmutable::<Current, Larger, Context>();
+   |                                            ^^^^^^ `V0u64` cannot be safely transmuted into `u128` in the defining scope of `n64::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<V0u64, n64::Context, true, true, true, true>` is not implemented for `u128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `V0isize` in the defining scope of `nsize::Context`.
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:137:44
+   |
+LL |         assert::is_transmutable::<Smaller, Current, Context>();
+   |                                            ^^^^^^^ `u8` cannot be safely transmuted into `V0isize` in the defining scope of `nsize::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u8, nsize::Context, true, true, true, true>` is not implemented for `V0isize`
+note: required by a bound in `is_transmutable`
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `V0isize` cannot be safely transmuted into `[usize; 2]` in the defining scope of `nsize::Context`.
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:139:44
+   |
+LL |         assert::is_transmutable::<Current, Larger, Context>();
+   |                                            ^^^^^^ `V0isize` cannot be safely transmuted into `[usize; 2]` in the defining scope of `nsize::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<V0isize, nsize::Context, true, true, true, true>` is not implemented for `[usize; 2]`
+note: required by a bound in `is_transmutable`
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `V0usize` in the defining scope of `nsize::Context`.
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:145:44
+   |
+LL |         assert::is_transmutable::<Smaller, Current, Context>();
+   |                                            ^^^^^^^ `u8` cannot be safely transmuted into `V0usize` in the defining scope of `nsize::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u8, nsize::Context, true, true, true, true>` is not implemented for `V0usize`
+note: required by a bound in `is_transmutable`
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `V0usize` cannot be safely transmuted into `[usize; 2]` in the defining scope of `nsize::Context`.
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:147:44
+   |
+LL |         assert::is_transmutable::<Current, Larger, Context>();
+   |                                            ^^^^^^ `V0usize` cannot be safely transmuted into `[usize; 2]` in the defining scope of `nsize::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<V0usize, nsize::Context, true, true, true, true>` is not implemented for `[usize; 2]`
+note: required by a bound in `is_transmutable`
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error: aborting due to 20 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.rs b/src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.rs
new file mode 100644 (file)
index 0000000..978a126
--- /dev/null
@@ -0,0 +1,117 @@
+//! An enum must have a well-defined layout to participate in a transmutation.
+
+#![crate_type = "lib"]
+#![feature(repr128)]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_maybe_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+    {}
+}
+
+fn should_reject_repr_rust() {
+    fn void() {
+        enum repr_rust {}
+        assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
+        assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+    }
+
+    fn singleton() {
+        enum repr_rust { V }
+        assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
+        assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+    }
+
+    fn duplex() {
+        enum repr_rust { A, B }
+        assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
+        assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+    }
+}
+
+fn should_accept_primitive_reprs()
+{
+    fn should_accept_repr_i8() {
+        #[repr(i8)] enum repr_i8 { V }
+        assert::is_maybe_transmutable::<repr_i8, ()>();
+        assert::is_maybe_transmutable::<i8, repr_i8>();
+    }
+
+    fn should_accept_repr_u8() {
+        #[repr(u8)] enum repr_u8 { V }
+        assert::is_maybe_transmutable::<repr_u8, ()>();
+        assert::is_maybe_transmutable::<u8, repr_u8>();
+    }
+
+    fn should_accept_repr_i16() {
+        #[repr(i16)] enum repr_i16 { V }
+        assert::is_maybe_transmutable::<repr_i16, ()>();
+        assert::is_maybe_transmutable::<i16, repr_i16>();
+    }
+
+    fn should_accept_repr_u16() {
+        #[repr(u16)] enum repr_u16 { V }
+        assert::is_maybe_transmutable::<repr_u16, ()>();
+        assert::is_maybe_transmutable::<u16, repr_u16>();
+    }
+
+    fn should_accept_repr_i32() {
+        #[repr(i32)] enum repr_i32 { V }
+        assert::is_maybe_transmutable::<repr_i32, ()>();
+        assert::is_maybe_transmutable::<i32, repr_i32>();
+    }
+
+    fn should_accept_repr_u32() {
+        #[repr(u32)] enum repr_u32 { V }
+        assert::is_maybe_transmutable::<repr_u32, ()>();
+        assert::is_maybe_transmutable::<u32, repr_u32>();
+    }
+
+    fn should_accept_repr_i64() {
+        #[repr(i64)] enum repr_i64 { V }
+        assert::is_maybe_transmutable::<repr_i64, ()>();
+        assert::is_maybe_transmutable::<i64, repr_i64>();
+    }
+
+    fn should_accept_repr_u64() {
+        #[repr(u64)] enum repr_u64 { V }
+        assert::is_maybe_transmutable::<repr_u64, ()>();
+        assert::is_maybe_transmutable::<u64, repr_u64>();
+    }
+
+    fn should_accept_repr_i128() {
+        #[repr(i128)] enum repr_i128 { V }
+        assert::is_maybe_transmutable::<repr_i128, ()>();
+        assert::is_maybe_transmutable::<i128, repr_i128>();
+    }
+
+    fn should_accept_repr_u128() {
+        #[repr(u128)] enum repr_u128 { V }
+        assert::is_maybe_transmutable::<repr_u128, ()>();
+        assert::is_maybe_transmutable::<u128, repr_u128>();
+    }
+
+    fn should_accept_repr_isize() {
+        #[repr(isize)] enum repr_isize { V }
+        assert::is_maybe_transmutable::<repr_isize, ()>();
+        assert::is_maybe_transmutable::<isize, repr_isize>();
+    }
+
+    fn should_accept_repr_usize() {
+        #[repr(usize)] enum repr_usize { V }
+        assert::is_maybe_transmutable::<repr_usize, ()>();
+        assert::is_maybe_transmutable::<usize, repr_usize>();
+    }
+}
+
+fn should_accept_repr_C() {
+    #[repr(C)] enum repr_c { V }
+    assert::is_maybe_transmutable::<repr_c, ()>();
+    assert::is_maybe_transmutable::<i128, repr_c>();
+}
diff --git a/src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr b/src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr
new file mode 100644 (file)
index 0000000..3273e87
--- /dev/null
@@ -0,0 +1,99 @@
+error[E0277]: `void::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:21:52
+   |
+LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
+   |                                                    ^^ `void::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<void::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:14:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `u128` cannot be safely transmuted into `void::repr_rust` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:22:47
+   |
+LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
+   |                                               ^^^^^^^^^ `u128` cannot be safely transmuted into `void::repr_rust` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `void::repr_rust`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:14:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `singleton::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:27:52
+   |
+LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
+   |                                                    ^^ `singleton::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<singleton::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:14:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `u128` cannot be safely transmuted into `singleton::repr_rust` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:28:47
+   |
+LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
+   |                                               ^^^^^^^^^ `u128` cannot be safely transmuted into `singleton::repr_rust` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `singleton::repr_rust`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:14:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `duplex::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:33:52
+   |
+LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
+   |                                                    ^^ `duplex::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<duplex::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:14:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `u128` cannot be safely transmuted into `duplex::repr_rust` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:34:47
+   |
+LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
+   |                                               ^^^^^^^^^ `u128` cannot be safely transmuted into `duplex::repr_rust` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `duplex::repr_rust`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:14:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/transmutability/enums/should_order_correctly.rs b/src/test/ui/transmutability/enums/should_order_correctly.rs
new file mode 100644 (file)
index 0000000..6558d26
--- /dev/null
@@ -0,0 +1,32 @@
+// check-pass
+//! The payloads of an enum variant should be ordered after its tag.
+
+#![crate_type = "lib"]
+#![feature(arbitrary_enum_discriminant)]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+    {}
+}
+
+#[repr(u8)] enum V0 { V = 0 }
+#[repr(u8)] enum V1 { V = 1 }
+#[repr(u8)] enum V2 { V = 2 }
+
+#[repr(u8)] enum E01 { V0(V1) = 0u8 }
+#[repr(u8)] enum E012 { V0(V1, V2) = 0u8 }
+
+fn should_order_tag_and_fields_correctly() {
+    // An implementation that (incorrectly) arranges E01 as [0x01, 0x00] will,
+    // in principle, reject this transmutation.
+    assert::is_transmutable::<E01, V0>();
+    // Again, but with one more field.
+    assert::is_transmutable::<E012, E01>();
+}
diff --git a/src/test/ui/transmutability/enums/should_pad_variants.rs b/src/test/ui/transmutability/enums/should_pad_variants.rs
new file mode 100644 (file)
index 0000000..466b6c8
--- /dev/null
@@ -0,0 +1,40 @@
+//! The variants of an enum must be padded with uninit bytes such that they have
+//! the same length (in bytes).
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+    {}
+}
+
+#[derive(Clone, Copy)]
+#[repr(C)] struct Zst;
+
+#[derive(Clone, Copy)]
+#[repr(u8)] enum V0 { V = 0 }
+
+#[derive(Clone, Copy)]
+#[repr(u8)] enum V2 { V = 2 }
+
+#[repr(C, u8)]
+enum Lopsided {
+    Smol(Zst),
+    Lorg(V0),
+}
+
+#[repr(C)] struct Src(V0, Zst, V2);
+#[repr(C)] struct Dst(Lopsided, V2);
+
+fn should_pad_variants() {
+    struct Context;
+    // If the implementation (incorrectly) fails to pad `Lopsided::Smol` with
+    // an uninitialized byte, this transmutation might be (wrongly) accepted:
+    assert::is_transmutable::<Src, Dst, Context>(); //~ ERROR cannot be safely transmuted
+}
diff --git a/src/test/ui/transmutability/enums/should_pad_variants.stderr b/src/test/ui/transmutability/enums/should_pad_variants.stderr
new file mode 100644 (file)
index 0000000..429f721
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `should_pad_variants::Context`.
+  --> $DIR/should_pad_variants.rs:39:36
+   |
+LL |     assert::is_transmutable::<Src, Dst, Context>();
+   |                                    ^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `should_pad_variants::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<Src, should_pad_variants::Context, true, true, true, true>` is not implemented for `Dst`
+note: required by a bound in `is_transmutable`
+  --> $DIR/should_pad_variants.rs:13:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/transmutability/enums/should_respect_endianness.rs b/src/test/ui/transmutability/enums/should_respect_endianness.rs
new file mode 100644 (file)
index 0000000..67a3c4e
--- /dev/null
@@ -0,0 +1,33 @@
+//! The target endianness should be a consideration in computing the layout of
+//! an enum with a multi-byte tag.
+
+#![crate_type = "lib"]
+#![feature(arbitrary_enum_discriminant)]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+    {}
+}
+
+#[repr(u16)] enum Src { V = 0xCAFE }
+
+#[repr(u8)] enum OxCA { V = 0xCA }
+#[repr(u8)] enum OxFE { V = 0xFE }
+
+#[cfg(target_endian = "big")] #[repr(C)] struct Expected(OxCA, OxFE);
+#[cfg(target_endian = "big")] #[repr(C)] struct Unexpected(OxFE, OxCA);
+
+#[cfg(target_endian = "little")] #[repr(C)] struct Expected(OxFE, OxCA);
+#[cfg(target_endian = "little")] #[repr(C)] struct Unexpected(OxCA, OxFE);
+
+fn should_respect_endianness() {
+    assert::is_transmutable::<Src, Expected>();
+    assert::is_transmutable::<Src, Unexpected>(); //~ ERROR cannot be safely transmuted
+}
diff --git a/src/test/ui/transmutability/enums/should_respect_endianness.stderr b/src/test/ui/transmutability/enums/should_respect_endianness.stderr
new file mode 100644 (file)
index 0000000..78023cb
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0277]: `Src` cannot be safely transmuted into `Unexpected` in the defining scope of `assert::Context`.
+  --> $DIR/should_respect_endianness.rs:32:36
+   |
+LL |     assert::is_transmutable::<Src, Unexpected>();
+   |                                    ^^^^^^^^^^ `Src` cannot be safely transmuted into `Unexpected` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<Src, assert::Context, true, true, true, true>` is not implemented for `Unexpected`
+note: required by a bound in `is_transmutable`
+  --> $DIR/should_respect_endianness.rs:15:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.rs b/src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.rs
new file mode 100644 (file)
index 0000000..30c3817
--- /dev/null
@@ -0,0 +1,9 @@
+// The trait must not be available if its feature flag is absent.
+
+#![crate_type = "lib"]
+
+use std::mem::BikeshedIntrinsicFrom;
+//~^ ERROR use of unstable library feature 'transmutability' [E0658]
+
+use std::mem::Assume;
+//~^ ERROR use of unstable library feature 'transmutability' [E0658]
diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.stderr b/src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.stderr
new file mode 100644 (file)
index 0000000..ba8093f
--- /dev/null
@@ -0,0 +1,21 @@
+error[E0658]: use of unstable library feature 'transmutability'
+  --> $DIR/feature-missing.rs:5:5
+   |
+LL | use std::mem::BikeshedIntrinsicFrom;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #99571 <https://github.com/rust-lang/rust/issues/99571> for more information
+   = help: add `#![feature(transmutability)]` to the crate attributes to enable
+
+error[E0658]: use of unstable library feature 'transmutability'
+  --> $DIR/feature-missing.rs:8:5
+   |
+LL | use std::mem::Assume;
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #99571 <https://github.com/rust-lang/rust/issues/99571> for more information
+   = help: add `#![feature(transmutability)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/unknown_dst.rs b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_dst.rs
new file mode 100644 (file)
index 0000000..e13462d
--- /dev/null
@@ -0,0 +1,21 @@
+// An unknown destination type should be gracefully handled.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+    {}
+}
+
+fn should_gracefully_handle_unknown_dst() {
+    struct Context;
+    struct Src;
+    assert::is_transmutable::<Src, Dst, Context>(); //~ cannot find type
+}
diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/unknown_dst.stderr b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_dst.stderr
new file mode 100644 (file)
index 0000000..8508728
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0412]: cannot find type `Dst` in this scope
+  --> $DIR/unknown_dst.rs:20:36
+   |
+LL | fn should_gracefully_handle_unknown_dst() {
+   |                                        - help: you might be missing a type parameter: `<Dst>`
+...
+LL |     assert::is_transmutable::<Src, Dst, Context>();
+   |                                    ^^^ 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/transmutability/malformed-program-gracefulness/unknown_src.rs b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src.rs
new file mode 100644 (file)
index 0000000..dc51e2a
--- /dev/null
@@ -0,0 +1,21 @@
+// An unknown source type should be gracefully handled.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+    {}
+}
+
+fn should_gracefully_handle_unknown_src() {
+    struct Context;
+    #[repr(C)] struct Dst;
+    assert::is_transmutable::<Src, Dst, Context>(); //~ cannot find type
+}
diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src.stderr b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src.stderr
new file mode 100644 (file)
index 0000000..9bedbe8
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0412]: cannot find type `Src` in this scope
+  --> $DIR/unknown_src.rs:20:31
+   |
+LL | fn should_gracefully_handle_unknown_src() {
+   |                                        - help: you might be missing a type parameter: `<Src>`
+...
+LL |     assert::is_transmutable::<Src, Dst, Context>();
+   |                               ^^^ 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/transmutability/malformed-program-gracefulness/unknown_src_field.rs b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src_field.rs
new file mode 100644 (file)
index 0000000..86fc8bd
--- /dev/null
@@ -0,0 +1,22 @@
+// An unknown destination type should be gracefully handled.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+    {}
+}
+
+fn should_gracefully_handle_unknown_dst_field() {
+    struct Context;
+    #[repr(C)] struct Src;
+    #[repr(C)] struct Dst(Missing); //~ cannot find type
+    assert::is_transmutable::<Src, Dst, Context>();
+}
diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src_field.stderr b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src_field.stderr
new file mode 100644 (file)
index 0000000..475e6f4
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0412]: cannot find type `Missing` in this scope
+  --> $DIR/unknown_src_field.rs:20:27
+   |
+LL |     #[repr(C)] struct Dst(Missing);
+   |                           ^^^^^^^ 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/transmutability/malformed-program-gracefulness/wrong-type-assume.rs b/src/test/ui/transmutability/malformed-program-gracefulness/wrong-type-assume.rs
new file mode 100644 (file)
index 0000000..bd36748
--- /dev/null
@@ -0,0 +1,40 @@
+//! The implementation must behave well if const values of wrong types are
+//! provided.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+
+    pub fn is_transmutable<
+        Src,
+        Dst,
+        Context,
+        const ASSUME_ALIGNMENT: bool,
+        const ASSUME_LIFETIMES: bool,
+        const ASSUME_VALIDITY: bool,
+        const ASSUME_VISIBILITY: bool,
+    >()
+    where
+        Dst: BikeshedIntrinsicFrom<
+            Src,
+            Context,
+            ASSUME_ALIGNMENT,
+            ASSUME_LIFETIMES,
+            ASSUME_VALIDITY,
+            ASSUME_VISIBILITY,
+        >,
+    {}
+}
+
+fn test() {
+    struct Context;
+    #[repr(C)] struct Src;
+    #[repr(C)] struct Dst;
+    assert::is_transmutable::<Src, Dst, Context, {0u8}, false, false, false>(); //~ ERROR mismatched types
+    assert::is_transmutable::<Src, Dst, Context, false, {0u8}, false, false>(); //~ ERROR mismatched types
+    assert::is_transmutable::<Src, Dst, Context, false, false, {0u8}, false>(); //~ ERROR mismatched types
+    assert::is_transmutable::<Src, Dst, Context, false, false, false, {0u8}>(); //~ ERROR mismatched types
+}
diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/wrong-type-assume.stderr b/src/test/ui/transmutability/malformed-program-gracefulness/wrong-type-assume.stderr
new file mode 100644 (file)
index 0000000..e1464e0
--- /dev/null
@@ -0,0 +1,27 @@
+error[E0308]: mismatched types
+  --> $DIR/wrong-type-assume.rs:36:51
+   |
+LL |     assert::is_transmutable::<Src, Dst, Context, {0u8}, false, false, false>();
+   |                                                   ^^^ expected `bool`, found `u8`
+
+error[E0308]: mismatched types
+  --> $DIR/wrong-type-assume.rs:37:58
+   |
+LL |     assert::is_transmutable::<Src, Dst, Context, false, {0u8}, false, false>();
+   |                                                          ^^^ expected `bool`, found `u8`
+
+error[E0308]: mismatched types
+  --> $DIR/wrong-type-assume.rs:38:65
+   |
+LL |     assert::is_transmutable::<Src, Dst, Context, false, false, {0u8}, false>();
+   |                                                                 ^^^ expected `bool`, found `u8`
+
+error[E0308]: mismatched types
+  --> $DIR/wrong-type-assume.rs:39:72
+   |
+LL |     assert::is_transmutable::<Src, Dst, Context, false, false, false, {0u8}>();
+   |                                                                        ^^^ expected `bool`, found `u8`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/transmutability/primitives/bool.rs b/src/test/ui/transmutability/primitives/bool.rs
new file mode 100644 (file)
index 0000000..4f79bc2
--- /dev/null
@@ -0,0 +1,25 @@
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+#![allow(incomplete_features)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+    {}
+
+    pub fn is_maybe_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, true, true>
+    {}
+}
+
+fn contrast_with_u8() {
+    assert::is_transmutable::<u8, bool>(); //~ ERROR cannot be safely transmuted
+    assert::is_maybe_transmutable::<u8, bool>();
+    assert::is_transmutable::<bool, u8>();
+}
diff --git a/src/test/ui/transmutability/primitives/bool.stderr b/src/test/ui/transmutability/primitives/bool.stderr
new file mode 100644 (file)
index 0000000..dc74025
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0277]: `u8` cannot be safely transmuted into `bool` in the defining scope of `assert::Context`.
+  --> $DIR/bool.rs:22:35
+   |
+LL |     assert::is_transmutable::<u8, bool>();
+   |                                   ^^^^ `u8` cannot be safely transmuted into `bool` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, true>` is not implemented for `bool`
+note: required by a bound in `is_transmutable`
+  --> $DIR/bool.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/transmutability/primitives/numbers.rs b/src/test/ui/transmutability/primitives/numbers.rs
new file mode 100644 (file)
index 0000000..a5f7906
--- /dev/null
@@ -0,0 +1,128 @@
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+#![allow(incomplete_features)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    struct Context;
+
+    pub fn is_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+    {}
+}
+
+fn should_accept_identity() {
+    assert::is_transmutable::<   i8,    i8>();
+    assert::is_transmutable::<   u8,    u8>();
+    assert::is_transmutable::<  i16,   i16>();
+    assert::is_transmutable::<  u16,   u16>();
+    assert::is_transmutable::<  i32,   i32>();
+    assert::is_transmutable::<  f32,   f32>();
+    assert::is_transmutable::<  u32,   u32>();
+    assert::is_transmutable::<  i64,   i64>();
+    assert::is_transmutable::<  f64,   f64>();
+    assert::is_transmutable::<  u64,   u64>();
+    assert::is_transmutable::< i128,  i128>();
+    assert::is_transmutable::< u128,  u128>();
+    assert::is_transmutable::<isize, isize>();
+    assert::is_transmutable::<usize, usize>();
+}
+
+fn should_be_bitransmutable() {
+    assert::is_transmutable::<   i8,    u8>();
+    assert::is_transmutable::<   u8,    i8>();
+
+    assert::is_transmutable::<  i16,   u16>();
+    assert::is_transmutable::<  u16,   i16>();
+
+    assert::is_transmutable::<  i32,   f32>();
+    assert::is_transmutable::<  i32,   u32>();
+    assert::is_transmutable::<  f32,   i32>();
+    assert::is_transmutable::<  f32,   u32>();
+    assert::is_transmutable::<  u32,   i32>();
+    assert::is_transmutable::<  u32,   f32>();
+
+    assert::is_transmutable::<  u64,   i64>();
+    assert::is_transmutable::<  u64,   f64>();
+    assert::is_transmutable::<  i64,   u64>();
+    assert::is_transmutable::<  i64,   f64>();
+    assert::is_transmutable::<  f64,   u64>();
+    assert::is_transmutable::<  f64,   i64>();
+
+    assert::is_transmutable::< u128,  i128>();
+    assert::is_transmutable::< i128,  u128>();
+
+    assert::is_transmutable::<isize, usize>();
+    assert::is_transmutable::<usize, isize>();
+}
+
+fn should_reject_extension() {
+    assert::is_transmutable::<   i8,   i16>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<   i8,   u16>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<   i8,   i32>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<   i8,   f32>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<   i8,   u32>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<   i8,   u64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<   i8,   i64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<   i8,   f64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<   i8,  u128>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<   i8,  i128>(); //~ ERROR cannot be safely transmuted
+
+    assert::is_transmutable::<   u8,   i16>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<   u8,   u16>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<   u8,   i32>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<   u8,   f32>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<   u8,   u32>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<   u8,   u64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<   u8,   i64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<   u8,   f64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<   u8,  u128>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<   u8,  i128>(); //~ ERROR cannot be safely transmuted
+
+    assert::is_transmutable::<  i16,   i32>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  i16,   f32>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  i16,   u32>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  i16,   u64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  i16,   i64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  i16,   f64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  i16,  u128>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  i16,  i128>(); //~ ERROR cannot be safely transmuted
+
+    assert::is_transmutable::<  u16,   i32>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  u16,   f32>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  u16,   u32>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  u16,   u64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  u16,   i64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  u16,   f64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  u16,  u128>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  u16,  i128>(); //~ ERROR cannot be safely transmuted
+
+    assert::is_transmutable::<  i32,   u64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  i32,   i64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  i32,   f64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  i32,  u128>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  i32,  i128>(); //~ ERROR cannot be safely transmuted
+
+    assert::is_transmutable::<  f32,   u64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  f32,   i64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  f32,   f64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  f32,  u128>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  f32,  i128>(); //~ ERROR cannot be safely transmuted
+
+    assert::is_transmutable::<  u32,   u64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  u32,   i64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  u32,   f64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  u32,  u128>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  u32,  i128>(); //~ ERROR cannot be safely transmuted
+
+    assert::is_transmutable::<  u64,  u128>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  u64,  i128>(); //~ ERROR cannot be safely transmuted
+
+    assert::is_transmutable::<  i64,  u128>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  i64,  i128>(); //~ ERROR cannot be safely transmuted
+
+    assert::is_transmutable::<  f64,  u128>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  f64,  i128>(); //~ ERROR cannot be safely transmuted
+}
diff --git a/src/test/ui/transmutability/primitives/numbers.stderr b/src/test/ui/transmutability/primitives/numbers.stderr
new file mode 100644 (file)
index 0000000..9b802a4
--- /dev/null
@@ -0,0 +1,915 @@
+error[E0277]: `i8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:62:40
+   |
+LL |     assert::is_transmutable::<   i8,   i16>();
+   |                                        ^^^ `i8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `i16`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:63:40
+   |
+LL |     assert::is_transmutable::<   i8,   u16>();
+   |                                        ^^^ `i8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `u16`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:64:40
+   |
+LL |     assert::is_transmutable::<   i8,   i32>();
+   |                                        ^^^ `i8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `i32`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:65:40
+   |
+LL |     assert::is_transmutable::<   i8,   f32>();
+   |                                        ^^^ `i8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `f32`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:66:40
+   |
+LL |     assert::is_transmutable::<   i8,   u32>();
+   |                                        ^^^ `i8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `u32`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:67:40
+   |
+LL |     assert::is_transmutable::<   i8,   u64>();
+   |                                        ^^^ `i8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `u64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:68:40
+   |
+LL |     assert::is_transmutable::<   i8,   i64>();
+   |                                        ^^^ `i8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `i64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:69:40
+   |
+LL |     assert::is_transmutable::<   i8,   f64>();
+   |                                        ^^^ `i8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `f64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:70:39
+   |
+LL |     assert::is_transmutable::<   i8,  u128>();
+   |                                       ^^^^ `i8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `u128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:71:39
+   |
+LL |     assert::is_transmutable::<   i8,  i128>();
+   |                                       ^^^^ `i8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `i128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:73:40
+   |
+LL |     assert::is_transmutable::<   u8,   i16>();
+   |                                        ^^^ `u8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `i16`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:74:40
+   |
+LL |     assert::is_transmutable::<   u8,   u16>();
+   |                                        ^^^ `u8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `u16`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:75:40
+   |
+LL |     assert::is_transmutable::<   u8,   i32>();
+   |                                        ^^^ `u8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `i32`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:76:40
+   |
+LL |     assert::is_transmutable::<   u8,   f32>();
+   |                                        ^^^ `u8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `f32`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:77:40
+   |
+LL |     assert::is_transmutable::<   u8,   u32>();
+   |                                        ^^^ `u8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `u32`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:78:40
+   |
+LL |     assert::is_transmutable::<   u8,   u64>();
+   |                                        ^^^ `u8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `u64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:79:40
+   |
+LL |     assert::is_transmutable::<   u8,   i64>();
+   |                                        ^^^ `u8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `i64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:80:40
+   |
+LL |     assert::is_transmutable::<   u8,   f64>();
+   |                                        ^^^ `u8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `f64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:81:39
+   |
+LL |     assert::is_transmutable::<   u8,  u128>();
+   |                                       ^^^^ `u8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `u128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:82:39
+   |
+LL |     assert::is_transmutable::<   u8,  i128>();
+   |                                       ^^^^ `u8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `i128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:84:40
+   |
+LL |     assert::is_transmutable::<  i16,   i32>();
+   |                                        ^^^ `i16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, false, false, false, false>` is not implemented for `i32`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:85:40
+   |
+LL |     assert::is_transmutable::<  i16,   f32>();
+   |                                        ^^^ `i16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, false, false, false, false>` is not implemented for `f32`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:86:40
+   |
+LL |     assert::is_transmutable::<  i16,   u32>();
+   |                                        ^^^ `i16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, false, false, false, false>` is not implemented for `u32`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:87:40
+   |
+LL |     assert::is_transmutable::<  i16,   u64>();
+   |                                        ^^^ `i16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, false, false, false, false>` is not implemented for `u64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:88:40
+   |
+LL |     assert::is_transmutable::<  i16,   i64>();
+   |                                        ^^^ `i16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, false, false, false, false>` is not implemented for `i64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:89:40
+   |
+LL |     assert::is_transmutable::<  i16,   f64>();
+   |                                        ^^^ `i16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, false, false, false, false>` is not implemented for `f64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:90:39
+   |
+LL |     assert::is_transmutable::<  i16,  u128>();
+   |                                       ^^^^ `i16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, false, false, false, false>` is not implemented for `u128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:91:39
+   |
+LL |     assert::is_transmutable::<  i16,  i128>();
+   |                                       ^^^^ `i16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, false, false, false, false>` is not implemented for `i128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:93:40
+   |
+LL |     assert::is_transmutable::<  u16,   i32>();
+   |                                        ^^^ `u16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, false, false, false, false>` is not implemented for `i32`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:94:40
+   |
+LL |     assert::is_transmutable::<  u16,   f32>();
+   |                                        ^^^ `u16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, false, false, false, false>` is not implemented for `f32`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:95:40
+   |
+LL |     assert::is_transmutable::<  u16,   u32>();
+   |                                        ^^^ `u16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, false, false, false, false>` is not implemented for `u32`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:96:40
+   |
+LL |     assert::is_transmutable::<  u16,   u64>();
+   |                                        ^^^ `u16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, false, false, false, false>` is not implemented for `u64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:97:40
+   |
+LL |     assert::is_transmutable::<  u16,   i64>();
+   |                                        ^^^ `u16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, false, false, false, false>` is not implemented for `i64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:98:40
+   |
+LL |     assert::is_transmutable::<  u16,   f64>();
+   |                                        ^^^ `u16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, false, false, false, false>` is not implemented for `f64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:99:39
+   |
+LL |     assert::is_transmutable::<  u16,  u128>();
+   |                                       ^^^^ `u16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, false, false, false, false>` is not implemented for `u128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:100:39
+   |
+LL |     assert::is_transmutable::<  u16,  i128>();
+   |                                       ^^^^ `u16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, false, false, false, false>` is not implemented for `i128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:102:40
+   |
+LL |     assert::is_transmutable::<  i32,   u64>();
+   |                                        ^^^ `i32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i32, assert::Context, false, false, false, false>` is not implemented for `u64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:103:40
+   |
+LL |     assert::is_transmutable::<  i32,   i64>();
+   |                                        ^^^ `i32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i32, assert::Context, false, false, false, false>` is not implemented for `i64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:104:40
+   |
+LL |     assert::is_transmutable::<  i32,   f64>();
+   |                                        ^^^ `i32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i32, assert::Context, false, false, false, false>` is not implemented for `f64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:105:39
+   |
+LL |     assert::is_transmutable::<  i32,  u128>();
+   |                                       ^^^^ `i32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i32, assert::Context, false, false, false, false>` is not implemented for `u128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:106:39
+   |
+LL |     assert::is_transmutable::<  i32,  i128>();
+   |                                       ^^^^ `i32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i32, assert::Context, false, false, false, false>` is not implemented for `i128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `f32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:108:40
+   |
+LL |     assert::is_transmutable::<  f32,   u64>();
+   |                                        ^^^ `f32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<f32, assert::Context, false, false, false, false>` is not implemented for `u64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `f32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:109:40
+   |
+LL |     assert::is_transmutable::<  f32,   i64>();
+   |                                        ^^^ `f32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<f32, assert::Context, false, false, false, false>` is not implemented for `i64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `f32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:110:40
+   |
+LL |     assert::is_transmutable::<  f32,   f64>();
+   |                                        ^^^ `f32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<f32, assert::Context, false, false, false, false>` is not implemented for `f64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `f32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:111:39
+   |
+LL |     assert::is_transmutable::<  f32,  u128>();
+   |                                       ^^^^ `f32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<f32, assert::Context, false, false, false, false>` is not implemented for `u128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `f32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:112:39
+   |
+LL |     assert::is_transmutable::<  f32,  i128>();
+   |                                       ^^^^ `f32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<f32, assert::Context, false, false, false, false>` is not implemented for `i128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:114:40
+   |
+LL |     assert::is_transmutable::<  u32,   u64>();
+   |                                        ^^^ `u32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u32, assert::Context, false, false, false, false>` is not implemented for `u64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:115:40
+   |
+LL |     assert::is_transmutable::<  u32,   i64>();
+   |                                        ^^^ `u32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u32, assert::Context, false, false, false, false>` is not implemented for `i64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:116:40
+   |
+LL |     assert::is_transmutable::<  u32,   f64>();
+   |                                        ^^^ `u32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u32, assert::Context, false, false, false, false>` is not implemented for `f64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:117:39
+   |
+LL |     assert::is_transmutable::<  u32,  u128>();
+   |                                       ^^^^ `u32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u32, assert::Context, false, false, false, false>` is not implemented for `u128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:118:39
+   |
+LL |     assert::is_transmutable::<  u32,  i128>();
+   |                                       ^^^^ `u32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u32, assert::Context, false, false, false, false>` is not implemented for `i128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:120:39
+   |
+LL |     assert::is_transmutable::<  u64,  u128>();
+   |                                       ^^^^ `u64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u64, assert::Context, false, false, false, false>` is not implemented for `u128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:121:39
+   |
+LL |     assert::is_transmutable::<  u64,  i128>();
+   |                                       ^^^^ `u64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u64, assert::Context, false, false, false, false>` is not implemented for `i128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:123:39
+   |
+LL |     assert::is_transmutable::<  i64,  u128>();
+   |                                       ^^^^ `i64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i64, assert::Context, false, false, false, false>` is not implemented for `u128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:124:39
+   |
+LL |     assert::is_transmutable::<  i64,  i128>();
+   |                                       ^^^^ `i64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i64, assert::Context, false, false, false, false>` is not implemented for `i128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `f64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:126:39
+   |
+LL |     assert::is_transmutable::<  f64,  u128>();
+   |                                       ^^^^ `f64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<f64, assert::Context, false, false, false, false>` is not implemented for `u128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `f64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:127:39
+   |
+LL |     assert::is_transmutable::<  f64,  i128>();
+   |                                       ^^^^ `f64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<f64, assert::Context, false, false, false, false>` is not implemented for `i128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error: aborting due to 57 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/transmutability/primitives/unit.rs b/src/test/ui/transmutability/primitives/unit.rs
new file mode 100644 (file)
index 0000000..86d4740
--- /dev/null
@@ -0,0 +1,24 @@
+//! The unit type, `()`, should be one byte.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+    {}
+}
+
+#[repr(C)]
+struct Zst;
+
+fn should_have_correct_size() {
+    struct Context;
+    assert::is_transmutable::<(), Zst, Context>();
+    assert::is_transmutable::<Zst, (), Context>();
+    assert::is_transmutable::<(), u8, Context>(); //~ ERROR cannot be safely transmuted
+}
diff --git a/src/test/ui/transmutability/primitives/unit.stderr b/src/test/ui/transmutability/primitives/unit.stderr
new file mode 100644 (file)
index 0000000..cf27c0d
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0277]: `()` cannot be safely transmuted into `u8` in the defining scope of `should_have_correct_size::Context`.
+  --> $DIR/unit.rs:23:35
+   |
+LL |     assert::is_transmutable::<(), u8, Context>();
+   |                                   ^^ `()` cannot be safely transmuted into `u8` in the defining scope of `should_have_correct_size::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<(), should_have_correct_size::Context, true, true, true, true>` is not implemented for `u8`
+note: required by a bound in `is_transmutable`
+  --> $DIR/unit.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/transmutability/references.rs b/src/test/ui/transmutability/references.rs
new file mode 100644 (file)
index 0000000..c6fd4c4
--- /dev/null
@@ -0,0 +1,20 @@
+//! Transmutations involving references are not yet supported.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_maybe_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+    {}
+}
+
+fn not_yet_implemented() {
+    #[repr(C)] struct Unit;
+    assert::is_maybe_transmutable::<&'static Unit, &'static Unit>(); //~ ERROR cannot be safely transmuted
+}
diff --git a/src/test/ui/transmutability/references.stderr b/src/test/ui/transmutability/references.stderr
new file mode 100644 (file)
index 0000000..b1359ea
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0277]: `&'static Unit` cannot be safely transmuted into `&'static Unit` in the defining scope of `assert::Context`.
+  --> $DIR/references.rs:19:37
+   |
+LL |     assert::is_maybe_transmutable::<&'static Unit, &'static Unit>();
+   |                                     ^^^^^^^^^^^^^ `&'static Unit` cannot be safely transmuted into `&'static Unit` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<&'static Unit, assert::Context, true, true, true, true>` is not implemented for `&'static Unit`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/references.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/transmutability/structs/repr/should_handle_align.rs b/src/test/ui/transmutability/structs/repr/should_handle_align.rs
new file mode 100644 (file)
index 0000000..7172016
--- /dev/null
@@ -0,0 +1,36 @@
+// check-pass
+//! The presence of an `align(X)` annotation must be accounted for.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_maybe_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+    {}
+}
+
+fn should_pad_explicitly_aligned_field() {
+    #[derive(Clone, Copy)] #[repr(u8)] enum V0u8 { V = 0 }
+
+    #[repr(C)]
+    pub union Uninit {
+        a: (),
+        b: V0u8,
+    }
+
+    #[repr(C, align(2))] struct align_2(V0u8);
+
+    #[repr(C)] struct ImplicitlyPadded(align_2, V0u8);
+    #[repr(C)] struct ExplicitlyPadded(V0u8, Uninit, V0u8);
+
+    // An implementation that (incorrectly) does not place a padding byte after
+    // `align_2` will, incorrectly, reject the following transmutations.
+    assert::is_maybe_transmutable::<ImplicitlyPadded, ExplicitlyPadded>();
+    assert::is_maybe_transmutable::<ExplicitlyPadded, ImplicitlyPadded>();
+}
diff --git a/src/test/ui/transmutability/structs/repr/should_handle_packed.rs b/src/test/ui/transmutability/structs/repr/should_handle_packed.rs
new file mode 100644 (file)
index 0000000..ae8acf5
--- /dev/null
@@ -0,0 +1,35 @@
+// check-pass
+//! The presence of an `align(X)` annotation must be accounted for.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_maybe_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+    {}
+}
+
+fn should_pad_explicitly_packed_field() {
+    #[derive(Clone, Copy)] #[repr(u8)] enum V0u8 { V = 0 }
+    #[derive(Clone, Copy)] #[repr(u32)] enum V0u32 { V = 0 }
+
+    #[repr(C)]
+    pub union Uninit {
+        a: (),
+        b: V0u8,
+    }
+
+    #[repr(C, packed(2))] struct ImplicitlyPadded(V0u8, V0u32);
+    #[repr(C)] struct ExplicitlyPadded(V0u8, Uninit, V0u8, V0u8, V0u8, V0u8);
+
+    // An implementation that (incorrectly) does not place a padding byte after
+    // `align_2` will, incorrectly, reject the following transmutations.
+    assert::is_maybe_transmutable::<ImplicitlyPadded, ExplicitlyPadded>();
+    assert::is_maybe_transmutable::<ExplicitlyPadded, ImplicitlyPadded>();
+}
diff --git a/src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.rs b/src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.rs
new file mode 100644 (file)
index 0000000..556be98
--- /dev/null
@@ -0,0 +1,76 @@
+//! A struct must have a well-defined layout to participate in a transmutation.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_maybe_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+    {}
+}
+
+fn should_reject_repr_rust()
+{
+    fn unit() {
+        struct repr_rust;
+        assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
+        assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+    }
+
+    fn tuple() {
+        struct repr_rust();
+        assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
+        assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+    }
+
+    fn braces() {
+        struct repr_rust{}
+        assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
+        assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+    }
+
+    fn aligned() {
+        #[repr(align(1))] struct repr_rust{}
+        assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
+        assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+    }
+
+    fn packed() {
+        #[repr(packed)] struct repr_rust{}
+        assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
+        assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+    }
+
+    fn nested() {
+        struct repr_rust;
+        #[repr(C)] struct repr_c(repr_rust);
+        assert::is_maybe_transmutable::<repr_c, ()>(); //~ ERROR cannot be safely transmuted
+        assert::is_maybe_transmutable::<u128, repr_c>(); //~ ERROR cannot be safely transmuted
+    }
+}
+
+fn should_accept_repr_C()
+{
+    fn unit() {
+        #[repr(C)] struct repr_c;
+        assert::is_maybe_transmutable::<repr_c, ()>();
+        assert::is_maybe_transmutable::<i128, repr_c>();
+    }
+
+    fn tuple() {
+        #[repr(C)] struct repr_c();
+        assert::is_maybe_transmutable::<repr_c, ()>();
+        assert::is_maybe_transmutable::<i128, repr_c>();
+    }
+
+    fn braces() {
+        #[repr(C)] struct repr_c{}
+        assert::is_maybe_transmutable::<repr_c, ()>();
+        assert::is_maybe_transmutable::<i128, repr_c>();
+    }
+}
diff --git a/src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr b/src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr
new file mode 100644 (file)
index 0000000..07355f7
--- /dev/null
@@ -0,0 +1,195 @@
+error[E0277]: `should_reject_repr_rust::unit::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:21:52
+   |
+LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
+   |                                                    ^^ `should_reject_repr_rust::unit::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<should_reject_repr_rust::unit::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::unit::repr_rust` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:22:47
+   |
+LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
+   |                                               ^^^^^^^^^ `u128` cannot be safely transmuted into `should_reject_repr_rust::unit::repr_rust` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `should_reject_repr_rust::unit::repr_rust`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `should_reject_repr_rust::tuple::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:27:52
+   |
+LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
+   |                                                    ^^ `should_reject_repr_rust::tuple::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<should_reject_repr_rust::tuple::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::tuple::repr_rust` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:28:47
+   |
+LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
+   |                                               ^^^^^^^^^ `u128` cannot be safely transmuted into `should_reject_repr_rust::tuple::repr_rust` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `should_reject_repr_rust::tuple::repr_rust`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `should_reject_repr_rust::braces::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:33:52
+   |
+LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
+   |                                                    ^^ `should_reject_repr_rust::braces::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<should_reject_repr_rust::braces::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::braces::repr_rust` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:34:47
+   |
+LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
+   |                                               ^^^^^^^^^ `u128` cannot be safely transmuted into `should_reject_repr_rust::braces::repr_rust` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `should_reject_repr_rust::braces::repr_rust`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `aligned::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:39:52
+   |
+LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
+   |                                                    ^^ `aligned::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<aligned::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `u128` cannot be safely transmuted into `aligned::repr_rust` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:40:47
+   |
+LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
+   |                                               ^^^^^^^^^ `u128` cannot be safely transmuted into `aligned::repr_rust` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `aligned::repr_rust`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `packed::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:45:52
+   |
+LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
+   |                                                    ^^ `packed::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<packed::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `u128` cannot be safely transmuted into `packed::repr_rust` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:46:47
+   |
+LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
+   |                                               ^^^^^^^^^ `u128` cannot be safely transmuted into `packed::repr_rust` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `packed::repr_rust`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `nested::repr_c` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:52:49
+   |
+LL |         assert::is_maybe_transmutable::<repr_c, ()>();
+   |                                                 ^^ `nested::repr_c` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<nested::repr_c, assert::Context, true, true, true, true>` is not implemented for `()`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `u128` cannot be safely transmuted into `nested::repr_c` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:53:47
+   |
+LL |         assert::is_maybe_transmutable::<u128, repr_c>();
+   |                                               ^^^^^^ `u128` cannot be safely transmuted into `nested::repr_c` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `nested::repr_c`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error: aborting due to 12 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/transmutability/structs/should_order_fields_correctly.rs b/src/test/ui/transmutability/structs/should_order_fields_correctly.rs
new file mode 100644 (file)
index 0000000..db49b91
--- /dev/null
@@ -0,0 +1,31 @@
+// check-pass
+//! The fields of a struct should be laid out in lexical order.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+    {}
+}
+
+#[repr(u8)] enum V0 { V = 0 }
+#[repr(u8)] enum V1 { V = 1 }
+#[repr(u8)] enum V2 { V = 2 }
+
+#[repr(C)] struct S01(V0, V1);
+#[repr(C)] struct S012(V0, V1, V2);
+
+fn should_order_tag_and_fields_correctly() {
+    // An implementation that (incorrectly) arranges S01 as [0x01, 0x00] will,
+    // in principle, reject this transmutation.
+    assert::is_transmutable::<S01, V0>();
+    // Again, but with one more field.
+    assert::is_transmutable::<S012, S01>();
+}
diff --git a/src/test/ui/transmutability/unions/boolish.rs b/src/test/ui/transmutability/unions/boolish.rs
new file mode 100644 (file)
index 0000000..975118b
--- /dev/null
@@ -0,0 +1,31 @@
+// check-pass
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![feature(marker_trait_attr)]
+#![allow(dead_code)]
+#![allow(incomplete_features)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+    {}
+}
+
+fn should_match_bool() {
+    #[derive(Copy, Clone)] #[repr(u8)] pub enum False { V = 0 }
+    #[derive(Copy, Clone)] #[repr(u8)] pub enum True { V = 1 }
+
+    #[repr(C)]
+    pub union Bool {
+        pub f: False,
+        pub t: True,
+    }
+
+    assert::is_transmutable::<Bool, bool>();
+    assert::is_transmutable::<bool, Bool>();
+}
diff --git a/src/test/ui/transmutability/unions/repr/should_handle_align.rs b/src/test/ui/transmutability/unions/repr/should_handle_align.rs
new file mode 100644 (file)
index 0000000..e215799
--- /dev/null
@@ -0,0 +1,40 @@
+// check-pass
+//! The presence of an `align(X)` annotation must be accounted for.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_maybe_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+    {}
+}
+
+fn should_pad_explicitly_aligned_field() {
+    #[derive(Clone, Copy)] #[repr(u8)] enum V0u8 { V = 0 }
+    #[derive(Clone, Copy)] #[repr(u8)] enum V1u8 { V = 1 }
+
+    #[repr(C)]
+    pub union Uninit {
+        a: (),
+        b: V1u8,
+    }
+
+    #[repr(C, align(2))]
+    pub union align_2 {
+        a: V0u8,
+    }
+
+    #[repr(C)] struct ImplicitlyPadded(align_2, V0u8);
+    #[repr(C)] struct ExplicitlyPadded(V0u8, Uninit, V0u8);
+
+    // An implementation that (incorrectly) does not place a padding byte after
+    // `align_2` will, incorrectly, reject the following transmutations.
+    assert::is_maybe_transmutable::<ImplicitlyPadded, ExplicitlyPadded>();
+    assert::is_maybe_transmutable::<ExplicitlyPadded, ImplicitlyPadded>();
+}
diff --git a/src/test/ui/transmutability/unions/repr/should_handle_packed.rs b/src/test/ui/transmutability/unions/repr/should_handle_packed.rs
new file mode 100644 (file)
index 0000000..34a53c7
--- /dev/null
@@ -0,0 +1,41 @@
+// check-pass
+//! The presence of an `align(X)` annotation must be accounted for.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_maybe_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+    {}
+}
+
+fn should_pad_explicitly_packed_field() {
+    #[derive(Clone, Copy)] #[repr(u8)] enum V0u8 { V = 0 }
+    #[derive(Clone, Copy)] #[repr(u8)] enum V1u8 { V = 1 }
+    #[derive(Clone, Copy)] #[repr(u8)] enum V2u8 { V = 2 }
+    #[derive(Clone, Copy)] #[repr(u32)] enum V3u32 { V = 3 }
+
+    #[repr(C)]
+    pub union Uninit {
+        a: (),
+        b: V1u8,
+    }
+
+    #[repr(C, packed(2))]
+    pub union Packed {
+        a: [V3u32; 0],
+        b: V0u8,
+    }
+
+    #[repr(C)] struct ImplicitlyPadded(Packed, V2u8);
+    #[repr(C)] struct ExplicitlyPadded(V0u8, Uninit, V2u8);
+
+    assert::is_maybe_transmutable::<ImplicitlyPadded, ExplicitlyPadded>();
+    assert::is_maybe_transmutable::<ExplicitlyPadded, ImplicitlyPadded>();
+}
diff --git a/src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.rs b/src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.rs
new file mode 100644 (file)
index 0000000..cec8e38
--- /dev/null
@@ -0,0 +1,37 @@
+//! A struct must have a well-defined layout to participate in a transmutation.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_maybe_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+    {}
+}
+
+fn should_reject_repr_rust()
+{
+    union repr_rust {
+        a: u8
+    }
+
+    assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
+    assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+}
+
+fn should_accept_repr_C()
+{
+    #[repr(C)]
+    union repr_c {
+        a: u8
+    }
+
+    struct repr_rust;
+    assert::is_maybe_transmutable::<repr_c, ()>();
+    assert::is_maybe_transmutable::<u128, repr_c>();
+}
diff --git a/src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr b/src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr
new file mode 100644 (file)
index 0000000..2ed01b1
--- /dev/null
@@ -0,0 +1,35 @@
+error[E0277]: `should_reject_repr_rust::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:23:48
+   |
+LL |     assert::is_maybe_transmutable::<repr_rust, ()>();
+   |                                                ^^ `should_reject_repr_rust::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<should_reject_repr_rust::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::repr_rust` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:24:43
+   |
+LL |     assert::is_maybe_transmutable::<u128, repr_rust>();
+   |                                           ^^^^^^^^^ `u128` cannot be safely transmuted into `should_reject_repr_rust::repr_rust` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `should_reject_repr_rust::repr_rust`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/transmutability/unions/should_pad_variants.rs b/src/test/ui/transmutability/unions/should_pad_variants.rs
new file mode 100644 (file)
index 0000000..c475790
--- /dev/null
@@ -0,0 +1,40 @@
+//! The variants of a union must be padded with uninit bytes such that they have
+//! the same length (in bytes).
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+    {}
+}
+
+#[derive(Clone, Copy)]
+#[repr(C)] struct Zst;
+
+#[derive(Clone, Copy)]
+#[repr(u8)] enum V0 { V = 0 }
+
+#[derive(Clone, Copy)]
+#[repr(u8)] enum V2 { V = 2 }
+
+#[repr(C)]
+union Lopsided {
+    smol: Zst,
+    lorg: V0,
+}
+
+#[repr(C)] struct Src(V0, Zst, V2);
+#[repr(C)] struct Dst(V0, Lopsided, V2);
+
+fn should_pad_variants() {
+    struct Context;
+    // If the implementation (incorrectly) fails to pad `Lopsided::smol` with
+    // an uninitialized byte, this transmutation might be (wrongly) accepted:
+    assert::is_transmutable::<Src, Dst, Context>(); //~ ERROR cannot be safely transmuted
+}
diff --git a/src/test/ui/transmutability/unions/should_pad_variants.stderr b/src/test/ui/transmutability/unions/should_pad_variants.stderr
new file mode 100644 (file)
index 0000000..429f721
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `should_pad_variants::Context`.
+  --> $DIR/should_pad_variants.rs:39:36
+   |
+LL |     assert::is_transmutable::<Src, Dst, Context>();
+   |                                    ^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `should_pad_variants::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<Src, should_pad_variants::Context, true, true, true, true>` is not implemented for `Dst`
+note: required by a bound in `is_transmutable`
+  --> $DIR/should_pad_variants.rs:13:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/transmutability/unions/should_permit_intersecting_if_validity_is_assumed.rs b/src/test/ui/transmutability/unions/should_permit_intersecting_if_validity_is_assumed.rs
new file mode 100644 (file)
index 0000000..2493d71
--- /dev/null
@@ -0,0 +1,39 @@
+// check-pass
+//! If validity is assumed, there need only be one matching bit-pattern between
+//! the source and destination types.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_maybe_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, true, true>
+        // validity IS assumed --------------------------------^^^^
+    {}
+}
+
+#[derive(Clone, Copy)] #[repr(u8)] enum Ox00 { V = 0x00 }
+#[derive(Clone, Copy)] #[repr(u8)] enum Ox7F { V = 0x7F }
+#[derive(Clone, Copy)] #[repr(u8)] enum OxFF { V = 0xFF }
+
+fn test() {
+    #[repr(C)]
+    union A {
+        a: Ox00,
+        b: Ox7F,
+    }
+
+    #[repr(C)]
+    union B {
+        a: Ox7F,
+        b: OxFF,
+    }
+
+    assert::is_maybe_transmutable::<A, B>();
+    assert::is_maybe_transmutable::<B, A>();
+}
diff --git a/src/test/ui/transmutability/unions/should_reject_contraction.rs b/src/test/ui/transmutability/unions/should_reject_contraction.rs
new file mode 100644 (file)
index 0000000..e8138d0
--- /dev/null
@@ -0,0 +1,36 @@
+//! Validity may not be contracted, unless validity is assumed.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+    {}
+}
+
+#[derive(Clone, Copy)] #[repr(u8)] enum Ox00 { V = 0x00 }
+#[derive(Clone, Copy)] #[repr(u8)] enum Ox01 { V = 0x01 }
+#[derive(Clone, Copy)] #[repr(u8)] enum OxFF { V = 0xFF }
+
+fn test() {
+    #[repr(C)]
+    union Subset {
+        a: Ox00,
+        b: OxFF,
+    }
+
+    #[repr(C)]
+    union Superset {
+        a: Ox00,
+        b: OxFF,
+        c: Ox01,
+    }
+
+    assert::is_transmutable::<Superset, Subset>(); //~ ERROR cannot be safely transmuted
+}
diff --git a/src/test/ui/transmutability/unions/should_reject_contraction.stderr b/src/test/ui/transmutability/unions/should_reject_contraction.stderr
new file mode 100644 (file)
index 0000000..99f5890
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0277]: `Superset` cannot be safely transmuted into `Subset` in the defining scope of `assert::Context`.
+  --> $DIR/should_reject_contraction.rs:35:41
+   |
+LL |     assert::is_transmutable::<Superset, Subset>();
+   |                                         ^^^^^^ `Superset` cannot be safely transmuted into `Subset` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<Superset, assert::Context, false, false, false, true>` is not implemented for `Subset`
+note: required by a bound in `is_transmutable`
+  --> $DIR/should_reject_contraction.rs:13:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/transmutability/unions/should_reject_disjoint.rs b/src/test/ui/transmutability/unions/should_reject_disjoint.rs
new file mode 100644 (file)
index 0000000..16160e2
--- /dev/null
@@ -0,0 +1,36 @@
+//! Validity must be satisfiable, even if validity is assumed.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_maybe_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, true, true>
+        // validity IS assumed --------------------------------^^^^
+    {}
+}
+
+#[derive(Clone, Copy)] #[repr(u8)] enum Ox00 { V = 0x00 }
+#[derive(Clone, Copy)] #[repr(u8)] enum Ox01 { V = 0x01 }
+#[derive(Clone, Copy)] #[repr(u8)] enum OxFF { V = 0xFF }
+
+fn test() {
+    #[repr(C)]
+    union A {
+        a: Ox00,
+        b: OxFF,
+    }
+
+    #[repr(C)]
+    union B {
+        c: Ox01,
+    }
+
+    assert::is_maybe_transmutable::<A, B>(); //~ ERROR cannot be safely transmuted
+    assert::is_maybe_transmutable::<B, A>(); //~ ERROR cannot be safely transmuted
+}
diff --git a/src/test/ui/transmutability/unions/should_reject_disjoint.stderr b/src/test/ui/transmutability/unions/should_reject_disjoint.stderr
new file mode 100644 (file)
index 0000000..5714e2b
--- /dev/null
@@ -0,0 +1,35 @@
+error[E0277]: `A` cannot be safely transmuted into `B` in the defining scope of `assert::Context`.
+  --> $DIR/should_reject_disjoint.rs:34:40
+   |
+LL |     assert::is_maybe_transmutable::<A, B>();
+   |                                        ^ `A` cannot be safely transmuted into `B` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<A, assert::Context, false, false, true, true>` is not implemented for `B`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_reject_disjoint.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context`.
+  --> $DIR/should_reject_disjoint.rs:35:40
+   |
+LL |     assert::is_maybe_transmutable::<B, A>();
+   |                                        ^ `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<B, assert::Context, false, false, true, true>` is not implemented for `A`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_reject_disjoint.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/transmutability/unions/should_reject_intersecting.rs b/src/test/ui/transmutability/unions/should_reject_intersecting.rs
new file mode 100644 (file)
index 0000000..58e399f
--- /dev/null
@@ -0,0 +1,38 @@
+//! ALL valid bit patterns of the source must be valid bit patterns of the
+//! destination type, unless validity is assumed.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+        // validity is NOT assumed ----------------------------^^^^^
+    {}
+}
+
+#[derive(Clone, Copy)] #[repr(u8)] enum Ox00 { V = 0x00 }
+#[derive(Clone, Copy)] #[repr(u8)] enum Ox7F { V = 0x7F }
+#[derive(Clone, Copy)] #[repr(u8)] enum OxFF { V = 0xFF }
+
+fn test() {
+    #[repr(C)]
+    union A {
+        a: Ox00,
+        b: Ox7F,
+    }
+
+    #[repr(C)]
+    union B {
+        a: Ox7F,
+        b: OxFF,
+    }
+
+    assert::is_transmutable::<A, B>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<B, A>(); //~ ERROR cannot be safely transmuted
+}
diff --git a/src/test/ui/transmutability/unions/should_reject_intersecting.stderr b/src/test/ui/transmutability/unions/should_reject_intersecting.stderr
new file mode 100644 (file)
index 0000000..92689a5
--- /dev/null
@@ -0,0 +1,35 @@
+error[E0277]: `A` cannot be safely transmuted into `B` in the defining scope of `assert::Context`.
+  --> $DIR/should_reject_intersecting.rs:36:34
+   |
+LL |     assert::is_transmutable::<A, B>();
+   |                                  ^ `A` cannot be safely transmuted into `B` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<A, assert::Context, false, false, false, true>` is not implemented for `B`
+note: required by a bound in `is_transmutable`
+  --> $DIR/should_reject_intersecting.rs:14:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context`.
+  --> $DIR/should_reject_intersecting.rs:37:34
+   |
+LL |     assert::is_transmutable::<B, A>();
+   |                                  ^ `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<B, assert::Context, false, false, false, true>` is not implemented for `A`
+note: required by a bound in `is_transmutable`
+  --> $DIR/should_reject_intersecting.rs:14:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_private_field.rs b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_private_field.rs
new file mode 100644 (file)
index 0000000..5a8c810
--- /dev/null
@@ -0,0 +1,38 @@
+// check-pass
+//! If visibility is assumed, a transmutation should be accepted even if the
+//! destination type contains a private field.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+        // visibility IS assumed -------------------------------------^^^^
+    {}
+}
+
+mod src {
+    #[repr(C)] pub(self) struct Zst;
+
+    #[repr(C)] pub(in super) struct Src {
+        pub(self) field: Zst,
+    }
+}
+
+mod dst {
+    #[repr(C)] pub(in super) struct Zst;
+
+    #[repr(C)] pub(in super) struct Dst {
+        pub(self) field: Zst, // <- private field
+    }
+}
+
+fn test() {
+    struct Context;
+    assert::is_transmutable::<src::Src, dst::Dst, Context>();
+}
diff --git a/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_private_variant.rs b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_private_variant.rs
new file mode 100644 (file)
index 0000000..77ab4fa
--- /dev/null
@@ -0,0 +1,39 @@
+// check-pass
+//! If visibility is assumed, a transmutation should be accepted even if the
+//! destination type contains a private variant.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+        // visibility IS assumed -------------------------------------^^^^
+    {}
+}
+
+mod src {
+    #[repr(C)] pub(self) struct Zst;
+
+    #[repr(C)] pub(in super) struct Src {
+        pub(self) field: Zst,
+    }
+}
+
+mod dst {
+    #[derive(Copy, Clone)]
+    #[repr(C)] pub(in super) struct Zst;
+
+    #[repr(C)] pub(in super) union Dst {
+        pub(self) field: Zst, // <- private variant
+    }
+}
+
+fn test() {
+    struct Context;
+    assert::is_transmutable::<src::Src, dst::Dst, Context>();
+}
diff --git a/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_tricky_unreachable_field.rs b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_tricky_unreachable_field.rs
new file mode 100644 (file)
index 0000000..2421b24
--- /dev/null
@@ -0,0 +1,46 @@
+// check-pass
+//! Unless visibility is assumed, a transmutation should be rejected if the
+//! destination type contains an unreachable field (e.g., a public field with a
+//! private type). (This rule is distinct from type privacy, which still may
+//! forbid naming such types.)
+//!
+//! This test exercises a tricky-to-implement instance of this principle: the
+//! "pub-in-priv trick". In the below example, the type `dst::private::Zst` is
+//! unreachable from `Context`.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+        // visibility IS assumed -------------------------------------^^^^
+    {}
+}
+
+mod src {
+    #[repr(C)] pub(in super) struct Zst;
+
+    #[repr(C)] pub(in super) struct Src {
+        pub(in super) field: Zst,
+    }
+}
+
+mod dst {
+    mod private {
+        #[repr(C)] pub struct Zst; // <- unreachable type
+    }
+
+    #[repr(C)] pub(in super) struct Dst {
+        pub(in super) field: private::Zst,
+    }
+}
+
+fn test() {
+    struct Context;
+    assert::is_transmutable::<src::Src, dst::Dst, Context>();
+}
diff --git a/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_field.rs b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_field.rs
new file mode 100644 (file)
index 0000000..80b454f
--- /dev/null
@@ -0,0 +1,39 @@
+//! If visibility is assumed, a transmutation should be accepted even if the
+//! destination type contains an unreachable field (e.g., a public field with a
+//! private type). (This rule is distinct from type privacy, which still may
+//! forbid naming such types.)
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+        // visibility IS assumed -------------------------------------^^^^
+    {}
+}
+
+mod src {
+    #[repr(C)] pub(self) struct Zst;
+
+    #[repr(C)] pub(in super) struct Src {
+        pub(self) field: Zst,
+    }
+}
+
+mod dst {
+    #[repr(C)] pub(self) struct Zst; // <- unreachable type
+
+    #[repr(C)] pub(in super) struct Dst {
+        pub(in super) field: Zst, //~ ERROR private type
+    }
+}
+
+fn test() {
+    struct Context;
+    assert::is_transmutable::<src::Src, dst::Dst, Context>();
+}
diff --git a/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_field.stderr b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_field.stderr
new file mode 100644 (file)
index 0000000..be83b7c
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0446]: private type `dst::Zst` in public interface
+  --> $DIR/should_accept_if_dst_has_unreachable_field.rs:32:9
+   |
+LL |     #[repr(C)] pub(self) struct Zst; // <- unreachable type
+   |                -------------------- `dst::Zst` declared as private
+...
+LL |         pub(in super) field: Zst,
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0446`.
diff --git a/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_ty.rs b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_ty.rs
new file mode 100644 (file)
index 0000000..7c53c91
--- /dev/null
@@ -0,0 +1,40 @@
+//! If visibility is assumed, a transmutation should be accepted even if the
+//! destination type contains an unreachable field (e.g., a public field with a
+//! private type). (This rule is distinct from type privacy, which still may
+//! forbid naming such types.)
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+        // visibility IS assumed -------------------------------------^^^^
+    {}
+}
+
+mod src {
+    #[repr(C)] pub(self) struct Zst;
+
+    #[repr(C)] pub(in super) struct Src {
+        pub(self) field: Zst,
+    }
+}
+
+mod dst {
+    #[repr(C)] pub(in super) struct Zst;
+
+    // unreachable type
+    #[repr(C)] pub(self) struct Dst {
+        pub(in super) field: Zst,
+    }
+}
+
+fn test() {
+    struct Context;
+    assert::is_transmutable::<src::Src, dst::Dst, Context>(); //~ ERROR `Dst` is private
+}
diff --git a/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_ty.stderr b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_ty.stderr
new file mode 100644 (file)
index 0000000..827df05
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0603]: struct `Dst` is private
+  --> $DIR/should_accept_if_dst_has_unreachable_ty.rs:39:46
+   |
+LL |     assert::is_transmutable::<src::Src, dst::Dst, Context>();
+   |                                              ^^^ private struct
+   |
+note: the struct `Dst` is defined here
+  --> $DIR/should_accept_if_dst_has_unreachable_ty.rs:32:16
+   |
+LL |     #[repr(C)] pub(self) struct Dst {
+   |                ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0603`.
diff --git a/src/test/ui/transmutability/visibility/should_accept_if_src_has_private_field.rs b/src/test/ui/transmutability/visibility/should_accept_if_src_has_private_field.rs
new file mode 100644 (file)
index 0000000..c3f298f
--- /dev/null
@@ -0,0 +1,38 @@
+// check-pass
+//! The presence of a private field in the source type does not affect
+//! transmutability.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+        // visibility is NOT assumed ---------------------------------^^^^^
+    {}
+}
+
+mod src {
+    #[repr(C)] pub(in super) struct Zst;
+
+    #[repr(C)] pub(in super) struct Src {
+        pub(self) field: Zst, // <- private field
+    }
+}
+
+mod dst {
+    #[repr(C)] pub(in super) struct Zst;
+
+    #[repr(C)] pub(in super) struct Dst {
+        pub(in super) field: Zst,
+    }
+}
+
+fn test() {
+    struct Context;
+    assert::is_transmutable::<src::Src, dst::Dst, Context>();
+}
diff --git a/src/test/ui/transmutability/visibility/should_accept_if_src_has_private_variant.rs b/src/test/ui/transmutability/visibility/should_accept_if_src_has_private_variant.rs
new file mode 100644 (file)
index 0000000..73f6aec
--- /dev/null
@@ -0,0 +1,39 @@
+// check-pass
+//! The presence of a private variant in the source type does not affect
+//! transmutability.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+        // visibility is NOT assumed ---------------------------------^^^^^
+    {}
+}
+
+mod src {
+    #[derive(Copy, Clone)]
+    #[repr(C)] pub(in super) struct Zst;
+
+    #[repr(C)] pub(in super) union Src {
+        pub(self) field: Zst, // <- private variant
+    }
+}
+
+mod dst {
+    #[repr(C)] pub(in super) struct Zst;
+
+    #[repr(C)] pub(in super) struct Dst {
+        pub(in super) field: Zst,
+    }
+}
+
+fn test() {
+    struct Context;
+    assert::is_transmutable::<src::Src, dst::Dst, Context>();
+}
diff --git a/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_field.rs b/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_field.rs
new file mode 100644 (file)
index 0000000..6d60260
--- /dev/null
@@ -0,0 +1,38 @@
+//! The presence of an unreachable field in the source type (e.g., a public
+//! field with a private type does not affect transmutability. (This rule is
+//! distinct from type privacy, which still may forbid naming such types.)
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+        // visibility is NOT assumed ---------------------------------^^^^^
+    {}
+}
+
+mod src {
+    #[repr(C)] pub(self) struct Zst; // <- unreachable type
+
+    #[repr(C)] pub(in super) struct Src {
+        pub(in super) field: Zst, //~ ERROR private type
+    }
+}
+
+mod dst {
+    #[repr(C)] pub(in super) struct Zst;
+
+    #[repr(C)] pub(in super) struct Dst {
+        pub(in super) field: Zst,
+    }
+}
+
+fn test() {
+    struct Context;
+    assert::is_transmutable::<src::Src, dst::Dst, Context>();
+}
diff --git a/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_field.stderr b/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_field.stderr
new file mode 100644 (file)
index 0000000..3f7d08d
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0446]: private type `src::Zst` in public interface
+  --> $DIR/should_accept_if_src_has_unreachable_field.rs:23:9
+   |
+LL |     #[repr(C)] pub(self) struct Zst; // <- unreachable type
+   |                -------------------- `src::Zst` declared as private
+...
+LL |         pub(in super) field: Zst,
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0446`.
diff --git a/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_ty.rs b/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_ty.rs
new file mode 100644 (file)
index 0000000..1943fb8
--- /dev/null
@@ -0,0 +1,39 @@
+//! The presence of an unreachable source type (i.e., the source type is
+//! private) does not affect transmutability. (This rule is distinct from type
+//! privacy, which still may forbid naming such types.)
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+        // visibility is NOT assumed ---------------------------------^^^^^
+    {}
+}
+
+mod src {
+    #[repr(C)] pub(in super) struct Zst;
+
+    // unreachable type
+    #[repr(C)] pub(self) struct Src {
+        pub(in super) field: Zst,
+    }
+}
+
+mod dst {
+    #[repr(C)] pub(in super) struct Zst;
+
+    #[repr(C)] pub(in super) struct Dst {
+        pub(in super) field: Zst,
+    }
+}
+
+fn test() {
+    struct Context;
+    assert::is_transmutable::<src::Src, dst::Dst, Context>(); //~ ERROR `Src` is private
+}
diff --git a/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_ty.stderr b/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_ty.stderr
new file mode 100644 (file)
index 0000000..e961984
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0603]: struct `Src` is private
+  --> $DIR/should_accept_if_src_has_unreachable_ty.rs:38:36
+   |
+LL |     assert::is_transmutable::<src::Src, dst::Dst, Context>();
+   |                                    ^^^ private struct
+   |
+note: the struct `Src` is defined here
+  --> $DIR/should_accept_if_src_has_unreachable_ty.rs:23:16
+   |
+LL |     #[repr(C)] pub(self) struct Src {
+   |                ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0603`.
diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.rs b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.rs
new file mode 100644 (file)
index 0000000..fcf3f3a
--- /dev/null
@@ -0,0 +1,37 @@
+//! Unless visibility is assumed, a transmutation should be rejected if the
+//! destination type contains a private field.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+        // visibility is NOT assumed ---------------------------------^^^^^
+    {}
+}
+
+mod src {
+    #[repr(C)] pub(in super) struct Zst;
+
+    #[repr(C)] pub(in super) struct Src {
+        pub(in super) field: Zst,
+    }
+}
+
+mod dst {
+    #[repr(C)] pub(in super) struct Zst;
+
+    #[repr(C)] pub(in super) struct Dst {
+        pub(self) field: Zst, // <- private field
+    }
+}
+
+fn test() {
+    struct Context;
+    assert::is_transmutable::<src::Src, dst::Dst, Context>(); //~ ERROR cannot be safely transmuted
+}
diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.stderr b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.stderr
new file mode 100644 (file)
index 0000000..8512401
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`.
+  --> $DIR/should_reject_if_dst_has_private_field.rs:36:41
+   |
+LL |     assert::is_transmutable::<src::Src, dst::Dst, Context>();
+   |                                         ^^^^^^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<Src, test::Context, false, false, false, false>` is not implemented for `Dst`
+note: required by a bound in `is_transmutable`
+  --> $DIR/should_reject_if_dst_has_private_field.rs:13:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.rs b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.rs
new file mode 100644 (file)
index 0000000..566b564
--- /dev/null
@@ -0,0 +1,38 @@
+//! Unless visibility is assumed, a transmutation should be rejected if the
+//! destination type contains a private variant.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+        // visibility is NOT assumed ---------------------------------^^^^^
+    {}
+}
+
+mod src {
+    #[repr(C)] pub(in super) struct Zst;
+
+    #[repr(C)] pub(in super) struct Src {
+        pub(in super) field: Zst,
+    }
+}
+
+mod dst {
+    #[derive(Copy, Clone)]
+    #[repr(C)] pub(in super) struct Zst;
+
+    #[repr(C)] pub(in super) union Dst {
+        pub(self) field: Zst, // <- private variant
+    }
+}
+
+fn test() {
+    struct Context;
+    assert::is_transmutable::<src::Src, dst::Dst, Context>(); //~ ERROR cannot be safely transmuted
+}
diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.stderr b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.stderr
new file mode 100644 (file)
index 0000000..0be564d
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`.
+  --> $DIR/should_reject_if_dst_has_private_variant.rs:37:41
+   |
+LL |     assert::is_transmutable::<src::Src, dst::Dst, Context>();
+   |                                         ^^^^^^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<Src, test::Context, false, false, false, false>` is not implemented for `Dst`
+note: required by a bound in `is_transmutable`
+  --> $DIR/should_reject_if_dst_has_private_variant.rs:13:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_tricky_unreachable_field.rs b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_tricky_unreachable_field.rs
new file mode 100644 (file)
index 0000000..35fff59
--- /dev/null
@@ -0,0 +1,52 @@
+// check-pass
+//! NOTE: This test documents a known-bug in the implementation of the
+//! transmutability trait. Once fixed, the above "check-pass" header should be
+//! removed, and an "ERROR cannot be safely transmuted" annotation should be added at the end
+//! of the line starting with `assert::is_transmutable`.
+//!
+//! Unless visibility is assumed, a transmutation should be rejected if the
+//! destination type contains an unreachable field (e.g., a public field with a
+//! private type). (This rule is distinct from type privacy, which still may
+//! forbid naming such types.)
+//!
+//! This test exercises a tricky-to-implement instance of this principle: the
+//! "pub-in-priv trick". In the below example, the type `dst::private::Zst` is
+//! unreachable from `Context`. Consequently, the transmute from `Src` to `Dst`
+//! SHOULD be rejected.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+        // visibility is NOT assumed ---------------------------------^^^^^
+    {}
+}
+
+mod src {
+    #[repr(C)] pub(in super) struct Zst;
+
+    #[repr(C)] pub(in super) struct Src {
+        pub(in super) field: Zst,
+    }
+}
+
+mod dst {
+    mod private {
+        #[repr(C)] pub struct Zst; // <- unreachable type
+    }
+
+    #[repr(C)] pub(in super) struct Dst {
+        pub(in super) field: private::Zst,
+    }
+}
+
+fn test() {
+    struct Context;
+    assert::is_transmutable::<src::Src, dst::Dst, Context>();
+}
diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.rs b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.rs
new file mode 100644 (file)
index 0000000..42799d8
--- /dev/null
@@ -0,0 +1,39 @@
+//! Unless visibility is assumed, a transmutation should be rejected if the
+//! destination type contains an unreachable field (e.g., a public field with a
+//! private type). (This rule is distinct from type privacy, which still may
+//! forbid naming such types.)
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+        // visibility is NOT assumed ---------------------------------^^^^^
+    {}
+}
+
+mod src {
+    #[repr(C)] pub(in super) struct Zst;
+
+    #[repr(C)] pub(in super) struct Src {
+        pub(in super) field: Zst,
+    }
+}
+
+mod dst {
+    #[repr(C)] pub(self) struct Zst; // <- unreachable type
+
+    #[repr(C)] pub(in super) struct Dst {
+        pub(in super) field: Zst,
+    }
+}
+
+fn test() {
+    struct Context;
+    assert::is_transmutable::<src::Src, dst::Dst, Context>(); //~ ERROR cannot be safely transmuted
+}
diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.stderr b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.stderr
new file mode 100644 (file)
index 0000000..95c68d4
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`.
+  --> $DIR/should_reject_if_dst_has_unreachable_field.rs:38:41
+   |
+LL |     assert::is_transmutable::<src::Src, dst::Dst, Context>();
+   |                                         ^^^^^^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<Src, test::Context, false, false, false, false>` is not implemented for `Dst`
+note: required by a bound in `is_transmutable`
+  --> $DIR/should_reject_if_dst_has_unreachable_field.rs:15:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.rs b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.rs
new file mode 100644 (file)
index 0000000..e13b32b
--- /dev/null
@@ -0,0 +1,42 @@
+//! Unless visibility is assumed, a transmutation should be rejected if the
+//! destination type contains an unreachable field (e.g., a public field with a
+//! private type). (This rule is distinct from type privacy, which still may
+//! forbid naming such types.)
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+        // visibility is NOT assumed ---------------------------------^^^^^
+    {}
+}
+
+mod src {
+    #[repr(C)] pub(in super) struct Zst;
+
+    #[repr(C)] pub(in super) struct Src {
+        pub(in super) field: Zst,
+    }
+}
+
+mod dst {
+    #[repr(C)] pub(in super) struct Zst;
+
+    // unreachable type
+    #[repr(C)] pub(self) struct Dst {
+        pub(in super) field: Zst,
+    }
+}
+
+fn test() {
+    struct Context;
+    assert::is_transmutable::<src::Src, dst::Dst, Context>();
+    //~^ ERROR `Dst` is private
+    //~| ERROR cannot be safely transmuted
+}
diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.stderr b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.stderr
new file mode 100644 (file)
index 0000000..3391839
--- /dev/null
@@ -0,0 +1,32 @@
+error[E0603]: struct `Dst` is private
+  --> $DIR/should_reject_if_dst_has_unreachable_ty.rs:39:46
+   |
+LL |     assert::is_transmutable::<src::Src, dst::Dst, Context>();
+   |                                              ^^^ private struct
+   |
+note: the struct `Dst` is defined here
+  --> $DIR/should_reject_if_dst_has_unreachable_ty.rs:32:16
+   |
+LL |     #[repr(C)] pub(self) struct Dst {
+   |                ^^^^^^^^^^^^^^^^^^^^
+
+error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`.
+  --> $DIR/should_reject_if_dst_has_unreachable_ty.rs:39:41
+   |
+LL |     assert::is_transmutable::<src::Src, dst::Dst, Context>();
+   |                                         ^^^^^^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<Src, test::Context, false, false, false, false>` is not implemented for `Dst`
+note: required by a bound in `is_transmutable`
+  --> $DIR/should_reject_if_dst_has_unreachable_ty.rs:15:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0277, E0603.
+For more information about an error, try `rustc --explain E0277`.
index 19fcc78721ab13afd10d486b0c4a748002b25930..0aa644db052f0f1a3a159c14d64364e33e41f979 100644 (file)
@@ -9,7 +9,7 @@
 
 #![allow(irrefutable_let_patterns)]
 
-enum Enum<T> { TSVariant(T), SVariant { _v: T }, UVariant }
+enum Enum<T> { TSVariant(#[allow(unused_tuple_struct_fields)] T), SVariant { _v: T }, UVariant }
 type Alias<T> = Enum<T>;
 type AliasFixed = Enum<()>;
 
index 277f4e8424030faed7f91b027c028605270973ea..4775e68820b523daac491f4ae3c7a4fdb9693f91 100644 (file)
@@ -2,18 +2,18 @@ error[E0391]: cycle detected when simplifying constant for the type system `Alph
   --> $DIR/self-in-enum-definition.rs:5:10
    |
 LL |     V3 = Self::V1 {} as u8 + 2,
-   |          ^^^^^^^^
+   |          ^^^^^^^^^^^^^^^^^^^^^
    |
 note: ...which requires simplifying constant for the type system `Alpha::V3::{constant#0}`...
   --> $DIR/self-in-enum-definition.rs:5:10
    |
 LL |     V3 = Self::V1 {} as u8 + 2,
-   |          ^^^^^^^^
+   |          ^^^^^^^^^^^^^^^^^^^^^
 note: ...which requires const-evaluating + checking `Alpha::V3::{constant#0}`...
   --> $DIR/self-in-enum-definition.rs:5:10
    |
 LL |     V3 = Self::V1 {} as u8 + 2,
-   |          ^^^^^^^^
+   |          ^^^^^^^^^^^^^^^^^^^^^
    = note: ...which requires computing layout of `Alpha`...
    = note: ...which again requires simplifying constant for the type system `Alpha::V3::{constant#0}`, completing the cycle
 note: cycle used when collecting item types in top-level module
index 472886c9caa23f0ff11101c545c83b6a4b591406..24b3a045856a6accd5656b25a2531e4afae89465 100644 (file)
@@ -8,7 +8,7 @@ trait Foo {
 
 impl Foo for () {
     type Bar = std::vec::IntoIter<u32>;
-    //~^ ERROR type mismatch resolving `<std::vec::IntoIter<u32> as Iterator>::Item == X
+    //~^ ERROR expected `std::vec::IntoIter<u32>` to be an iterator that yields `X`, but it yields `u32`
 }
 
 fn incoherent() {
index ed4caf6ce68d6e6cf3e778c88512deda0c0a2037..fb40895c49f15d13e28a81527f3ef4ac2e159014 100644 (file)
@@ -1,4 +1,4 @@
-error[E0271]: type mismatch resolving `<std::vec::IntoIter<u32> as Iterator>::Item == X`
+error[E0271]: expected `std::vec::IntoIter<u32>` to be an iterator that yields `X`, but it yields `u32`
   --> $DIR/issue-57961.rs:10:16
    |
 LL | type X = impl Sized;
index 5ed29e0ac94ff77825ba3380e31cc2674183603c..66886db6eb9465762b89014697cee1bafcd6cc95 100644 (file)
@@ -2,7 +2,7 @@ error[E0308]: mismatched types
   --> $DIR/issue-74280.rs:9:5
    |
 LL | fn test() -> Test {
-   |              ---- expected `_` because of return type
+   |              ---- expected `()` because of return type
 LL |     let y = || -> Test { () };
 LL |     7
    |     ^ expected `()`, found integer
index a4fd8a82a04fd2771c51d4597be5117f1eefd2f4..32c2f9ed51edf3476df927c63f6465635a7946a0 100644 (file)
@@ -1,13 +1,11 @@
 // edition:2018
 
-type AsyncFnPtr = Box<
-    dyn Fn() -> std::pin::Pin<Box<dyn std::future::Future<Output = ()>>>,
->;
+type AsyncFnPtr = Box<dyn Fn() -> std::pin::Pin<Box<dyn std::future::Future<Output = ()>>>>;
 
 async fn test() {}
 
 #[allow(unused_must_use)]
 fn main() {
     Box::new(test) as AsyncFnPtr;
-    //~^ ERROR type mismatch
+    //~^ ERROR expected `fn() -> impl Future<Output = ()> {test}` to be a fn item that returns `Pin<Box<(dyn Future<Output = ()> + 'static)>>`, but it returns `impl Future<Output = ()>`
 }
index f04d1b4d7877e974e67a9efe5696c955df36bcef..92d01eb0d3d5ea0a1128208af5075fff0435b3e2 100644 (file)
@@ -1,11 +1,11 @@
-error[E0271]: type mismatch resolving `<fn() -> impl Future<Output = ()> {test} as FnOnce<()>>::Output == Pin<Box<(dyn Future<Output = ()> + 'static)>>`
-  --> $DIR/issue-98604.rs:11:5
+error[E0271]: expected `fn() -> impl Future<Output = ()> {test}` to be a fn item that returns `Pin<Box<(dyn Future<Output = ()> + 'static)>>`, but it returns `impl Future<Output = ()>`
+  --> $DIR/issue-98604.rs:9:5
    |
 LL |     Box::new(test) as AsyncFnPtr;
    |     ^^^^^^^^^^^^^^ expected struct `Pin`, found opaque type
    |
 note: while checking the return type of the `async fn`
-  --> $DIR/issue-98604.rs:7:17
+  --> $DIR/issue-98604.rs:5:17
    |
 LL | async fn test() {}
    |                 ^ checked the `Output` of this `async fn`, found opaque type
index d75762a8b62f094933539dfa770d7d5df7856745..1f89af0457653b066d09f2c0455f9cdf915329ff 100644 (file)
@@ -1,8 +1,10 @@
-fn hi() -> impl Sized { std::ptr::null::<u8>() }
+fn hi() -> impl Sized {
+    std::ptr::null::<u8>()
+}
 
 fn main() {
     let b: Box<dyn Fn() -> Box<u8>> = Box::new(hi);
-    //~^ ERROR type mismatch resolving `<fn() -> impl Sized {hi} as FnOnce<()>>::Output == Box<u8>`
+    //~^ ERROR expected `fn() -> impl Sized {hi}` to be a fn item that returns `Box<u8>`, but it returns `impl Sized`
     let boxed = b();
     let null = *boxed;
     println!("{null:?}");
index 8f3ec7d9d16160ed0fee5b1b6372f8345820dcdb..916a58451baa2f8b5c7d0f1a3414e98ae51faa02 100644 (file)
@@ -1,7 +1,7 @@
-error[E0271]: type mismatch resolving `<fn() -> impl Sized {hi} as FnOnce<()>>::Output == Box<u8>`
-  --> $DIR/issue-98608.rs:4:39
+error[E0271]: expected `fn() -> impl Sized {hi}` to be a fn item that returns `Box<u8>`, but it returns `impl Sized`
+  --> $DIR/issue-98608.rs:6:39
    |
-LL | fn hi() -> impl Sized { std::ptr::null::<u8>() }
+LL | fn hi() -> impl Sized {
    |            ---------- the found opaque type
 ...
 LL |     let b: Box<dyn Fn() -> Box<u8>> = Box::new(hi);
diff --git a/src/test/ui/type/missing-let-in-binding.fixed b/src/test/ui/type/missing-let-in-binding.fixed
new file mode 100644 (file)
index 0000000..d178768
--- /dev/null
@@ -0,0 +1,5 @@
+// run-rustfix
+fn main() {
+    let mut _foo: i32 = 1;
+    let _foo: i32 = 4; //~ ERROR type ascription is experimental
+}
diff --git a/src/test/ui/type/missing-let-in-binding.rs b/src/test/ui/type/missing-let-in-binding.rs
new file mode 100644 (file)
index 0000000..ca42f2e
--- /dev/null
@@ -0,0 +1,5 @@
+// run-rustfix
+fn main() {
+    let mut _foo: i32 = 1;
+    _foo: i32 = 4; //~ ERROR type ascription is experimental
+}
diff --git a/src/test/ui/type/missing-let-in-binding.stderr b/src/test/ui/type/missing-let-in-binding.stderr
new file mode 100644 (file)
index 0000000..12759c5
--- /dev/null
@@ -0,0 +1,16 @@
+error[E0658]: type ascription is experimental
+  --> $DIR/missing-let-in-binding.rs:4:5
+   |
+LL |     _foo: i32 = 4;
+   |     ^^^^^^^^^
+   |
+   = note: see issue #23416 <https://github.com/rust-lang/rust/issues/23416> for more information
+   = help: add `#![feature(type_ascription)]` to the crate attributes to enable
+help: you might have meant to introduce a new binding
+   |
+LL |     let _foo: i32 = 4;
+   |     +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/typeck/issue-100164.fixed b/src/test/ui/typeck/issue-100164.fixed
new file mode 100644 (file)
index 0000000..a5f68be
--- /dev/null
@@ -0,0 +1,9 @@
+// run-rustfix
+
+const _A: i32 = 123;
+//~^ ERROR: missing type for `const` item
+
+fn main() {
+    const _B: i32 = 123;
+    //~^ ERROR: missing type for `const` item
+}
diff --git a/src/test/ui/typeck/issue-100164.rs b/src/test/ui/typeck/issue-100164.rs
new file mode 100644 (file)
index 0000000..7efb9ac
--- /dev/null
@@ -0,0 +1,9 @@
+// run-rustfix
+
+const _A: = 123;
+//~^ ERROR: missing type for `const` item
+
+fn main() {
+    const _B: = 123;
+    //~^ ERROR: missing type for `const` item
+}
diff --git a/src/test/ui/typeck/issue-100164.stderr b/src/test/ui/typeck/issue-100164.stderr
new file mode 100644 (file)
index 0000000..06a132d
--- /dev/null
@@ -0,0 +1,14 @@
+error: missing type for `const` item
+  --> $DIR/issue-100164.rs:3:10
+   |
+LL | const _A: = 123;
+   |          ^ help: provide a type for the constant: `i32`
+
+error: missing type for `const` item
+  --> $DIR/issue-100164.rs:7:14
+   |
+LL |     const _B: = 123;
+   |              ^ help: provide a type for the constant: `i32`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/typeck/issue-100246.rs b/src/test/ui/typeck/issue-100246.rs
new file mode 100644 (file)
index 0000000..8f0b34b
--- /dev/null
@@ -0,0 +1,30 @@
+#![recursion_limit = "5"] // To reduce noise
+
+//expect incompatible type error when ambiguous traits are in scope
+//and not an overflow error on the span in the main function.
+
+struct Ratio<T>(T);
+
+pub trait Pow {
+    fn pow(self) -> Self;
+}
+
+impl<'a, T> Pow for &'a Ratio<T>
+where
+    &'a T: Pow,
+{
+    fn pow(self) -> Self {
+        self
+    }
+}
+
+fn downcast<'a, W: ?Sized>() -> std::io::Result<&'a W> {
+    todo!()
+}
+
+struct Other;
+
+fn main() -> std::io::Result<()> {
+    let other: Other = downcast()?;//~ERROR 28:24: 28:35: `?` operator has incompatible types
+    Ok(())
+}
diff --git a/src/test/ui/typeck/issue-100246.stderr b/src/test/ui/typeck/issue-100246.stderr
new file mode 100644 (file)
index 0000000..8b77de9
--- /dev/null
@@ -0,0 +1,13 @@
+error[E0308]: `?` operator has incompatible types
+  --> $DIR/issue-100246.rs:28:24
+   |
+LL |     let other: Other = downcast()?;
+   |                        ^^^^^^^^^^^ expected struct `Other`, found reference
+   |
+   = note: `?` operator cannot convert from `&_` to `Other`
+   = note: expected struct `Other`
+           found reference `&_`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
index aec2e1ec9e4efe0f0296dc4c0b2c6d4841d9c2ce..c820d1e08c4adbd2abb9f040739eee8415827e26 100644 (file)
@@ -7,10 +7,10 @@ LL |     const FOO = "hello" + 1;
    |                 &str
 
 error: missing type for `const` item
-  --> $DIR/issue-79040.rs:2:11
+  --> $DIR/issue-79040.rs:2:14
    |
 LL |     const FOO = "hello" + 1;
-   |           ^^^ help: provide a type for the item: `FOO: <type>`
+   |              ^ help: provide a type for the item: `: <type>`
 
 error: aborting due to 2 previous errors
 
index 503a32373d5707fc32b80c4ebc059da7c31fcb31..7a0cfb2cf51a727bb39f0df6a92a3cf93e5842ed 100644 (file)
@@ -2,9 +2,12 @@ error[E0615]: attempted to take value of method `read` on type `*mut Foo`
   --> $DIR/issue-91210-ptr-method.rs:10:7
    |
 LL |     x.read = 4;
-   |     - ^^^^ method, not a field
-   |     |
-   |     help: to access the field, dereference first: `(*x)`
+   |       ^^^^ method, not a field
+   |
+help: to access the field, dereference first
+   |
+LL |     (*x).read = 4;
+   |     ++ +
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/typeck/issue-98982.rs b/src/test/ui/typeck/issue-98982.rs
new file mode 100644 (file)
index 0000000..2553824
--- /dev/null
@@ -0,0 +1,9 @@
+fn foo() -> i32 {
+    for i in 0..0 {
+    //~^ ERROR: mismatched types [E0308]
+        return i;
+    }
+    //~| help: return a value for the case when the loop has zero elements to iterate on, or consider changing the return type to account for that possibility
+}
+
+fn main() {}
diff --git a/src/test/ui/typeck/issue-98982.stderr b/src/test/ui/typeck/issue-98982.stderr
new file mode 100644 (file)
index 0000000..3c9806a
--- /dev/null
@@ -0,0 +1,24 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-98982.rs:2:5
+   |
+LL |   fn foo() -> i32 {
+   |               --- expected `i32` because of return type
+LL | /     for i in 0..0 {
+LL | |
+LL | |         return i;
+LL | |     }
+   | |_____^ expected `i32`, found `()`
+   |
+note: the function expects a value to always be returned, but loops might run zero times
+  --> $DIR/issue-98982.rs:2:5
+   |
+LL |     for i in 0..0 {
+   |     ^^^^^^^^^^^^^ this might have zero elements to iterate on
+LL |
+LL |         return i;
+   |         -------- if the loop doesn't execute, this value would never get returned
+   = help: return a value for the case when the loop has zero elements to iterate on, or consider changing the return type to account for that possibility
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
index 3ea317dfb1a5d329a07c14569935f854b1a32861..c57f71b8057a956a93c67ea818679891ee4d9b85 100644 (file)
@@ -189,10 +189,10 @@ LL ~     b: (T, T),
    |
 
 error: missing type for `static` item
-  --> $DIR/typeck_type_placeholder_item.rs:73:12
+  --> $DIR/typeck_type_placeholder_item.rs:73:13
    |
 LL |     static A = 42;
-   |            ^ help: provide a type for the static variable: `A: i32`
+   |             ^ help: provide a type for the static variable: `: i32`
 
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables
   --> $DIR/typeck_type_placeholder_item.rs:75:15
index 355d11099419c41eae12e6a0b63463ff12ad8ec5..1f8aec205fbeb41e405c6bea947871524efc9f76 100644 (file)
@@ -4,7 +4,7 @@
 
 use std::any::{Any, TypeId};
 
-struct Struct<'a>(&'a ());
+struct Struct<'a>(#[allow(unused_tuple_struct_fields)] &'a ());
 trait Trait<'a> {}
 
 fn main() {
index 8fcb6d93d391cd4686e2a613e572c1ae332cebbd..175b02fcb817539f63314d307e42b091abac8547 100644 (file)
@@ -2,7 +2,7 @@
 #![allow(incomplete_features, unused_braces, unused_parens)]
 #![feature(unsized_tuple_coercion, unsized_locals, unsized_fn_params)]
 
-struct A<X: ?Sized>(X);
+struct A<X: ?Sized>(#[allow(unused_tuple_struct_fields)] X);
 
 fn udrop<T: ?Sized>(_x: T) {}
 fn foo() -> Box<[u8]> {
index 93c7af68ac388e145714fe11c473d29eb0b5b16b..6bdc89310ebaeaeb0d281e36b5b7aa20f00b73b8 100644 (file)
@@ -1,8 +1,8 @@
 // run-pass
 // Test that we allow unsizing even if there is an unchanged param in the
 // field getting unsized.
-struct A<T, U: ?Sized + 'static>(T, B<T, U>);
-struct B<T, U: ?Sized>(T, U);
+struct A<T, U: ?Sized + 'static>(#[allow(unused_tuple_struct_fields)] T, B<T, U>);
+struct B<T, U: ?Sized>(#[allow(unused_tuple_struct_fields)] T, U);
 
 fn main() {
     let x: A<[u32; 1], [u32; 1]> = A([0; 1], B([0; 1], [0; 1]));
index 85b500ccad8cd0b63995fd94a03ddd4b83f7905b..efd4ca3dc0b89929dc8c5f5c023d25978d76cb61 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 85b500ccad8cd0b63995fd94a03ddd4b83f7905b
+Subproject commit efd4ca3dc0b89929dc8c5f5c023d25978d76cb61
index 2278a8dc16ba04183535e156d4e4e3d7f4710482..380cd451987bfc982d00448668e1699fb999ffc9 100644 (file)
@@ -965,7 +965,7 @@ Released 2021-09-09
   [#7407](https://github.com/rust-lang/rust-clippy/pull/7407)
 * [`redundant_allocation`]: Now additionally supports the `Arc<>` type
   [#7308](https://github.com/rust-lang/rust-clippy/pull/7308)
-* [`blacklisted_name`]: Now allows blacklisted names in test code
+* [`disallowed_names`]: Now allows disallowed names in test code
   [#7379](https://github.com/rust-lang/rust-clippy/pull/7379)
 * [`redundant_closure`]: Suggests `&mut` for `FnMut`
   [#7437](https://github.com/rust-lang/rust-clippy/pull/7437)
@@ -2066,7 +2066,7 @@ Released 2020-08-27
   [#5692](https://github.com/rust-lang/rust-clippy/pull/5692)
 * [`if_same_then_else`]: Don't assume multiplication is always commutative
   [#5702](https://github.com/rust-lang/rust-clippy/pull/5702)
-* [`blacklisted_name`]: Remove `bar` from the default configuration
+* [`disallowed_names`]: Remove `bar` from the default configuration
   [#5712](https://github.com/rust-lang/rust-clippy/pull/5712)
 * [`redundant_pattern_matching`]: Avoid suggesting non-`const fn` calls in const contexts
   [#5724](https://github.com/rust-lang/rust-clippy/pull/5724)
@@ -3522,6 +3522,7 @@ Released 2018-09-13
 [`derive_partial_eq_without_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_partial_eq_without_eq
 [`disallowed_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_method
 [`disallowed_methods`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_methods
+[`disallowed_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_names
 [`disallowed_script_idents`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_script_idents
 [`disallowed_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_type
 [`disallowed_types`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types
@@ -3685,6 +3686,7 @@ Released 2018-09-13
 [`manual_find`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find
 [`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map
 [`manual_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten
+[`manual_instant_elapsed`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_instant_elapsed
 [`manual_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_map
 [`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy
 [`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive
@@ -3816,11 +3818,13 @@ Released 2018-09-13
 [`or_then_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#or_then_unwrap
 [`out_of_bounds_indexing`]: https://rust-lang.github.io/rust-clippy/master/index.html#out_of_bounds_indexing
 [`overflow_check_conditional`]: https://rust-lang.github.io/rust-clippy/master/index.html#overflow_check_conditional
+[`overly_complex_bool_expr`]: https://rust-lang.github.io/rust-clippy/master/index.html#overly_complex_bool_expr
 [`panic`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic
 [`panic_in_result_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_in_result_fn
 [`panic_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_params
 [`panicking_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_unwrap
 [`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl
+[`partialeq_to_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_to_none
 [`path_buf_push_overwrite`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_buf_push_overwrite
 [`pattern_type_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#pattern_type_mismatch
 [`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma
index 6e15133d267ba04cfa304a2f7f73b909cfa4fee7..28b4cfd5f099520cf023e30fbec1d8953b9b29d9 100644 (file)
@@ -30,10 +30,10 @@ All contributors are expected to follow the [Rust Code of Conduct].
 ## The Clippy book
 
 If you're new to Clippy and don't know where to start the [Clippy book] includes
-a developer guide and is a good place to start your journey.
+a [developer guide] and is a good place to start your journey.
 
-<!-- FIXME: Link to the deployed book, once it is deployed through CI -->
-[Clippy book]: book/src
+[Clippy book]: https://doc.rust-lang.org/nightly/clippy/index.html
+[developer guide]: https://doc.rust-lang.org/nightly/clippy/development/index.html
 
 ## High level approach
 
index 1c875c3adcf55f3acacc07d9f05c28e5618ff5b9..b7e136ce9b29e4bddf01074fab885210325d25ac 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "clippy"
-version = "0.1.64"
+version = "0.1.65"
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
index 2c3defeaa83078d2d124d62fbc1bb3cb6458d600..1193771ff736b2471ca8a224098e80ed24efeff4 100644 (file)
@@ -144,7 +144,7 @@ value` mapping e.g.
 
 ```toml
 avoid-breaking-exported-api = false
-blacklisted-names = ["toto", "tata", "titi"]
+disallowed-names = ["toto", "tata", "titi"]
 cognitive-complexity-threshold = 30
 ```
 
index 6e295ac3181dd99e7c3e40324eafa69069076185..77f1d2e8797a36c2200c5563e0b05085bc3c4b9e 100644 (file)
@@ -7,7 +7,7 @@ basic `variable = value` mapping eg.
 
 ```toml
 avoid-breaking-exported-api = false
-blacklisted-names = ["toto", "tata", "titi"]
+disallowed-names = ["toto", "tata", "titi"]
 cognitive-complexity-threshold = 30
 ```
 
index 03d2ef3d19edd4406c4c0d86eb62ceff71f23d72..10a8f31f4573f790d63a4c786037abff9ce40004 100644 (file)
@@ -438,7 +438,7 @@ fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str>
     let mut lint_context = None;
 
     let mut iter = rustc_lexer::tokenize(&file_contents).map(|t| {
-        let range = offset..offset + t.len;
+        let range = offset..offset + t.len as usize;
         offset = range.end;
 
         LintDeclSearchResult {
index aed38bc2817607266ed65679a74afed63a427069..05e79a241884f43bb9175afd3b01b483e6596959 100644 (file)
@@ -836,7 +836,7 @@ pub(crate) struct LintDeclSearchResult<'a> {
 fn parse_contents(contents: &str, module: &str, lints: &mut Vec<Lint>) {
     let mut offset = 0usize;
     let mut iter = tokenize(contents).map(|t| {
-        let range = offset..offset + t.len;
+        let range = offset..offset + t.len as usize;
         offset = range.end;
 
         LintDeclSearchResult {
@@ -899,7 +899,7 @@ fn parse_contents(contents: &str, module: &str, lints: &mut Vec<Lint>) {
 fn parse_deprecated_contents(contents: &str, lints: &mut Vec<DeprecatedLint>) {
     let mut offset = 0usize;
     let mut iter = tokenize(contents).map(|t| {
-        let range = offset..offset + t.len;
+        let range = offset..offset + t.len as usize;
         offset = range.end;
 
         LintDeclSearchResult {
@@ -946,7 +946,7 @@ fn parse_renamed_contents(contents: &str, lints: &mut Vec<RenamedLint>) {
     for line in contents.lines() {
         let mut offset = 0usize;
         let mut iter = tokenize(line).map(|t| {
-            let range = offset..offset + t.len;
+            let range = offset..offset + t.len as usize;
             offset = range.end;
 
             LintDeclSearchResult {
index 79a56dc405d17a35fb53849002e34c2ae06cd16c..738562ef85597b1edaeabb796c8fb734a947ae87 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "clippy_lints"
-version = "0.1.64"
+version = "0.1.65"
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
index b6affdee5236418d65a4f5a5d45e493ae54ce414..6a6554f968b334e5ca3ce1802ff475440df66090 100644 (file)
@@ -19,6 +19,9 @@
     /// ### Why is this bad?
     /// An assertion failure cannot output an useful message of the error.
     ///
+    /// ### Known problems
+    /// The suggested replacement decreases the readability of code and log output.
+    ///
     /// ### Example
     /// ```rust,ignore
     /// # let r = Ok::<_, ()>(());
@@ -28,7 +31,7 @@
     /// ```
     #[clippy::version = "1.64.0"]
     pub ASSERTIONS_ON_RESULT_STATES,
-    style,
+    restriction,
     "`assert!(r.is_ok())`/`assert!(r.is_err())` gives worse error message than directly calling `r.unwrap()`/`r.unwrap_err()`"
 }
 
@@ -50,13 +53,14 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                 if result_type_with_refs != result_type {
                     return;
                 } else if let Res::Local(binding_id) = path_res(cx, recv)
-                    && local_used_after_expr(cx, binding_id, recv) {
+                    && local_used_after_expr(cx, binding_id, recv)
+                {
                     return;
                 }
             }
             let mut app = Applicability::MachineApplicable;
             match method_segment.ident.as_str() {
-                "is_ok" if has_debug_impl(cx, substs.type_at(1)) => {
+                "is_ok" if type_suitable_to_unwrap(cx, substs.type_at(1)) => {
                     span_lint_and_sugg(
                         cx,
                         ASSERTIONS_ON_RESULT_STATES,
@@ -70,7 +74,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                         app,
                     );
                 }
-                "is_err" if has_debug_impl(cx, substs.type_at(0)) => {
+                "is_err" if type_suitable_to_unwrap(cx, substs.type_at(0)) => {
                     span_lint_and_sugg(
                         cx,
                         ASSERTIONS_ON_RESULT_STATES,
@@ -96,3 +100,7 @@ fn has_debug_impl<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
         .get_diagnostic_item(sym::Debug)
         .map_or(false, |debug| implements_trait(cx, ty, debug, &[]))
 }
+
+fn type_suitable_to_unwrap<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
+    has_debug_impl(cx, ty) && !ty.is_unit() && !ty.is_never()
+}
diff --git a/src/tools/clippy/clippy_lints/src/blacklisted_name.rs b/src/tools/clippy/clippy_lints/src/blacklisted_name.rs
deleted file mode 100644 (file)
index 1600fb2..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-use clippy_utils::{diagnostics::span_lint, is_test_module_or_function};
-use rustc_data_structures::fx::FxHashSet;
-use rustc_hir::{Item, Pat, PatKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for usage of blacklisted names for variables, such
-    /// as `foo`.
-    ///
-    /// ### Why is this bad?
-    /// These names are usually placeholder names and should be
-    /// avoided.
-    ///
-    /// ### Example
-    /// ```rust
-    /// let foo = 3.14;
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub BLACKLISTED_NAME,
-    style,
-    "usage of a blacklisted/placeholder name"
-}
-
-#[derive(Clone, Debug)]
-pub struct BlacklistedName {
-    blacklist: FxHashSet<String>,
-    test_modules_deep: u32,
-}
-
-impl BlacklistedName {
-    pub fn new(blacklist: FxHashSet<String>) -> Self {
-        Self {
-            blacklist,
-            test_modules_deep: 0,
-        }
-    }
-
-    fn in_test_module(&self) -> bool {
-        self.test_modules_deep != 0
-    }
-}
-
-impl_lint_pass!(BlacklistedName => [BLACKLISTED_NAME]);
-
-impl<'tcx> LateLintPass<'tcx> for BlacklistedName {
-    fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
-        if is_test_module_or_function(cx.tcx, item) {
-            self.test_modules_deep = self.test_modules_deep.saturating_add(1);
-        }
-    }
-
-    fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
-        // Check whether we are under the `test` attribute.
-        if self.in_test_module() {
-            return;
-        }
-
-        if let PatKind::Binding(.., ident, _) = pat.kind {
-            if self.blacklist.contains(&ident.name.to_string()) {
-                span_lint(
-                    cx,
-                    BLACKLISTED_NAME,
-                    ident.span,
-                    &format!("use of a blacklisted/placeholder name `{}`", ident.name),
-                );
-            }
-        }
-    }
-
-    fn check_item_post(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
-        if is_test_module_or_function(cx.tcx, item) {
-            self.test_modules_deep = self.test_modules_deep.saturating_sub(1);
-        }
-    }
-}
index 526ee2f891a16c79192d523edeaf0313f0db7133..6eb78d21e826629e7c928153ffe4c007e4c1fc32 100644 (file)
@@ -64,7 +64,7 @@
     /// if a {}
     /// ```
     #[clippy::version = "pre 1.29.0"]
-    pub LOGIC_BUG,
+    pub OVERLY_COMPLEX_BOOL_EXPR,
     correctness,
     "boolean expressions that contain terminals which can be eliminated"
 }
@@ -72,7 +72,7 @@
 // For each pairs, both orders are considered.
 const METHODS_WITH_NEGATION: [(&str, &str); 2] = [("is_some", "is_none"), ("is_err", "is_ok")];
 
-declare_lint_pass!(NonminimalBool => [NONMINIMAL_BOOL, LOGIC_BUG]);
+declare_lint_pass!(NonminimalBool => [NONMINIMAL_BOOL, OVERLY_COMPLEX_BOOL_EXPR]);
 
 impl<'tcx> LateLintPass<'tcx> for NonminimalBool {
     fn check_fn(
@@ -396,7 +396,7 @@ fn bool_expr(&self, e: &'tcx Expr<'_>) {
                     if stats.terminals[i] != 0 && simplified_stats.terminals[i] == 0 {
                         span_lint_hir_and_then(
                             self.cx,
-                            LOGIC_BUG,
+                            OVERLY_COMPLEX_BOOL_EXPR,
                             e.hir_id,
                             e.span,
                             "this boolean expression contains a logic bug",
index 64ea326b75a0d3335f7407a9f3e17e9176457190..6426e8c25ac1c728de493d03ad475bdbc4256651 100644 (file)
@@ -37,7 +37,7 @@ pub(super) fn check(
             span,
             &format!("casting the result of `{cast_from}::abs()` to {cast_to}"),
             "replace with",
-            format!("{}.unsigned_abs()", Sugg::hir(cx, &args[0], "..")),
+            format!("{}.unsigned_abs()", Sugg::hir(cx, &args[0], "..").maybe_par()),
             Applicability::MachineApplicable,
         );
     }
index 17fc81951f95b41e3a4e81b4f8315c23f389143b..37b2fdcff09ff5467a6ace2c657f7fb78c98d13d 100644 (file)
@@ -270,10 +270,7 @@ fn get_types_from_cast<'a>(
     let limit_from: Option<(&Expr<'_>, &str)> = call_from_cast.or_else(|| {
         if_chain! {
             // `from_type::from, to_type::max_value()`
-            if let ExprKind::Call(from_func, args) = &expr.kind;
-            // `to_type::max_value()`
-            if args.len() == 1;
-            if let limit = &args[0];
+            if let ExprKind::Call(from_func, [limit]) = &expr.kind;
             // `from_type::from`
             if let ExprKind::Path(ref path) = &from_func.kind;
             if let Some(from_sym) = get_implementing_type(path, INTS, "from");
index 18d34370a7b87d136a8c2ac0c7545d5d47b7e8d9..878248a6bdc8c899fec7050fd6f4c41b58817063 100644 (file)
@@ -34,7 +34,7 @@
 impl LateLintPass<'_> for CreateDir {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
         if_chain! {
-            if let ExprKind::Call(func, args) = expr.kind;
+            if let ExprKind::Call(func, [arg, ..]) = expr.kind;
             if let ExprKind::Path(ref path) = func.kind;
             if let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id();
             if match_def_path(cx, def_id, &paths::STD_FS_CREATE_DIR);
@@ -45,7 +45,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
                     expr.span,
                     "calling `std::fs::create_dir` where there may be a better way",
                     "consider calling `std::fs::create_dir_all` instead",
-                    format!("create_dir_all({})", snippet(cx, args[0].span, "..")),
+                    format!("create_dir_all({})", snippet(cx, arg.span, "..")),
                     Applicability::MaybeIncorrect,
                 )
             }
index d99a1aa2969461a40153b91b10933b57b264e794..74f7df611778ec32d61d9a056f23dccd727756ec 100644 (file)
@@ -1,7 +1,9 @@
 use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg};
 use clippy_utils::source::snippet_with_macro_callsite;
 use clippy_utils::ty::{has_drop, is_copy};
-use clippy_utils::{any_parent_is_automatically_derived, contains_name, get_parent_expr, match_def_path, paths};
+use clippy_utils::{
+    any_parent_is_automatically_derived, contains_name, get_parent_expr, is_from_proc_macro, match_def_path, paths,
+};
 use if_chain::if_chain;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
@@ -94,6 +96,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             if let QPath::Resolved(None, _path) = qpath;
             let expr_ty = cx.typeck_results().expr_ty(expr);
             if let ty::Adt(def, ..) = expr_ty.kind();
+            if !is_from_proc_macro(cx, expr);
             then {
                 // TODO: Work out a way to put "whatever the imported way of referencing
                 // this type in this file" rather than a fully-qualified type.
index a90f894a7b19cdbcdc422fbe2c1bca66a9cb70a6..5d41c63928dfb0daeb6cb3a2bb2eed9bd9e80af9 100644 (file)
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
 use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
 use clippy_utils::sugg::has_enclosing_paren;
-use clippy_utils::ty::{expr_sig, peel_mid_ty_refs, variant_of_res};
+use clippy_utils::ty::{expr_sig, peel_mid_ty_refs, ty_sig, variant_of_res};
 use clippy_utils::{get_parent_expr, is_lint_allowed, path_to_local, walk_to_expr_usage};
 use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX};
 use rustc_data_structures::fx::FxIndexMap;
@@ -15,9 +15,9 @@
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable, TypeckResults};
+use rustc_middle::ty::{self, Binder, BoundVariableKind, List, Ty, TyCtxt, TypeVisitable, TypeckResults};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::{symbol::sym, Span, Symbol};
+use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP};
 use rustc_trait_selection::infer::InferCtxtExt;
 
 declare_clippy_lint! {
@@ -183,24 +183,24 @@ enum State {
     },
     DerefedBorrow(DerefedBorrow),
     ExplicitDeref {
-        // Span and id of the top-level deref expression if the parent expression is a borrow.
-        deref_span_id: Option<(Span, HirId)>,
+        mutability: Option<Mutability>,
     },
     ExplicitDerefField {
         name: Symbol,
     },
     Reborrow {
-        deref_span: Span,
-        deref_hir_id: HirId,
+        mutability: Mutability,
+    },
+    Borrow {
+        mutability: Mutability,
     },
-    Borrow,
 }
 
 // A reference operation considered by this lint pass
 enum RefOp {
     Method(Mutability),
     Deref,
-    AddrOf,
+    AddrOf(Mutability),
 }
 
 struct RefPat {
@@ -263,7 +263,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                             ));
                         } else if position.is_deref_stable() {
                             self.state = Some((
-                                State::ExplicitDeref { deref_span_id: None },
+                                State::ExplicitDeref { mutability: None },
                                 StateData { span: expr.span, hir_id: expr.hir_id, position },
                             ));
                         }
@@ -289,7 +289,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                             },
                         ));
                     },
-                    RefOp::AddrOf => {
+                    RefOp::AddrOf(mutability) => {
                         // Find the number of times the borrow is auto-derefed.
                         let mut iter = adjustments.iter();
                         let mut deref_count = 0usize;
@@ -357,9 +357,13 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                                 }),
                                 StateData { span: expr.span, hir_id: expr.hir_id, position },
                             ));
-                        } else if position.is_deref_stable() {
+                        } else if position.is_deref_stable()
+                            // Auto-deref doesn't combine with other adjustments
+                            && next_adjust.map_or(true, |a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_)))
+                            && iter.all(|a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_)))
+                        {
                             self.state = Some((
-                                State::Borrow,
+                                State::Borrow { mutability },
                                 StateData {
                                     span: expr.span,
                                     hir_id: expr.hir_id,
@@ -395,7 +399,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                     data,
                 ));
             },
-            (Some((State::DerefedBorrow(state), data)), RefOp::AddrOf) if state.count != 0 => {
+            (Some((State::DerefedBorrow(state), data)), RefOp::AddrOf(_)) if state.count != 0 => {
                 self.state = Some((
                     State::DerefedBorrow(DerefedBorrow {
                         count: state.count - 1,
@@ -404,12 +408,12 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                     data,
                 ));
             },
-            (Some((State::DerefedBorrow(state), data)), RefOp::AddrOf) => {
+            (Some((State::DerefedBorrow(state), data)), RefOp::AddrOf(mutability)) => {
                 let position = data.position;
                 report(cx, expr, State::DerefedBorrow(state), data);
                 if position.is_deref_stable() {
                     self.state = Some((
-                        State::Borrow,
+                        State::Borrow { mutability },
                         StateData {
                             span: expr.span,
                             hir_id: expr.hir_id,
@@ -430,43 +434,28 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                     ));
                 } else if position.is_deref_stable() {
                     self.state = Some((
-                        State::ExplicitDeref { deref_span_id: None },
+                        State::ExplicitDeref { mutability: None },
                         StateData { span: expr.span, hir_id: expr.hir_id, position },
                     ));
                 }
             },
 
-            (Some((State::Borrow, data)), RefOp::Deref) => {
+            (Some((State::Borrow { mutability }, data)), RefOp::Deref) => {
                 if typeck.expr_ty(sub_expr).is_ref() {
-                    self.state = Some((
-                        State::Reborrow {
-                            deref_span: expr.span,
-                            deref_hir_id: expr.hir_id,
-                        },
-                        data,
-                    ));
+                    self.state = Some((State::Reborrow { mutability }, data));
                 } else {
                     self.state = Some((
                         State::ExplicitDeref {
-                            deref_span_id: Some((expr.span, expr.hir_id)),
+                            mutability: Some(mutability),
                         },
                         data,
                     ));
                 }
             },
-            (
-                Some((
-                    State::Reborrow {
-                        deref_span,
-                        deref_hir_id,
-                    },
-                    data,
-                )),
-                RefOp::Deref,
-            ) => {
+            (Some((State::Reborrow { mutability }, data)), RefOp::Deref) => {
                 self.state = Some((
                     State::ExplicitDeref {
-                        deref_span_id: Some((deref_span, deref_hir_id)),
+                        mutability: Some(mutability),
                     },
                     data,
                 ));
@@ -573,7 +562,7 @@ fn try_parse_ref_op<'tcx>(
         ExprKind::Unary(UnOp::Deref, sub_expr) if !typeck.expr_ty(sub_expr).is_unsafe_ptr() => {
             return Some((RefOp::Deref, sub_expr));
         },
-        ExprKind::AddrOf(BorrowKind::Ref, _, sub_expr) => return Some((RefOp::AddrOf, sub_expr)),
+        ExprKind::AddrOf(BorrowKind::Ref, mutability, sub_expr) => return Some((RefOp::AddrOf(mutability), sub_expr)),
         _ => return None,
     };
     if tcx.is_diagnostic_item(sym::deref_method, def_id) {
@@ -609,18 +598,21 @@ enum Position {
     Postfix,
     Deref,
     /// Any other location which will trigger auto-deref to a specific time.
-    DerefStable(i8),
+    /// Contains the precedence of the parent expression and whether the target type is sized.
+    DerefStable(i8, bool),
     /// Any other location which will trigger auto-reborrowing.
+    /// Contains the precedence of the parent expression.
     ReborrowStable(i8),
+    /// Contains the precedence of the parent expression.
     Other(i8),
 }
 impl Position {
     fn is_deref_stable(self) -> bool {
-        matches!(self, Self::DerefStable(_))
+        matches!(self, Self::DerefStable(..))
     }
 
     fn is_reborrow_stable(self) -> bool {
-        matches!(self, Self::DerefStable(_) | Self::ReborrowStable(_))
+        matches!(self, Self::DerefStable(..) | Self::ReborrowStable(_))
     }
 
     fn can_auto_borrow(self) -> bool {
@@ -628,7 +620,7 @@ fn can_auto_borrow(self) -> bool {
     }
 
     fn lint_explicit_deref(self) -> bool {
-        matches!(self, Self::Other(_) | Self::DerefStable(_) | Self::ReborrowStable(_))
+        matches!(self, Self::Other(_) | Self::DerefStable(..) | Self::ReborrowStable(_))
     }
 
     fn precedence(self) -> i8 {
@@ -639,7 +631,7 @@ fn precedence(self) -> i8 {
             | Self::FieldAccess(_)
             | Self::Postfix => PREC_POSTFIX,
             Self::Deref => PREC_PREFIX,
-            Self::DerefStable(p) | Self::ReborrowStable(p) | Self::Other(p) => p,
+            Self::DerefStable(p, _) | Self::ReborrowStable(p) | Self::Other(p) => p,
         }
     }
 }
@@ -659,7 +651,7 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
         }
         match parent {
             Node::Local(Local { ty: Some(ty), span, .. }) if span.ctxt() == ctxt => {
-                Some(binding_ty_auto_deref_stability(ty, precedence))
+                Some(binding_ty_auto_deref_stability(cx, ty, precedence, List::empty()))
             },
             Node::Item(&Item {
                 kind: ItemKind::Static(..) | ItemKind::Const(..),
@@ -680,11 +672,7 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
                 ..
             }) if span.ctxt() == ctxt => {
                 let ty = cx.tcx.type_of(def_id);
-                Some(if ty.is_ref() {
-                    Position::DerefStable(precedence)
-                } else {
-                    Position::Other(precedence)
-                })
+                Some(ty_auto_deref_stability(cx, ty, precedence).position_for_result(cx))
             },
 
             Node::Item(&Item {
@@ -705,45 +693,38 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
                 span,
                 ..
             }) if span.ctxt() == ctxt => {
-                let output = cx.tcx.fn_sig(def_id.to_def_id()).skip_binder().output();
-                Some(if !output.is_ref() {
-                    Position::Other(precedence)
-                } else if output.has_placeholders() || output.has_opaque_types() {
-                    Position::ReborrowStable(precedence)
-                } else {
-                    Position::DerefStable(precedence)
-                })
+                let output = cx
+                    .tcx
+                    .erase_late_bound_regions(cx.tcx.fn_sig(def_id.to_def_id()).output());
+                Some(ty_auto_deref_stability(cx, output, precedence).position_for_result(cx))
             },
 
             Node::Expr(parent) if parent.span.ctxt() == ctxt => match parent.kind {
                 ExprKind::Ret(_) => {
                     let owner_id = cx.tcx.hir().body_owner(cx.enclosing_body.unwrap());
                     Some(
-                        if let Node::Expr(Expr {
-                            kind: ExprKind::Closure(&Closure { fn_decl, .. }),
-                            ..
-                        }) = cx.tcx.hir().get(owner_id)
+                        if let Node::Expr(
+                            closure_expr @ Expr {
+                                kind: ExprKind::Closure(closure),
+                                ..
+                            },
+                        ) = cx.tcx.hir().get(owner_id)
                         {
-                            match fn_decl.output {
-                                FnRetTy::Return(ty) => binding_ty_auto_deref_stability(ty, precedence),
-                                FnRetTy::DefaultReturn(_) => Position::Other(precedence),
-                            }
+                            closure_result_position(cx, closure, cx.typeck_results().expr_ty(closure_expr), precedence)
                         } else {
                             let output = cx
                                 .tcx
-                                .fn_sig(cx.tcx.hir().local_def_id(owner_id))
-                                .skip_binder()
-                                .output();
-                            if !output.is_ref() {
-                                Position::Other(precedence)
-                            } else if output.has_placeholders() || output.has_opaque_types() {
-                                Position::ReborrowStable(precedence)
-                            } else {
-                                Position::DerefStable(precedence)
-                            }
+                                .erase_late_bound_regions(cx.tcx.fn_sig(cx.tcx.hir().local_def_id(owner_id)).output());
+                            ty_auto_deref_stability(cx, output, precedence).position_for_result(cx)
                         },
                     )
                 },
+                ExprKind::Closure(closure) => Some(closure_result_position(
+                    cx,
+                    closure,
+                    cx.typeck_results().expr_ty(parent),
+                    precedence,
+                )),
                 ExprKind::Call(func, _) if func.hir_id == child_id => {
                     (child_id == e.hir_id).then_some(Position::Callee)
                 },
@@ -755,8 +736,9 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
                     .map(|(hir_ty, ty)| match hir_ty {
                         // Type inference for closures can depend on how they're called. Only go by the explicit
                         // types here.
-                        Some(ty) => binding_ty_auto_deref_stability(ty, precedence),
-                        None => param_auto_deref_stability(ty.skip_binder(), precedence),
+                        Some(hir_ty) => binding_ty_auto_deref_stability(cx, hir_ty, precedence, ty.bound_vars()),
+                        None => ty_auto_deref_stability(cx, cx.tcx.erase_late_bound_regions(ty), precedence)
+                            .position_for_arg(),
                     }),
                 ExprKind::MethodCall(_, args, _) => {
                     let id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap();
@@ -797,7 +779,12 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
                                 Position::MethodReceiver
                             }
                         } else {
-                            param_auto_deref_stability(cx.tcx.fn_sig(id).skip_binder().inputs()[i], precedence)
+                            ty_auto_deref_stability(
+                                cx,
+                                cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i)),
+                                precedence,
+                            )
+                            .position_for_arg()
                         }
                     })
                 },
@@ -808,7 +795,9 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
                         .find(|f| f.expr.hir_id == child_id)
                         .zip(variant)
                         .and_then(|(field, variant)| variant.fields.iter().find(|f| f.name == field.ident.name))
-                        .map(|field| param_auto_deref_stability(cx.tcx.type_of(field.did), precedence))
+                        .map(|field| {
+                            ty_auto_deref_stability(cx, cx.tcx.type_of(field.did), precedence).position_for_arg()
+                        })
                 },
                 ExprKind::Field(child, name) if child.hir_id == e.hir_id => Some(Position::FieldAccess(name.name)),
                 ExprKind::Unary(UnOp::Deref, child) if child.hir_id == e.hir_id => Some(Position::Deref),
@@ -831,6 +820,26 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
     (position, adjustments)
 }
 
+fn closure_result_position<'tcx>(
+    cx: &LateContext<'tcx>,
+    closure: &'tcx Closure<'_>,
+    ty: Ty<'tcx>,
+    precedence: i8,
+) -> Position {
+    match closure.fn_decl.output {
+        FnRetTy::Return(hir_ty) => {
+            if let Some(sig) = ty_sig(cx, ty)
+                && let Some(output) = sig.output()
+            {
+                binding_ty_auto_deref_stability(cx, hir_ty, precedence, output.bound_vars())
+            } else {
+                Position::Other(precedence)
+            }
+        },
+        FnRetTy::DefaultReturn(_) => Position::Other(precedence),
+    }
+}
+
 // Checks the stability of auto-deref when assigned to a binding with the given explicit type.
 //
 // e.g.
@@ -840,7 +849,12 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
 //
 // Here `y1` and `y2` would resolve to different types, so the type `&Box<_>` is not stable when
 // switching to auto-dereferencing.
-fn binding_ty_auto_deref_stability(ty: &hir::Ty<'_>, precedence: i8) -> Position {
+fn binding_ty_auto_deref_stability<'tcx>(
+    cx: &LateContext<'tcx>,
+    ty: &'tcx hir::Ty<'_>,
+    precedence: i8,
+    binder_args: &'tcx List<BoundVariableKind>,
+) -> Position {
     let TyKind::Rptr(_, ty) = &ty.kind else {
         return Position::Other(precedence);
     };
@@ -870,21 +884,33 @@ fn binding_ty_auto_deref_stability(ty: &hir::Ty<'_>, precedence: i8) -> Position
                 {
                     Position::ReborrowStable(precedence)
                 } else {
-                    Position::DerefStable(precedence)
+                    Position::DerefStable(
+                        precedence,
+                        cx.tcx
+                            .erase_late_bound_regions(Binder::bind_with_vars(
+                                cx.typeck_results().node_type(ty.ty.hir_id),
+                                binder_args,
+                            ))
+                            .is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()),
+                    )
                 }
             },
-            TyKind::Slice(_)
-            | TyKind::Array(..)
-            | TyKind::BareFn(_)
-            | TyKind::Never
+            TyKind::Slice(_) => Position::DerefStable(precedence, false),
+            TyKind::Array(..) | TyKind::Ptr(_) | TyKind::BareFn(_) => Position::DerefStable(precedence, true),
+            TyKind::Never
             | TyKind::Tup(_)
-            | TyKind::Ptr(_)
-            | TyKind::TraitObject(..)
-            | TyKind::Path(_) => Position::DerefStable(precedence),
-            TyKind::OpaqueDef(..)
-            | TyKind::Infer
-            | TyKind::Typeof(..)
-            | TyKind::Err => Position::ReborrowStable(precedence),
+            | TyKind::Path(_) => Position::DerefStable(
+                precedence,
+                cx.tcx
+                    .erase_late_bound_regions(Binder::bind_with_vars(
+                        cx.typeck_results().node_type(ty.ty.hir_id),
+                        binder_args,
+                    ))
+                    .is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()),
+            ),
+            TyKind::OpaqueDef(..) | TyKind::Infer | TyKind::Typeof(..) | TyKind::TraitObject(..) | TyKind::Err => {
+                Position::ReborrowStable(precedence)
+            },
         };
     }
 }
@@ -920,10 +946,39 @@ fn visit_generic_arg(&mut self, arg: &GenericArg<'_>) {
     v.0
 }
 
+struct TyPosition<'tcx> {
+    position: Position,
+    ty: Option<Ty<'tcx>>,
+}
+impl From<Position> for TyPosition<'_> {
+    fn from(position: Position) -> Self {
+        Self { position, ty: None }
+    }
+}
+impl<'tcx> TyPosition<'tcx> {
+    fn new_deref_stable_for_result(precedence: i8, ty: Ty<'tcx>) -> Self {
+        Self {
+            position: Position::ReborrowStable(precedence),
+            ty: Some(ty),
+        }
+    }
+    fn position_for_result(self, cx: &LateContext<'tcx>) -> Position {
+        match (self.position, self.ty) {
+            (Position::ReborrowStable(precedence), Some(ty)) => {
+                Position::DerefStable(precedence, ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env))
+            },
+            (position, _) => position,
+        }
+    }
+    fn position_for_arg(self) -> Position {
+        self.position
+    }
+}
+
 // Checks whether a type is stable when switching to auto dereferencing,
-fn param_auto_deref_stability(ty: Ty<'_>, precedence: i8) -> Position {
+fn ty_auto_deref_stability<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, precedence: i8) -> TyPosition<'tcx> {
     let ty::Ref(_, mut ty, _) = *ty.kind() else {
-        return Position::Other(precedence);
+        return Position::Other(precedence).into();
     };
 
     loop {
@@ -932,35 +987,38 @@ fn param_auto_deref_stability(ty: Ty<'_>, precedence: i8) -> Position {
                 ty = ref_ty;
                 continue;
             },
-            ty::Infer(_)
-            | ty::Error(_)
-            | ty::Param(_)
-            | ty::Bound(..)
-            | ty::Opaque(..)
-            | ty::Placeholder(_)
-            | ty::Dynamic(..) => Position::ReborrowStable(precedence),
-            ty::Adt(..) if ty.has_placeholders() || ty.has_param_types_or_consts() => {
-                Position::ReborrowStable(precedence)
+            ty::Param(_) => TyPosition::new_deref_stable_for_result(precedence, ty),
+            ty::Infer(_) | ty::Error(_) | ty::Bound(..) | ty::Opaque(..) | ty::Placeholder(_) | ty::Dynamic(..) => {
+                Position::ReborrowStable(precedence).into()
             },
-            ty::Adt(..)
-            | ty::Bool
+            ty::Adt(..) if ty.has_placeholders() || ty.has_opaque_types() => {
+                Position::ReborrowStable(precedence).into()
+            },
+            ty::Adt(_, substs) if substs.has_param_types_or_consts() => {
+                TyPosition::new_deref_stable_for_result(precedence, ty)
+            },
+            ty::Bool
             | ty::Char
             | ty::Int(_)
             | ty::Uint(_)
-            | ty::Float(_)
-            | ty::Foreign(_)
-            | ty::Str
             | ty::Array(..)
-            | ty::Slice(..)
+            | ty::Float(_)
             | ty::RawPtr(..)
+            | ty::FnPtr(_) => Position::DerefStable(precedence, true).into(),
+            ty::Str | ty::Slice(..) => Position::DerefStable(precedence, false).into(),
+            ty::Adt(..)
+            | ty::Foreign(_)
             | ty::FnDef(..)
-            | ty::FnPtr(_)
-            | ty::Closure(..)
             | ty::Generator(..)
             | ty::GeneratorWitness(..)
+            | ty::Closure(..)
             | ty::Never
             | ty::Tuple(_)
-            | ty::Projection(_) => Position::DerefStable(precedence),
+            | ty::Projection(_) => Position::DerefStable(
+                precedence,
+                ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()),
+            )
+            .into(),
         };
     }
 }
@@ -1040,34 +1098,64 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
                 diag.span_suggestion(data.span, "change this to", sugg, app);
             });
         },
-        State::ExplicitDeref { deref_span_id } => {
-            let (span, hir_id, precedence) = if let Some((span, hir_id)) = deref_span_id
+        State::ExplicitDeref { mutability } => {
+            if matches!(
+                expr.kind,
+                ExprKind::Block(..)
+                    | ExprKind::ConstBlock(_)
+                    | ExprKind::If(..)
+                    | ExprKind::Loop(..)
+                    | ExprKind::Match(..)
+            ) && matches!(data.position, Position::DerefStable(_, true))
+            {
+                // Rustc bug: auto deref doesn't work on block expression when targeting sized types.
+                return;
+            }
+
+            let (prefix, precedence) = if let Some(mutability) = mutability
                 && !cx.typeck_results().expr_ty(expr).is_ref()
             {
-                (span, hir_id, PREC_PREFIX)
+                let prefix = match mutability {
+                    Mutability::Not => "&",
+                    Mutability::Mut => "&mut ",
+                };
+                (prefix, 0)
             } else {
-                (data.span, data.hir_id, data.position.precedence())
+                ("", data.position.precedence())
             };
             span_lint_hir_and_then(
                 cx,
                 EXPLICIT_AUTO_DEREF,
-                hir_id,
-                span,
+                data.hir_id,
+                data.span,
                 "deref which would be done by auto-deref",
                 |diag| {
                     let mut app = Applicability::MachineApplicable;
-                    let (snip, snip_is_macro) = snippet_with_context(cx, expr.span, span.ctxt(), "..", &mut app);
+                    let (snip, snip_is_macro) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app);
                     let sugg =
                         if !snip_is_macro && expr.precedence().order() < precedence && !has_enclosing_paren(&snip) {
-                            format!("({})", snip)
+                            format!("{}({})", prefix, snip)
                         } else {
-                            snip.into()
+                            format!("{}{}", prefix, snip)
                         };
-                    diag.span_suggestion(span, "try this", sugg, app);
+                    diag.span_suggestion(data.span, "try this", sugg, app);
                 },
             );
         },
         State::ExplicitDerefField { .. } => {
+            if matches!(
+                expr.kind,
+                ExprKind::Block(..)
+                    | ExprKind::ConstBlock(_)
+                    | ExprKind::If(..)
+                    | ExprKind::Loop(..)
+                    | ExprKind::Match(..)
+            ) && matches!(data.position, Position::DerefStable(_, true))
+            {
+                // Rustc bug: auto deref doesn't work on block expression when targeting sized types.
+                return;
+            }
+
             span_lint_hir_and_then(
                 cx,
                 EXPLICIT_AUTO_DEREF,
@@ -1081,7 +1169,7 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
                 },
             );
         },
-        State::Borrow | State::Reborrow { .. } => (),
+        State::Borrow { .. } | State::Reborrow { .. } => (),
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_names.rs b/src/tools/clippy/clippy_lints/src/disallowed_names.rs
new file mode 100644 (file)
index 0000000..6e6615f
--- /dev/null
@@ -0,0 +1,77 @@
+use clippy_utils::{diagnostics::span_lint, is_test_module_or_function};
+use rustc_data_structures::fx::FxHashSet;
+use rustc_hir::{Item, Pat, PatKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for usage of disallowed names for variables, such
+    /// as `foo`.
+    ///
+    /// ### Why is this bad?
+    /// These names are usually placeholder names and should be
+    /// avoided.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let foo = 3.14;
+    /// ```
+    #[clippy::version = "pre 1.29.0"]
+    pub DISALLOWED_NAMES,
+    style,
+    "usage of a disallowed/placeholder name"
+}
+
+#[derive(Clone, Debug)]
+pub struct DisallowedNames {
+    disallow: FxHashSet<String>,
+    test_modules_deep: u32,
+}
+
+impl DisallowedNames {
+    pub fn new(disallow: FxHashSet<String>) -> Self {
+        Self {
+            disallow,
+            test_modules_deep: 0,
+        }
+    }
+
+    fn in_test_module(&self) -> bool {
+        self.test_modules_deep != 0
+    }
+}
+
+impl_lint_pass!(DisallowedNames => [DISALLOWED_NAMES]);
+
+impl<'tcx> LateLintPass<'tcx> for DisallowedNames {
+    fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
+        if is_test_module_or_function(cx.tcx, item) {
+            self.test_modules_deep = self.test_modules_deep.saturating_add(1);
+        }
+    }
+
+    fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
+        // Check whether we are under the `test` attribute.
+        if self.in_test_module() {
+            return;
+        }
+
+        if let PatKind::Binding(.., ident, _) = pat.kind {
+            if self.disallow.contains(&ident.name.to_string()) {
+                span_lint(
+                    cx,
+                    DISALLOWED_NAMES,
+                    ident.span,
+                    &format!("use of a disallowed/placeholder name `{}`", ident.name),
+                );
+            }
+        }
+    }
+
+    fn check_item_post(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
+        if is_test_module_or_function(cx.tcx, item) {
+            self.test_modules_deep = self.test_modules_deep.saturating_sub(1);
+        }
+    }
+}
index a33ef5ce6e37c5a30b4c9586ffe5590bfba66235..0f1d701865e7d711bbf8ae1bdb949c31d5214611 100644 (file)
@@ -61,9 +61,8 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
                     }
                 }
             },
-            ExprKind::MethodCall(_, ref params, _) => {
-                if params.len() == 2 {
-                    let param = &params[1];
+            ExprKind::MethodCall(_, _, ref params, _) => {
+                if let [ref param] = params[..] {
                     if let ExprKind::Paren(_) = param.kind {
                         span_lint(cx, DOUBLE_PARENS, param.span, msg);
                     }
index 80c84014bfdeb7c864c2ceab833c52bd50b27f26..4f9ff97f1fd1a1ace7344eb47c6aa6259fbaa29d 100644 (file)
@@ -220,9 +220,11 @@ fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure_ty: Ty<'tcx>, call_ty: Ty<'tc
 }
 
 fn get_ufcs_type_name(cx: &LateContext<'_>, method_def_id: DefId) -> String {
-    match cx.tcx.associated_item(method_def_id).container {
-        ty::TraitContainer(def_id) => cx.tcx.def_path_str(def_id),
-        ty::ImplContainer(def_id) => {
+    let assoc_item = cx.tcx.associated_item(method_def_id);
+    let def_id = assoc_item.container_id(cx.tcx);
+    match assoc_item.container {
+        ty::TraitContainer => cx.tcx.def_path_str(def_id),
+        ty::ImplContainer => {
             let ty = cx.tcx.type_of(def_id);
             match ty.kind() {
                 ty::Adt(adt, _) => cx.tcx.def_path_str(adt.did()),
index db0166da57f0e343fb65e3898b8320b3b42bd1f3..01cefe4af8532638a5179eba0c26fde9599fcdbe 100644 (file)
@@ -1,4 +1,5 @@
 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note};
+use clippy_utils::is_span_if;
 use clippy_utils::source::snippet_opt;
 use if_chain::if_chain;
 use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp};
@@ -297,12 +298,11 @@ fn check_array(cx: &EarlyContext<'_>, expr: &Expr) {
 fn check_missing_else(cx: &EarlyContext<'_>, first: &Expr, second: &Expr) {
     if_chain! {
         if !first.span.from_expansion() && !second.span.from_expansion();
-        if let ExprKind::If(cond_expr, ..) = &first.kind;
+        if matches!(first.kind, ExprKind::If(..));
         if is_block(second) || is_if(second);
 
         // Proc-macros can give weird spans. Make sure this is actually an `if`.
-        if let Some(if_snip) = snippet_opt(cx, first.span.until(cond_expr.span));
-        if if_snip.starts_with("if");
+        if is_span_if(cx, first.span);
 
         // If there is a line break between the two expressions, don't lint.
         // If there is a non-whitespace character, this span came from a proc-macro.
index 57b0751320521b5bab69b34e34a0196e6517213a..74941d817be360bec835d08f4747b9e0078651fd 100644 (file)
@@ -46,7 +46,7 @@
 impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, exp: &Expr<'tcx>) {
         if_chain! {
-            if let ExprKind::Call(maybe_path, arguments) = &exp.kind;
+            if let ExprKind::Call(maybe_path, [src, radix]) = &exp.kind;
             if let ExprKind::Path(QPath::TypeRelative(ty, pathseg)) = &maybe_path.kind;
 
             // check if the first part of the path is some integer primitive
@@ -60,20 +60,19 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, exp: &Expr<'tcx>) {
             if pathseg.ident.name.as_str() == "from_str_radix";
 
             // check if the second argument is a primitive `10`
-            if arguments.len() == 2;
-            if let ExprKind::Lit(lit) = &arguments[1].kind;
+            if let ExprKind::Lit(lit) = &radix.kind;
             if let rustc_ast::ast::LitKind::Int(10, _) = lit.node;
 
             then {
-                let expr = if let ExprKind::AddrOf(_, _, expr) = &arguments[0].kind {
+                let expr = if let ExprKind::AddrOf(_, _, expr) = &src.kind {
                     let ty = cx.typeck_results().expr_ty(expr);
                     if is_ty_stringish(cx, ty) {
                         expr
                     } else {
-                        &arguments[0]
+                        &src
                     }
                 } else {
-                    &arguments[0]
+                    &src
                 };
 
                 let sugg = Sugg::hir_with_applicability(
index 5c46d6c7df7056856ed7afcd3d37f09b70cd2808..ef7d75aa8ed9b56a264ace501e0e36e21426d9e5 100644 (file)
@@ -9,7 +9,7 @@
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::{sym, Span};
 use rustc_trait_selection::traits::error_reporting::suggestions::InferCtxtExt;
-use rustc_trait_selection::traits::{self, FulfillmentError, TraitEngine};
+use rustc_trait_selection::traits::{self, FulfillmentError};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -80,9 +80,7 @@ fn check_fn(
                 let span = decl.output.span();
                 let send_errors = cx.tcx.infer_ctxt().enter(|infcx| {
                     let cause = traits::ObligationCause::misc(span, hir_id);
-                    let mut fulfillment_cx = traits::FulfillmentContext::new();
-                    fulfillment_cx.register_bound(&infcx, cx.param_env, ret_ty, send_trait, cause);
-                    fulfillment_cx.select_all_or_error(&infcx)
+                    traits::fully_solve_bound(&infcx, cause, cx.param_env, ret_ty, send_trait)
                 });
                 if !send_errors.is_empty() {
                     span_lint_and_then(
index 5be1c417bf8f665701e92f588782508680079ff7..01082cc8eeb64933304d54f3c2616d81a723f247 100644 (file)
@@ -6,7 +6,6 @@
     LintId::of(almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE),
     LintId::of(approx_const::APPROX_CONSTANT),
     LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS),
-    LintId::of(assertions_on_result_states::ASSERTIONS_ON_RESULT_STATES),
     LintId::of(async_yields_async::ASYNC_YIELDS_ASYNC),
     LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS),
     LintId::of(attrs::DEPRECATED_CFG_ATTR),
     LintId::of(await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE),
     LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK),
     LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
-    LintId::of(blacklisted_name::BLACKLISTED_NAME),
     LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
     LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON),
-    LintId::of(booleans::LOGIC_BUG),
     LintId::of(booleans::NONMINIMAL_BOOL),
+    LintId::of(booleans::OVERLY_COMPLEX_BOOL_EXPR),
     LintId::of(borrow_deref_ref::BORROW_DEREF_REF),
     LintId::of(bytes_count_to_len::BYTES_COUNT_TO_LEN),
     LintId::of(casts::CAST_ABS_TO_UNSIGNED),
@@ -47,6 +45,7 @@
     LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD),
     LintId::of(derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ),
     LintId::of(disallowed_methods::DISALLOWED_METHODS),
+    LintId::of(disallowed_names::DISALLOWED_NAMES),
     LintId::of(disallowed_types::DISALLOWED_TYPES),
     LintId::of(doc::MISSING_SAFETY_DOC),
     LintId::of(doc::NEEDLESS_DOCTEST_MAIN),
     LintId::of(matches::MATCH_STR_CASE_MISMATCH),
     LintId::of(matches::NEEDLESS_MATCH),
     LintId::of(matches::REDUNDANT_PATTERN_MATCHING),
-    LintId::of(matches::SIGNIFICANT_DROP_IN_SCRUTINEE),
     LintId::of(matches::SINGLE_MATCH),
     LintId::of(matches::WILDCARD_IN_OR_PATTERNS),
     LintId::of(mem_replace::MEM_REPLACE_OPTION_WITH_NONE),
     LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP),
     LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL),
     LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL),
+    LintId::of(partialeq_to_none::PARTIALEQ_TO_NONE),
     LintId::of(precedence::PRECEDENCE),
     LintId::of(ptr::CMP_NULL),
     LintId::of(ptr::INVALID_NULL_PTR_USAGE),
index 9975859c54fea5a7bd676730d8b2d24cf58b5385..006275d1383ff0d313784fb9a5a486d88068bd3e 100644 (file)
@@ -8,7 +8,7 @@
     LintId::of(attrs::DEPRECATED_SEMVER),
     LintId::of(attrs::MISMATCHED_TARGET_OS),
     LintId::of(attrs::USELESS_ATTRIBUTE),
-    LintId::of(booleans::LOGIC_BUG),
+    LintId::of(booleans::OVERLY_COMPLEX_BOOL_EXPR),
     LintId::of(casts::CAST_REF_TO_MUT),
     LintId::of(casts::CAST_SLICE_DIFFERENT_SIZES),
     LintId::of(copies::IFS_SAME_COND),
index 99bde35cf152b96bebf97fc279ed91aed7534a10..c540573b80228e8f3786a4117ab3dbda503266f7 100644 (file)
     await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE,
     await_holding_invalid::AWAIT_HOLDING_LOCK,
     await_holding_invalid::AWAIT_HOLDING_REFCELL_REF,
-    blacklisted_name::BLACKLISTED_NAME,
     blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS,
     bool_assert_comparison::BOOL_ASSERT_COMPARISON,
-    booleans::LOGIC_BUG,
     booleans::NONMINIMAL_BOOL,
+    booleans::OVERLY_COMPLEX_BOOL_EXPR,
     borrow_as_ptr::BORROW_AS_PTR,
     borrow_deref_ref::BORROW_DEREF_REF,
     bytecount::NAIVE_BYTECOUNT,
     derive::EXPL_IMPL_CLONE_ON_COPY,
     derive::UNSAFE_DERIVE_DESERIALIZE,
     disallowed_methods::DISALLOWED_METHODS,
+    disallowed_names::DISALLOWED_NAMES,
     disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS,
     disallowed_types::DISALLOWED_TYPES,
     doc::DOC_MARKDOWN,
     manual_assert::MANUAL_ASSERT,
     manual_async_fn::MANUAL_ASYNC_FN,
     manual_bits::MANUAL_BITS,
+    manual_instant_elapsed::MANUAL_INSTANT_ELAPSED,
     manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE,
     manual_ok_or::MANUAL_OK_OR,
     manual_rem_euclid::MANUAL_REM_EUCLID,
     panic_unimplemented::UNIMPLEMENTED,
     panic_unimplemented::UNREACHABLE,
     partialeq_ne_impl::PARTIALEQ_NE_IMPL,
+    partialeq_to_none::PARTIALEQ_TO_NONE,
     pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE,
     pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF,
     path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE,
index 642d629971d90b678b0509bac6daec53d6882356..91210b23afe30c46c31d796b7b4f1e1bdcae82b5 100644 (file)
@@ -13,6 +13,7 @@
     LintId::of(future_not_send::FUTURE_NOT_SEND),
     LintId::of(index_refutable_slice::INDEX_REFUTABLE_SLICE),
     LintId::of(let_if_seq::USELESS_LET_IF_SEQ),
+    LintId::of(matches::SIGNIFICANT_DROP_IN_SCRUTINEE),
     LintId::of(methods::ITER_WITH_DRAIN),
     LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN),
     LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL),
index a1b5466581491253448d7242ea16d6e2b4aa269d..bd7d1a15ab4ea1dad05f3b905d28f3392107d38f 100644 (file)
@@ -49,6 +49,7 @@
     LintId::of(loops::EXPLICIT_ITER_LOOP),
     LintId::of(macro_use::MACRO_USE_IMPORTS),
     LintId::of(manual_assert::MANUAL_ASSERT),
+    LintId::of(manual_instant_elapsed::MANUAL_INSTANT_ELAPSED),
     LintId::of(manual_ok_or::MANUAL_OK_OR),
     LintId::of(matches::MATCH_BOOL),
     LintId::of(matches::MATCH_ON_VEC_ITEMS),
index 495abd8387e85e0bd8ce1c073e02b6ec4e4564b6..a7339ef272174d4ee4955b60edd66778cd032461 100644 (file)
@@ -7,6 +7,7 @@
     LintId::of(as_underscore::AS_UNDERSCORE),
     LintId::of(asm_syntax::INLINE_ASM_X86_ATT_SYNTAX),
     LintId::of(asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX),
+    LintId::of(assertions_on_result_states::ASSERTIONS_ON_RESULT_STATES),
     LintId::of(attrs::ALLOW_ATTRIBUTES_WITHOUT_REASON),
     LintId::of(casts::FN_TO_NUMERIC_CAST_ANY),
     LintId::of(create_dir::CREATE_DIR),
index e029a5235e720995a26ddac5fd07301917a31a64..bfa654238f130386f1332b134d6a86eefc0fe544 100644 (file)
@@ -4,8 +4,6 @@
 
 store.register_group(true, "clippy::style", Some("clippy_style"), vec![
     LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS),
-    LintId::of(assertions_on_result_states::ASSERTIONS_ON_RESULT_STATES),
-    LintId::of(blacklisted_name::BLACKLISTED_NAME),
     LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
     LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON),
     LintId::of(casts::FN_TO_NUMERIC_CAST),
@@ -18,6 +16,7 @@
     LintId::of(dereference::NEEDLESS_BORROW),
     LintId::of(derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ),
     LintId::of(disallowed_methods::DISALLOWED_METHODS),
+    LintId::of(disallowed_names::DISALLOWED_NAMES),
     LintId::of(disallowed_types::DISALLOWED_TYPES),
     LintId::of(doc::MISSING_SAFETY_DOC),
     LintId::of(doc::NEEDLESS_DOCTEST_MAIN),
     LintId::of(operators::ASSIGN_OP_PATTERN),
     LintId::of(operators::OP_REF),
     LintId::of(operators::PTR_EQ),
+    LintId::of(partialeq_to_none::PARTIALEQ_TO_NONE),
     LintId::of(ptr::CMP_NULL),
     LintId::of(ptr::PTR_ARG),
     LintId::of(question_mark::QUESTION_MARK),
index f7558f8709810fe51d3475758f954fa76fa7fece..964992bd94fe259f64aa4cd6a99a3e05621cca44 100644 (file)
@@ -22,7 +22,6 @@
     LintId::of(loops::EMPTY_LOOP),
     LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES),
     LintId::of(loops::MUT_RANGE_BOUND),
-    LintId::of(matches::SIGNIFICANT_DROP_IN_SCRUTINEE),
     LintId::of(methods::NO_EFFECT_REPLACE),
     LintId::of(methods::SUSPICIOUS_MAP),
     LintId::of(mut_key::MUTABLE_KEY_TYPE),
index eb3841272b17f4709c76697ff8f68f2266b9caa7..2975399a8bbbacca3e07ff1b7b42f05ee74ed7e3 100644 (file)
@@ -178,7 +178,6 @@ macro_rules! declare_clippy_lint {
 mod async_yields_async;
 mod attrs;
 mod await_holding_invalid;
-mod blacklisted_name;
 mod blocks_in_if_conditions;
 mod bool_assert_comparison;
 mod booleans;
@@ -206,6 +205,7 @@ macro_rules! declare_clippy_lint {
 mod derivable_impls;
 mod derive;
 mod disallowed_methods;
+mod disallowed_names;
 mod disallowed_script_idents;
 mod disallowed_types;
 mod doc;
@@ -274,6 +274,7 @@ macro_rules! declare_clippy_lint {
 mod manual_assert;
 mod manual_async_fn;
 mod manual_bits;
+mod manual_instant_elapsed;
 mod manual_non_exhaustive;
 mod manual_ok_or;
 mod manual_rem_euclid;
@@ -332,6 +333,7 @@ macro_rules! declare_clippy_lint {
 mod panic_in_result_fn;
 mod panic_unimplemented;
 mod partialeq_ne_impl;
+mod partialeq_to_none;
 mod pass_by_ref_or_value;
 mod path_buf_push_overwrite;
 mod pattern_type_mismatch;
@@ -487,7 +489,7 @@ pub fn read_conf(sess: &Session) -> Conf {
         },
     };
 
-    let TryConf { conf, errors } = utils::conf::read(&file_name);
+    let TryConf { conf, errors, warnings } = utils::conf::read(&file_name);
     // all conf errors are non-fatal, we just use the default conf in case of error
     for error in errors {
         sess.err(&format!(
@@ -497,6 +499,15 @@ pub fn read_conf(sess: &Session) -> Conf {
         ));
     }
 
+    for warning in warnings {
+        sess.struct_warn(&format!(
+            "error reading Clippy's configuration file `{}`: {}",
+            file_name.display(),
+            format_error(warning)
+        ))
+        .emit();
+    }
+
     conf
 }
 
@@ -675,8 +686,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| Box::new(swap::Swap));
     store.register_late_pass(|| Box::new(overflow_check_conditional::OverflowCheckConditional));
     store.register_late_pass(|| Box::new(new_without_default::NewWithoutDefault::default()));
-    let blacklisted_names = conf.blacklisted_names.iter().cloned().collect::<FxHashSet<_>>();
-    store.register_late_pass(move || Box::new(blacklisted_name::BlacklistedName::new(blacklisted_names.clone())));
+    let disallowed_names = conf.disallowed_names.iter().cloned().collect::<FxHashSet<_>>();
+    store.register_late_pass(move || Box::new(disallowed_names::DisallowedNames::new(disallowed_names.clone())));
     let too_many_arguments_threshold = conf.too_many_arguments_threshold;
     let too_many_lines_threshold = conf.too_many_lines_threshold;
     store.register_late_pass(move || {
@@ -921,6 +932,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(move || Box::new(operators::Operators::new(verbose_bit_mask_threshold)));
     store.register_late_pass(|| Box::new(invalid_utf8_in_unchecked::InvalidUtf8InUnchecked));
     store.register_late_pass(|| Box::new(std_instead_of_core::StdReexports::default()));
+    store.register_late_pass(|| Box::new(manual_instant_elapsed::ManualInstantElapsed));
+    store.register_late_pass(|| Box::new(partialeq_to_none::PartialeqToNone));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
index b31015d195b52007211e0bf97b04b39f9c19733e..a65df48e413e842115fc8154ab7787944d4c2851 100644 (file)
@@ -119,11 +119,9 @@ fn print_offset(offset: MinifyingSugg<'static>) -> MinifyingSugg<'static> {
 
     let print_limit = |end: &Expr<'_>, end_str: &str, base: &Expr<'_>, sugg: MinifyingSugg<'static>| {
         if_chain! {
-            if let ExprKind::MethodCall(method, len_args, _) = end.kind;
+            if let ExprKind::MethodCall(method, [recv], _) = end.kind;
             if method.ident.name == sym::len;
-            if len_args.len() == 1;
-            if let Some(arg) = len_args.get(0);
-            if path_to_local(arg) == path_to_local(base);
+            if path_to_local(recv) == path_to_local(base);
             then {
                 if sugg.to_string() == end_str {
                     sugg::EMPTY.into()
@@ -343,10 +341,8 @@ fn get_slice_like_element_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Opti
 
 fn fetch_cloned_expr<'tcx>(expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
     if_chain! {
-        if let ExprKind::MethodCall(method, args, _) = expr.kind;
+        if let ExprKind::MethodCall(method, [arg], _) = expr.kind;
         if method.ident.name == sym::clone;
-        if args.len() == 1;
-        if let Some(arg) = args.get(0);
         then { arg } else { expr }
     }
 }
index a7ef562b21fc48880a253b2d8a612920f550832f..7ca4a7c4ebfc276a60a692f1491056942a621810 100644 (file)
@@ -188,10 +188,9 @@ pub(super) fn check<'tcx>(
 
 fn is_len_call(expr: &Expr<'_>, var: Symbol) -> bool {
     if_chain! {
-        if let ExprKind::MethodCall(method, len_args, _) = expr.kind;
-        if len_args.len() == 1;
+        if let ExprKind::MethodCall(method, [recv], _) = expr.kind;
         if method.ident.name == sym::len;
-        if let ExprKind::Path(QPath::Resolved(_, path)) = len_args[0].kind;
+        if let ExprKind::Path(QPath::Resolved(_, path)) = recv.kind;
         if path.segments.len() == 1;
         if path.segments[0].ident.name == var;
         then {
diff --git a/src/tools/clippy/clippy_lints/src/manual_instant_elapsed.rs b/src/tools/clippy/clippy_lints/src/manual_instant_elapsed.rs
new file mode 100644 (file)
index 0000000..331cda1
--- /dev/null
@@ -0,0 +1,69 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use rustc_errors::Applicability;
+use rustc_hir::{BinOpKind, Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::source_map::Spanned;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Lints subtraction between `Instant::now()` and another `Instant`.
+    ///
+    /// ### Why is this bad?
+    /// It is easy to accidentally write `prev_instant - Instant::now()`, which will always be 0ns
+    /// as `Instant` subtraction saturates.
+    ///
+    /// `prev_instant.elapsed()` also more clearly signals intention.
+    ///
+    /// ### Example
+    /// ```rust
+    /// use std::time::Instant;
+    /// let prev_instant = Instant::now();
+    /// let duration = Instant::now() - prev_instant;
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// use std::time::Instant;
+    /// let prev_instant = Instant::now();
+    /// let duration = prev_instant.elapsed();
+    /// ```
+    #[clippy::version = "1.64.0"]
+    pub MANUAL_INSTANT_ELAPSED,
+    pedantic,
+    "subtraction between `Instant::now()` and previous `Instant`"
+}
+
+declare_lint_pass!(ManualInstantElapsed => [MANUAL_INSTANT_ELAPSED]);
+
+impl LateLintPass<'_> for ManualInstantElapsed {
+    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
+        if let ExprKind::Binary(Spanned {node: BinOpKind::Sub, ..}, lhs, rhs) = expr.kind
+            && check_instant_now_call(cx, lhs)
+            && let ty_resolved = cx.typeck_results().expr_ty(rhs)
+            && let rustc_middle::ty::Adt(def, _) = ty_resolved.kind()
+            && clippy_utils::match_def_path(cx, def.did(), &clippy_utils::paths::INSTANT)
+            && let Some(sugg) = clippy_utils::sugg::Sugg::hir_opt(cx, rhs)
+        {
+            span_lint_and_sugg(
+                cx,
+                MANUAL_INSTANT_ELAPSED,
+                expr.span,
+                "manual implementation of `Instant::elapsed`",
+                "try",
+                format!("{}.elapsed()", sugg.maybe_par()),
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+}
+
+fn check_instant_now_call(cx: &LateContext<'_>, expr_block: &'_ Expr<'_>) -> bool {
+    if let ExprKind::Call(fn_expr, []) = expr_block.kind
+        && let Some(fn_id) = clippy_utils::path_def_id(cx, fn_expr)
+        && clippy_utils::match_def_path(cx, fn_id, &clippy_utils::paths::INSTANT_NOW)
+    {
+        true
+    } else {
+        false
+    }
+}
index 9abf2507b921c79f915e779d02e0adfeb774fd73..cf5004399b884cb67e8e1553e4d7aaa9ab9eba5f 100644 (file)
@@ -47,17 +47,14 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'tcx>) {
         }
 
         if_chain! {
-            if let ExprKind::MethodCall(method_segment, args, _) = scrutinee.kind;
+            if let ExprKind::MethodCall(method_segment, [receiver, or_expr, map_expr], _) = scrutinee.kind;
             if method_segment.ident.name == sym!(map_or);
-            if args.len() == 3;
-            let method_receiver = &args[0];
-            let ty = cx.typeck_results().expr_ty(method_receiver);
+            let ty = cx.typeck_results().expr_ty(receiver);
             if is_type_diagnostic_item(cx, ty, sym::Option);
-            let or_expr = &args[1];
-            if is_ok_wrapping(cx, &args[2]);
+            if is_ok_wrapping(cx, map_expr);
             if let ExprKind::Call(Expr { kind: ExprKind::Path(err_path), .. }, &[ref err_arg]) = or_expr.kind;
             if is_lang_ctor(cx, err_path, ResultErr);
-            if let Some(method_receiver_snippet) = snippet_opt(cx, method_receiver.span);
+            if let Some(method_receiver_snippet) = snippet_opt(cx, receiver.span);
             if let Some(err_arg_snippet) = snippet_opt(cx, err_arg.span);
             if let Some(indent) = indent_of(cx, scrutinee.span);
             then {
index 21d0e19eb0a489998a98b2ebcee90f9f514b86a1..1e542447c96eca92b3668e723c5bef92393abb68 100644 (file)
@@ -113,10 +113,10 @@ fn check_expr(&mut self, cx: &LateContext<'_>, e: &Expr<'_>) {
         }
 
         // check if this is a method call (e.g. x.foo())
-        if let ExprKind::MethodCall(method, args, _) = e.kind {
+        if let ExprKind::MethodCall(method, [_, arg], _) = e.kind {
             // only work if the method name is `map_err` and there are only 2 arguments (e.g. x.map_err(|_|[1]
             // Enum::Variant[2]))
-            if method.ident.as_str() == "map_err" && args.len() == 2 {
+            if method.ident.name == sym!(map_err) {
                 // make sure the first argument is a closure, and grab the CaptureRef, BodyId, and fn_decl_span
                 // fields
                 if let ExprKind::Closure(&Closure {
@@ -124,7 +124,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, e: &Expr<'_>) {
                     body,
                     fn_decl_span,
                     ..
-                }) = args[1].kind
+                }) = arg.kind
                 {
                     // check if this is by Reference (meaning there's no move statement)
                     if capture_clause == CaptureBy::Ref {
index af9d948af00e68e7425f3166e5f09f5da7fd01a2..6db852c3ffe79a1c6f9234f7f3b3a35cd6af7848 100644 (file)
 declare_lint_pass!(MapUnit => [OPTION_MAP_UNIT_FN, RESULT_MAP_UNIT_FN]);
 
 fn is_unit_type(ty: Ty<'_>) -> bool {
-    match ty.kind() {
-        ty::Tuple(slice) => slice.is_empty(),
-        ty::Never => true,
-        _ => false,
-    }
+    ty.is_unit() || ty.is_never()
 }
 
 fn is_unit_function(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
index d914eba01716b69e6fb182bcede18001c2e6f94b..a0efdecec67f49aac5d6af449d4156c6059729e1 100644 (file)
@@ -72,10 +72,10 @@ fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option<BindingAnnotat
         if is_lang_ctor(cx, qpath, LangItem::OptionSome);
         if let PatKind::Binding(rb, .., ident, _) = first_pat.kind;
         if rb == BindingAnnotation::Ref || rb == BindingAnnotation::RefMut;
-        if let ExprKind::Call(e, args) = peel_blocks(arm.body).kind;
+        if let ExprKind::Call(e, [arg]) = peel_blocks(arm.body).kind;
         if let ExprKind::Path(ref some_path) = e.kind;
-        if is_lang_ctor(cx, some_path, LangItem::OptionSome) && args.len() == 1;
-        if let ExprKind::Path(QPath::Resolved(_, path2)) = args[0].kind;
+        if is_lang_ctor(cx, some_path, LangItem::OptionSome);
+        if let ExprKind::Path(QPath::Resolved(_, path2)) = arg.kind;
         if path2.segments.len() == 1 && ident.name == path2.segments[0].ident.name;
         then {
             return Some(rb)
index b638f2716028284ef20874c53cf1d6187f79ef5e..e6b183fc05f25df01fabded1ce6bb49835880cf9 100644 (file)
@@ -21,8 +21,8 @@
 mod try_err;
 mod wild_in_or_pats;
 
-use clippy_utils::source::{snippet_opt, span_starts_with, walk_span_to_context};
-use clippy_utils::{higher, in_constant, meets_msrv, msrvs};
+use clippy_utils::source::{snippet_opt, walk_span_to_context};
+use clippy_utils::{higher, in_constant, is_span_match, meets_msrv, msrvs};
 use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat};
 use rustc_lexer::{tokenize, TokenKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
     /// ```
     #[clippy::version = "1.60.0"]
     pub SIGNIFICANT_DROP_IN_SCRUTINEE,
-    suspicious,
+    nursery,
     "warns when a temporary of a type with a drop with a significant side-effect might have a surprising lifetime"
 }
 
@@ -949,7 +949,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         let from_expansion = expr.span.from_expansion();
 
         if let ExprKind::Match(ex, arms, source) = expr.kind {
-            if source == MatchSource::Normal && !span_starts_with(cx, expr.span, "match") {
+            if source == MatchSource::Normal && !is_span_match(cx, expr.span) {
                 return;
             }
             if matches!(source, MatchSource::Normal | MatchSource::ForLoopDesugar) {
@@ -1112,7 +1112,7 @@ fn span_contains_cfg(cx: &LateContext<'_>, s: Span) -> bool {
     let mut pos = 0usize;
     let mut iter = tokenize(&snip).map(|t| {
         let start = pos;
-        pos += t.len;
+        pos += t.len as usize;
         (t.kind, start..pos)
     });
 
index 0491a0679f37abc89393aec264321c296316b721..663277d11365fa53e11f8f886d631d2dbcb33bdb 100644 (file)
@@ -23,12 +23,10 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, scrutine
     //         val,
     // };
     if_chain! {
-        if let ExprKind::Call(match_fun, try_args) = scrutinee.kind;
+        if let ExprKind::Call(match_fun, [try_arg, ..]) = scrutinee.kind;
         if let ExprKind::Path(ref match_fun_path) = match_fun.kind;
         if matches!(match_fun_path, QPath::LangItem(LangItem::TryTraitBranch, ..));
-        if let Some(try_arg) = try_args.get(0);
-        if let ExprKind::Call(err_fun, err_args) = try_arg.kind;
-        if let Some(err_arg) = err_args.get(0);
+        if let ExprKind::Call(err_fun, [err_arg, ..]) = try_arg.kind;
         if let ExprKind::Path(ref err_fun_path) = err_fun.kind;
         if is_lang_ctor(cx, err_fun_path, ResultErr);
         if let Some(return_ty) = find_return_type(cx, &expr.kind);
index 41073d40f3d79052530e6afc063eeeb9ed44f970..cad3ea2a176cd0c25b5dc80fc2097cfbce45a2c0 100644 (file)
@@ -163,8 +163,7 @@ fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'
     }
 
     if_chain! {
-        if let ExprKind::Call(repl_func, repl_args) = src.kind;
-        if repl_args.is_empty();
+        if let ExprKind::Call(repl_func, []) = src.kind;
         if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind;
         if let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id();
         then {
@@ -246,11 +245,10 @@ impl<'tcx> LateLintPass<'tcx> for MemReplace {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if_chain! {
             // Check that `expr` is a call to `mem::replace()`
-            if let ExprKind::Call(func, func_args) = expr.kind;
+            if let ExprKind::Call(func, [dest, src]) = expr.kind;
             if let ExprKind::Path(ref func_qpath) = func.kind;
             if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id();
             if cx.tcx.is_diagnostic_item(sym::mem_replace, def_id);
-            if let [dest, src] = func_args;
             then {
                 check_replace_option_with_none(cx, src, dest, expr.span);
                 check_replace_with_uninit(cx, src, dest, expr.span);
index 0b38a07204e86cec08a825a3d00b5e7b3dc09c46..60e1355f9b92d889036ae7b2c67e4d510e4305c0 100644 (file)
@@ -4,7 +4,7 @@
 use clippy_utils::sugg;
 use clippy_utils::ty::is_copy;
 use rustc_errors::Applicability;
-use rustc_hir::{BindingAnnotation, Expr, ExprKind, MatchSource, Node, PatKind};
+use rustc_hir::{BindingAnnotation, Expr, ExprKind, MatchSource, Node, PatKind, QPath};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, adjustment::Adjust};
 use rustc_span::symbol::{sym, Symbol};
@@ -86,6 +86,11 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol,
                 {
                     return;
                 },
+                // ? is a Call, makes sure not to rec *x?, but rather (*x)?
+                ExprKind::Call(hir_callee, _) => matches!(
+                    hir_callee.kind,
+                    ExprKind::Path(QPath::LangItem(rustc_hir::LangItem::TryTraitBranch, _, _))
+                ),
                 ExprKind::MethodCall(_, [self_arg, ..], _) if expr.hir_id == self_arg.hir_id => true,
                 ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar)
                 | ExprKind::Field(..)
index fbc3348f1855fe3b7a8af071101bde3548905971..5ef08ca6290bae6adbc15a6887edbd755c040711 100644 (file)
@@ -12,9 +12,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
     let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
 
     let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) {
-        Some((EXPECT_USED, "an Option", "None"))
+        Some((EXPECT_USED, "an Option", "None", ""))
     } else if is_type_diagnostic_item(cx, obj_ty, sym::Result) {
-        Some((EXPECT_USED, "a Result", "Err"))
+        Some((EXPECT_USED, "a Result", "Err", "an "))
     } else {
         None
     };
@@ -23,14 +23,14 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
         return;
     }
 
-    if let Some((lint, kind, none_value)) = mess {
+    if let Some((lint, kind, none_value, none_prefix)) = mess {
         span_lint_and_help(
             cx,
             lint,
             expr.span,
-            &format!("used `expect()` on `{}` value", kind,),
+            &format!("used `expect()` on `{kind}` value"),
             None,
-            &format!("if this value is an `{}`, it will panic", none_value,),
+            &format!("if this value is {none_prefix}`{none_value}`, it will panic"),
         );
     }
 }
index 202fbc1f7f668039e998a43c8b60c195b35d78c2..5ac6b09f0aa27bff22fa87c05292791f0a13f1b0 100644 (file)
     /// option.expect("more helpful message");
     /// result.expect("more helpful message");
     /// ```
+    ///
+    /// If [expect_used](#expect_used) is enabled, instead:
+    /// ```rust,ignore
+    /// # let option = Some(1);
+    /// # let result: Result<usize, ()> = Ok(1);
+    /// option?;
+    ///
+    /// // or
+    ///
+    /// result?;
+    /// ```
     #[clippy::version = "1.45.0"]
     pub UNWRAP_USED,
     restriction,
index 5c761014927c28dae2af593d4dcfaf5d46efb28e..ce1a52e5480afb81226859153023754301935f84 100644 (file)
@@ -1,20 +1,20 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::is_in_test_function;
 use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::{is_in_test_function, is_lint_allowed};
 use rustc_hir as hir;
 use rustc_lint::LateContext;
 use rustc_span::sym;
 
-use super::UNWRAP_USED;
+use super::{EXPECT_USED, UNWRAP_USED};
 
 /// lint use of `unwrap()` for `Option`s and `Result`s
 pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, allow_unwrap_in_tests: bool) {
     let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
 
     let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) {
-        Some((UNWRAP_USED, "an Option", "None"))
+        Some((UNWRAP_USED, "an Option", "None", ""))
     } else if is_type_diagnostic_item(cx, obj_ty, sym::Result) {
-        Some((UNWRAP_USED, "a Result", "Err"))
+        Some((UNWRAP_USED, "a Result", "Err", "an "))
     } else {
         None
     };
@@ -23,18 +23,23 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
         return;
     }
 
-    if let Some((lint, kind, none_value)) = mess {
+    if let Some((lint, kind, none_value, none_prefix)) = mess {
+        let help = if is_lint_allowed(cx, EXPECT_USED, expr.hir_id) {
+            format!(
+                "if you don't want to handle the `{none_value}` case gracefully, consider \
+                using `expect()` to provide a better panic message"
+            )
+        } else {
+            format!("if this value is {none_prefix}`{none_value}`, it will panic")
+        };
+
         span_lint_and_help(
             cx,
             lint,
             expr.span,
-            &format!("used `unwrap()` on `{}` value", kind,),
+            &format!("used `unwrap()` on `{kind}` value"),
             None,
-            &format!(
-                "if you don't want to handle the `{}` case gracefully, consider \
-                using `expect()` to provide a better panic message",
-                none_value,
-            ),
+            &help,
         );
     }
 }
index 16d65966c10096622166221906219d1fdba863b1..bc304c081b9062ec2f121665a81db06a6a20d48b 100644 (file)
@@ -1,7 +1,9 @@
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::qualify_min_const_fn::is_min_const_fn;
 use clippy_utils::ty::has_drop;
-use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, meets_msrv, msrvs, trait_ref_of_method};
+use clippy_utils::{
+    fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_macro, meets_msrv, msrvs, trait_ref_of_method,
+};
 use rustc_hir as hir;
 use rustc_hir::def_id::CRATE_DEF_ID;
 use rustc_hir::intravisit::FnKind;
@@ -86,10 +88,10 @@ pub fn new(msrv: Option<RustcVersion>) -> Self {
 impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
     fn check_fn(
         &mut self,
-        cx: &LateContext<'_>,
-        kind: FnKind<'_>,
+        cx: &LateContext<'tcx>,
+        kind: FnKind<'tcx>,
         _: &FnDecl<'_>,
-        _: &Body<'_>,
+        body: &Body<'tcx>,
         span: Span,
         hir_id: HirId,
     ) {
@@ -124,7 +126,7 @@ fn check_fn(
             FnKind::Method(_, sig, ..) => {
                 if trait_ref_of_method(cx, def_id).is_some()
                     || already_const(sig.header)
-                    || method_accepts_dropable(cx, sig.decl.inputs)
+                    || method_accepts_droppable(cx, sig.decl.inputs)
                 {
                     return;
                 }
@@ -144,6 +146,10 @@ fn check_fn(
             }
         }
 
+        if is_from_proc_macro(cx, &(&kind, body, hir_id, span)) {
+            return;
+        }
+
         let mir = cx.tcx.optimized_mir(def_id);
 
         if let Err((span, err)) = is_min_const_fn(cx.tcx, mir, self.msrv) {
@@ -159,7 +165,7 @@ fn check_fn(
 
 /// Returns true if any of the method parameters is a type that implements `Drop`. The method
 /// can't be made const then, because `drop` can't be const-evaluated.
-fn method_accepts_dropable(cx: &LateContext<'_>, param_tys: &[hir::Ty<'_>]) -> bool {
+fn method_accepts_droppable(cx: &LateContext<'_>, param_tys: &[hir::Ty<'_>]) -> bool {
     // If any of the params are droppable, return true
     param_tys.iter().any(|hir_ty| {
         let ty_ty = hir_ty_to_ty(cx.tcx, hir_ty);
index a20377f320b23b2dca9b7c2e30f48b249956876f..3701fdb4adbffb1604b38dacf38166161098716a 100644 (file)
@@ -7,10 +7,11 @@
 
 use clippy_utils::attrs::is_doc_hidden;
 use clippy_utils::diagnostics::span_lint;
-use rustc_ast::ast;
+use clippy_utils::is_from_proc_macro;
+use rustc_ast::ast::{self, MetaItem, MetaItemKind};
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::ty::{self, DefIdTree};
+use rustc_middle::ty::DefIdTree;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::def_id::CRATE_DEF_ID;
 use rustc_span::source_map::Span;
@@ -57,6 +58,20 @@ fn doc_hidden(&self) -> bool {
         *self.doc_hidden_stack.last().expect("empty doc_hidden_stack")
     }
 
+    fn has_include(meta: Option<MetaItem>) -> bool {
+        if_chain! {
+            if let Some(meta) = meta;
+            if let MetaItemKind::List(list) = meta.kind;
+            if let Some(meta) = list.get(0);
+            if let Some(name) = meta.ident();
+            then {
+                name.name == sym::include
+            } else {
+                false
+            }
+        }
+    }
+
     fn check_missing_docs_attrs(
         &self,
         cx: &LateContext<'_>,
@@ -80,7 +95,9 @@ fn check_missing_docs_attrs(
             return;
         }
 
-        let has_doc = attrs.iter().any(|a| a.doc_str().is_some());
+        let has_doc = attrs
+            .iter()
+            .any(|a| a.doc_str().is_some() || Self::has_include(a.meta()));
         if !has_doc {
             span_lint(
                 cx,
@@ -141,41 +158,50 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) {
         let (article, desc) = cx.tcx.article_and_description(it.def_id.to_def_id());
 
         let attrs = cx.tcx.hir().attrs(it.hir_id());
-        self.check_missing_docs_attrs(cx, attrs, it.span, article, desc);
+        if !is_from_proc_macro(cx, it) {
+            self.check_missing_docs_attrs(cx, attrs, it.span, article, desc);
+        }
     }
 
     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx hir::TraitItem<'_>) {
         let (article, desc) = cx.tcx.article_and_description(trait_item.def_id.to_def_id());
 
         let attrs = cx.tcx.hir().attrs(trait_item.hir_id());
-        self.check_missing_docs_attrs(cx, attrs, trait_item.span, article, desc);
+        if !is_from_proc_macro(cx, trait_item) {
+            self.check_missing_docs_attrs(cx, attrs, trait_item.span, article, desc);
+        }
     }
 
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) {
         // If the method is an impl for a trait, don't doc.
-        match cx.tcx.associated_item(impl_item.def_id).container {
-            ty::TraitContainer(_) => return,
-            ty::ImplContainer(cid) => {
-                if cx.tcx.impl_trait_ref(cid).is_some() {
-                    return;
-                }
-            },
+        if let Some(cid) = cx.tcx.associated_item(impl_item.def_id).impl_container(cx.tcx) {
+            if cx.tcx.impl_trait_ref(cid).is_some() {
+                return;
+            }
+        } else {
+            return;
         }
 
         let (article, desc) = cx.tcx.article_and_description(impl_item.def_id.to_def_id());
         let attrs = cx.tcx.hir().attrs(impl_item.hir_id());
-        self.check_missing_docs_attrs(cx, attrs, impl_item.span, article, desc);
+        if !is_from_proc_macro(cx, impl_item) {
+            self.check_missing_docs_attrs(cx, attrs, impl_item.span, article, desc);
+        }
     }
 
     fn check_field_def(&mut self, cx: &LateContext<'tcx>, sf: &'tcx hir::FieldDef<'_>) {
         if !sf.is_positional() {
             let attrs = cx.tcx.hir().attrs(sf.hir_id);
-            self.check_missing_docs_attrs(cx, attrs, sf.span, "a", "struct field");
+            if !is_from_proc_macro(cx, sf) {
+                self.check_missing_docs_attrs(cx, attrs, sf.span, "a", "struct field");
+            }
         }
     }
 
     fn check_variant(&mut self, cx: &LateContext<'tcx>, v: &'tcx hir::Variant<'_>) {
         let attrs = cx.tcx.hir().attrs(v.id);
-        self.check_missing_docs_attrs(cx, attrs, v.span, "a", "variant");
+        if !is_from_proc_macro(cx, v) {
+            self.check_missing_docs_attrs(cx, attrs, v.span, "a", "variant");
+        }
     }
 }
index 0d95329918984c68a74d541042995ff1a94ec28b..07bc2ca5d3cd2fa263893adde7f24e4cb0ef640b 100644 (file)
@@ -105,7 +105,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) {
                     match tit_.kind {
                         hir::TraitItemKind::Const(..) | hir::TraitItemKind::Type(..) => {},
                         hir::TraitItemKind::Fn(..) => {
-                            if tit.defaultness.has_value() {
+                            if cx.tcx.impl_defaultness(tit.id.def_id).has_value() {
                                 // trait method with default body needs inline in case
                                 // an impl is not provided
                                 let desc = "a default trait method";
@@ -151,9 +151,11 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::Impl
             hir::ImplItemKind::Const(..) | hir::ImplItemKind::TyAlias(_) => return,
         };
 
-        let trait_def_id = match cx.tcx.associated_item(impl_item.def_id).container {
-            TraitContainer(cid) => Some(cid),
-            ImplContainer(cid) => cx.tcx.impl_trait_ref(cid).map(|t| t.def_id),
+        let assoc_item = cx.tcx.associated_item(impl_item.def_id);
+        let container_id = assoc_item.container_id(cx.tcx);
+        let trait_def_id = match assoc_item.container {
+            TraitContainer => Some(container_id),
+            ImplContainer => cx.tcx.impl_trait_ref(container_id).map(|t| t.def_id),
         };
 
         if let Some(trait_def_id) = trait_def_id {
index 3f5286ba097b5970993d6f7027b94c512a556041..d9ee031c9f9756ffe11968f79499cd56b0277bca 100644 (file)
@@ -37,9 +37,9 @@
 impl EarlyLintPass for OptionEnvUnwrap {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
         if_chain! {
-            if let ExprKind::MethodCall(path_segment, args, _) = &expr.kind;
+            if let ExprKind::MethodCall(path_segment, receiver, _, _) = &expr.kind;
             if matches!(path_segment.ident.name, sym::expect | sym::unwrap);
-            if let ExprKind::Call(caller, _) = &args[0].kind;
+            if let ExprKind::Call(caller, _) = &receiver.kind;
             if is_direct_expn_of(caller.span, "option_env").is_some();
             then {
                 span_lint_and_help(
diff --git a/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs b/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs
new file mode 100644 (file)
index 0000000..eee7642
--- /dev/null
@@ -0,0 +1,104 @@
+use clippy_utils::{
+    diagnostics::span_lint_and_sugg, is_lang_ctor, peel_hir_expr_refs, peel_ref_operators, sugg,
+    ty::is_type_diagnostic_item,
+};
+use rustc_errors::Applicability;
+use rustc_hir::{BinOpKind, Expr, ExprKind, LangItem};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
+
+declare_clippy_lint! {
+    /// ### What it does
+    ///
+    /// Checks for binary comparisons to a literal `Option::None`.
+    ///
+    /// ### Why is this bad?
+    ///
+    /// A programmer checking if some `foo` is `None` via a comparison `foo == None`
+    /// is usually inspired from other programming languages (e.g. `foo is None`
+    /// in Python).
+    /// Checking if a value of type `Option<T>` is (not) equal to `None` in that
+    /// way relies on `T: PartialEq` to do the comparison, which is unneeded.
+    ///
+    /// ### Example
+    /// ```rust
+    /// fn foo(f: Option<u32>) -> &'static str {
+    ///     if f != None { "yay" } else { "nay" }
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// fn foo(f: Option<u32>) -> &'static str {
+    ///     if f.is_some() { "yay" } else { "nay" }
+    /// }
+    /// ```
+    #[clippy::version = "1.64.0"]
+    pub PARTIALEQ_TO_NONE,
+    style,
+    "Binary comparison to `Option<T>::None` relies on `T: PartialEq`, which is unneeded"
+}
+declare_lint_pass!(PartialeqToNone => [PARTIALEQ_TO_NONE]);
+
+impl<'tcx> LateLintPass<'tcx> for PartialeqToNone {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
+        // Skip expanded code, as we have no control over it anyway...
+        if e.span.from_expansion() {
+            return;
+        }
+
+        // If the expression is of type `Option`
+        let is_ty_option =
+            |expr: &Expr<'_>| is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr).peel_refs(), sym::Option);
+
+        // If the expression is a literal `Option::None`
+        let is_none_ctor = |expr: &Expr<'_>| {
+            matches!(&peel_hir_expr_refs(expr).0.kind,
+            ExprKind::Path(p) if is_lang_ctor(cx, p, LangItem::OptionNone))
+        };
+
+        let mut applicability = Applicability::MachineApplicable;
+
+        if let ExprKind::Binary(op, left_side, right_side) = e.kind {
+            // All other comparisons (e.g. `>= None`) have special meaning wrt T
+            let is_eq = match op.node {
+                BinOpKind::Eq => true,
+                BinOpKind::Ne => false,
+                _ => return,
+            };
+
+            // We are only interested in comparisons between `Option` and a literal `Option::None`
+            let scrutinee = match (
+                is_none_ctor(left_side) && is_ty_option(right_side),
+                is_none_ctor(right_side) && is_ty_option(left_side),
+            ) {
+                (true, false) => right_side,
+                (false, true) => left_side,
+                _ => return,
+            };
+
+            // Peel away refs/derefs (as long as we don't cross manual deref impls), as
+            // autoref/autoderef will take care of those
+            let sugg = format!(
+                "{}.{}",
+                sugg::Sugg::hir_with_applicability(cx, peel_ref_operators(cx, scrutinee), "..", &mut applicability)
+                    .maybe_par(),
+                if is_eq { "is_none()" } else { "is_some()" }
+            );
+
+            span_lint_and_sugg(
+                cx,
+                PARTIALEQ_TO_NONE,
+                e.span,
+                "binary comparison to literal `Option::None`",
+                if is_eq {
+                    "use `Option::is_none()` instead"
+                } else {
+                    "use `Option::is_some()` instead"
+                },
+                sugg,
+                applicability,
+            );
+        }
+    }
+}
index 3f940ce61c03e2c935d9870745384caa79aaa208..bc6a918f7035544ace250e7516c78731b1edd98e 100644 (file)
 impl<'tcx> LateLintPass<'tcx> for PathBufPushOverwrite {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if_chain! {
-            if let ExprKind::MethodCall(path, args, _) = expr.kind;
+            if let ExprKind::MethodCall(path, [recv, get_index_arg], _) = expr.kind;
             if path.ident.name == sym!(push);
-            if args.len() == 2;
-            if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]).peel_refs(), sym::PathBuf);
-            if let Some(get_index_arg) = args.get(1);
+            if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv).peel_refs(), sym::PathBuf);
             if let ExprKind::Lit(ref lit) = get_index_arg.kind;
             if let LitKind::Str(ref path_lit, _) = lit.node;
             if let pushed_path = Path::new(path_lit.as_str());
index cc0533c9f5d1aa5b0abfb43e5050b42605f34265..e6e3ad05ad70abbee15e673653f9b076a43affff 100644 (file)
@@ -109,12 +109,12 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
             let mut arg = operand;
 
             let mut all_odd = true;
-            while let ExprKind::MethodCall(path_segment, args, _) = &arg.kind {
+            while let ExprKind::MethodCall(path_segment, receiver, _, _) = &arg.kind {
                 let path_segment_str = path_segment.ident.name.as_str();
                 all_odd &= ALLOWED_ODD_FUNCTIONS
                     .iter()
                     .any(|odd_function| **odd_function == *path_segment_str);
-                arg = args.first().expect("A method always has a receiver.");
+                arg = receiver;
             }
 
             if_chain! {
index fd0a53839e6eaa2f7e6c3f9955711bfeb94834bc..964a057f00d32e5c1da41c7a4d1b7a3525710f0c 100644 (file)
@@ -86,8 +86,7 @@ fn check_is_none_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Ex
     if_chain! {
         if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr);
         if !is_else_clause(cx.tcx, expr);
-        if let ExprKind::MethodCall(segment, args, _) = &cond.kind;
-        if let Some(caller) = args.get(0);
+        if let ExprKind::MethodCall(segment, [caller, ..], _) = &cond.kind;
         let caller_ty = cx.typeck_results().expr_ty(caller);
         let if_block = IfBlockType::IfIs(caller, caller_ty, segment.ident.name, then, r#else);
         if is_early_return(sym::Option, cx, &if_block) || is_early_return(sym::Result, cx, &if_block);
index 547d4da818727016098b8c7865ab9ef2488cf690..fbf842c339e4906b3fff22a5e3a2d608bc40e047 100644 (file)
@@ -385,24 +385,24 @@ fn check_range_zip_with_len(cx: &LateContext<'_>, path: &PathSegment<'_>, args:
         if path.ident.as_str() == "zip";
         if let [iter, zip_arg] = args;
         // `.iter()` call
-        if let ExprKind::MethodCall(iter_path, iter_args, _) = iter.kind;
+        if let ExprKind::MethodCall(iter_path, [iter_caller, ..], _) = iter.kind;
         if iter_path.ident.name == sym::iter;
         // range expression in `.zip()` call: `0..x.len()`
         if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::Range::hir(zip_arg);
         if is_integer_const(cx, start, 0);
         // `.len()` call
-        if let ExprKind::MethodCall(len_path, len_args, _) = end.kind;
-        if len_path.ident.name == sym::len && len_args.len() == 1;
+        if let ExprKind::MethodCall(len_path, [len_caller], _) = end.kind;
+        if len_path.ident.name == sym::len;
         // `.iter()` and `.len()` called on same `Path`
-        if let ExprKind::Path(QPath::Resolved(_, iter_path)) = iter_args[0].kind;
-        if let ExprKind::Path(QPath::Resolved(_, len_path)) = len_args[0].kind;
-        if SpanlessEq::new(cx).eq_path_segments(&iter_path.segments, &len_path.segments);
+        if let ExprKind::Path(QPath::Resolved(_, iter_path)) = iter_caller.kind;
+        if let ExprKind::Path(QPath::Resolved(_, len_path)) = len_caller.kind;
+        if SpanlessEq::new(cx).eq_path_segments(iter_path.segments, len_path.segments);
         then {
             span_lint(cx,
                 RANGE_ZIP_WITH_LEN,
                 span,
                 &format!("it is more idiomatic to use `{}.iter().enumerate()`",
-                    snippet(cx, iter_args[0].span, "_"))
+                    snippet(cx, iter_caller.span, "_"))
             );
         }
     }
index f5a93cebab8ca65707c1151a85346c34081a071c..74eea6de4bbeff43d30c92d83a8553c73d6cfab9 100644 (file)
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
-use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::sugg::Sugg;
 use if_chain::if_chain;
 use rustc_ast::ast;
 use rustc_ast::visit as ast_visit;
@@ -69,7 +69,7 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
         if_chain! {
             if let ast::ExprKind::Call(ref paren, _) = expr.kind;
             if let ast::ExprKind::Paren(ref closure) = paren.kind;
-            if let ast::ExprKind::Closure(_, _, _, _, ref decl, ref block, _) = closure.kind;
+            if let ast::ExprKind::Closure(_, _, ref r#async, _, ref decl, ref block, _) = closure.kind;
             then {
                 let mut visitor = ReturnVisitor::new();
                 visitor.visit_expr(block);
@@ -81,10 +81,19 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
                         "try not to call a closure in the expression where it is declared",
                         |diag| {
                             if decl.inputs.is_empty() {
-                                let mut app = Applicability::MachineApplicable;
-                                let hint =
-                                    snippet_with_applicability(cx, block.span, "..", &mut app).into_owned();
-                                diag.span_suggestion(expr.span, "try doing something like", hint, app);
+                                let app = Applicability::MachineApplicable;
+                                let mut hint = Sugg::ast(cx, block, "..");
+
+                                if r#async.is_async() {
+                                    // `async x` is a syntax error, so it becomes `async { x }`
+                                    if !matches!(block.kind, ast::ExprKind::Block(_, _)) {
+                                        hint = hint.blockify();
+                                    }
+
+                                    hint = hint.asyncify();
+                                }
+
+                                diag.span_suggestion(expr.span, "try doing something like", hint.to_string(), app);
                             }
                         },
                     );
index f9a9b0691935ad82cc3b817f5d276524a18efd41..6bcae0da8f48f1bb0333841620147ec445a56ca7 100644 (file)
 impl<'tcx> LateLintPass<'tcx> for Regex {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if_chain! {
-            if let ExprKind::Call(fun, args) = expr.kind;
+            if let ExprKind::Call(fun, [arg]) = expr.kind;
             if let ExprKind::Path(ref qpath) = fun.kind;
-            if args.len() == 1;
             if let Some(def_id) = cx.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) {
-                    check_regex(cx, &args[0], true);
+                    check_regex(cx, arg, true);
                 } else if match_def_path(cx, def_id, &paths::REGEX_BYTES_NEW) ||
                    match_def_path(cx, def_id, &paths::REGEX_BYTES_BUILDER_NEW) {
-                    check_regex(cx, &args[0], false);
+                    check_regex(cx, arg, false);
                 } else if match_def_path(cx, def_id, &paths::REGEX_SET_NEW) {
-                    check_set(cx, &args[0], true);
+                    check_set(cx, arg, true);
                 } else if match_def_path(cx, def_id, &paths::REGEX_BYTES_SET_NEW) {
-                    check_set(cx, &args[0], false);
+                    check_set(cx, arg, false);
                 }
             }
         }
index ba03ef93721186296021cb596a2992264072e4ee..6bea6dc0773d5c2fef2d45e8dc300695ffe7de67 100644 (file)
@@ -2,6 +2,7 @@
 
 #[rustfmt::skip]
 pub static RENAMED_LINTS: &[(&str, &str)] = &[
+    ("clippy::blacklisted_name", "clippy::disallowed_names"),
     ("clippy::block_in_if_condition_expr", "clippy::blocks_in_if_conditions"),
     ("clippy::block_in_if_condition_stmt", "clippy::blocks_in_if_conditions"),
     ("clippy::box_vec", "clippy::box_collection"),
@@ -14,6 +15,7 @@
     ("clippy::for_loop_over_result", "clippy::for_loops_over_fallibles"),
     ("clippy::identity_conversion", "clippy::useless_conversion"),
     ("clippy::if_let_some_result", "clippy::match_result_ok"),
+    ("clippy::logic_bug", "clippy::overly_complex_bool_expr"),
     ("clippy::new_without_default_derive", "clippy::new_without_default"),
     ("clippy::option_and_then_some", "clippy::bind_instead_of_map"),
     ("clippy::option_expect_used", "clippy::expect_used"),
index 2c8aa17e80dbdeb3fa5c3a33c91fce560f450e7d..b59a25e3a40047eb024a24547ba458488d910ce0 100644 (file)
@@ -233,15 +233,10 @@ fn search_slow_resize_filling(&mut self, expr: &'tcx Expr<'_>) {
     /// Returns `true` if give expression is `repeat(0).take(...)`
     fn is_repeat_take(&self, expr: &Expr<'_>) -> bool {
         if_chain! {
-            if let ExprKind::MethodCall(take_path, take_args, _) = expr.kind;
+            if let ExprKind::MethodCall(take_path, [recv, len_arg, ..], _) = expr.kind;
             if take_path.ident.name == sym!(take);
-
             // Check that take is applied to `repeat(0)`
-            if let Some(repeat_expr) = take_args.get(0);
-            if self.is_repeat_zero(repeat_expr);
-
-            if let Some(len_arg) = take_args.get(1);
-
+            if self.is_repeat_zero(recv);
             then {
                 // Check that len expression is equals to `with_capacity` expression
                 if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr) {
index a6c685df721d6fac310117306cb98cd2b46f9a96..6d54935f81ab26e29d03b3eac6e1fc33e2c88ea9 100644 (file)
@@ -97,12 +97,11 @@ struct LintDetection {
 
 fn detect_stable_sort_primitive(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<LintDetection> {
     if_chain! {
-        if let ExprKind::MethodCall(method_name, args, _) = &expr.kind;
-        if let Some(slice) = &args.get(0);
+        if let ExprKind::MethodCall(method_name, [slice, args @ ..], _) = &expr.kind;
         if let Some(method) = SortingKind::from_stable_name(method_name.ident.name.as_str());
         if let Some(slice_type) = is_slice_of_primitives(cx, slice);
         then {
-            let args_str = args.iter().skip(1).map(|arg| Sugg::hir(cx, arg, "..").to_string()).collect::<Vec<String>>().join(", ");
+            let args_str = args.iter().map(|arg| Sugg::hir(cx, arg, "..").to_string()).collect::<Vec<String>>().join(", ");
             Some(LintDetection { slice_name: Sugg::hir(cx, slice, "..").to_string(), method, method_args: args_str, slice_type })
         } else {
             None
index fe8859905953ff0fb35b870e71e1bfab8eb493be..5d36f0f5ff8bc91cde11f88026437c7ceb826f21 100644 (file)
@@ -595,7 +595,7 @@ fn ident_difference_expr_with_base_location(
         | (Unary(_, _), Unary(_, _))
         | (Binary(_, _, _), Binary(_, _, _))
         | (Tup(_), Tup(_))
-        | (MethodCall(_, _, _), MethodCall(_, _, _))
+        | (MethodCall(_, _, _, _), MethodCall(_, _, _, _))
         | (Call(_, _), Call(_, _))
         | (ConstBlock(_), ConstBlock(_))
         | (Array(_), Array(_))
index 04f16fd2161c51a0cdbed5e35419540052e912c5..d2e675a783eaaf382517370b34526011b2cf2923 100644 (file)
@@ -345,7 +345,7 @@ fn text_has_safety_comment(src: &str, line_starts: &[BytePos], offset: usize) ->
         if line.starts_with("/*") {
             let src = src[line_start..line_starts.last().unwrap().to_usize() - offset].trim_start();
             let mut tokens = tokenize(src);
-            return src[..tokens.next().unwrap().len]
+            return src[..tokens.next().unwrap().len as usize]
                 .to_ascii_uppercase()
                 .contains("SAFETY:")
                 && tokens.all(|t| t.kind == TokenKind::Whitespace);
index 6aa86a57c9bdf58b2ccb07cd804c5a1d292da1b6..546242ebd9a474d1c27d8b39ad986472814f71d7 100644 (file)
@@ -103,7 +103,7 @@ fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
         let_unit_value::check(cx, local);
     }
 
-    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         unit_cmp::check(cx, expr);
         unit_arg::check(cx, expr);
     }
index 97d92f10e1cb2b039e13b6b646be14c4370e1343..16da2f11b81a6a6650b07d9dde5062461720c5b5 100644 (file)
@@ -1,4 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::is_from_proc_macro;
 use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
@@ -7,7 +8,7 @@
 
 use super::{utils, UNIT_ARG};
 
-pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
     if expr.span.from_expansion() {
         return;
     }
@@ -44,7 +45,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
                     }
                 })
                 .collect::<Vec<_>>();
-            if !args_to_recover.is_empty() {
+            if !args_to_recover.is_empty() && !is_from_proc_macro(cx, expr) {
                 lint_unit_args(cx, expr, &args_to_recover);
             }
         },
index 306afe441484755d025289dee2a7992329ab2d9d..e1ec357838dbd88846e97ef43c602d33500ebe85 100644 (file)
 declare_lint_pass!(UnusedRounding => [UNUSED_ROUNDING]);
 
 fn is_useless_rounding(expr: &Expr) -> Option<(&str, String)> {
-    if let ExprKind::MethodCall(name_ident, args, _) = &expr.kind
+    if let ExprKind::MethodCall(name_ident, receiver, _, _) = &expr.kind
         && let method_name = name_ident.ident.name.as_str()
         && (method_name == "ceil" || method_name == "round" || method_name == "floor")
-        && !args.is_empty()
-        && let ExprKind::Lit(spanned) = &args[0].kind
+        && let ExprKind::Lit(spanned) = &receiver.kind
         && let LitKind::Float(symbol, ty) = spanned.kind {
             let f = symbol.as_str().parse::<f64>().unwrap();
             let f_str = symbol.to_string() + if let LitFloatType::Suffixed(ty) = ty {
index 52585e59566c8128a6df546b3c00871f096f545f..cd1d90e860b9fe865baef8a27bcbeb3078b7b0ec 100644 (file)
@@ -89,7 +89,7 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
         }
     }
 
-    fn check_poly_trait_ref(&mut self, cx: &EarlyContext<'_>, poly: &ast::PolyTraitRef, _: &ast::TraitBoundModifier) {
+    fn check_poly_trait_ref(&mut self, cx: &EarlyContext<'_>, poly: &ast::PolyTraitRef) {
         let segments = &poly.trait_ref.path.segments;
 
         if_chain! {
index fe29bf29d0caf9c7b3bf9f1f37cfa4693e5bdd4b..b6738e2891d3e914b2a31f655b5d2402c6a49efb 100644 (file)
@@ -59,17 +59,17 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                     ExprKind::Ret(Some(e)) | ExprKind::Break(_, Some(e)) => e,
                     _ => return,
                 };
-                if let ExprKind::Call(_, args) = e.kind {
-                    self.try_desugar_arm.push(args[0].hir_id);
+                if let ExprKind::Call(_, [arg, ..]) = e.kind {
+                    self.try_desugar_arm.push(arg.hir_id);
                 }
             },
 
-            ExprKind::MethodCall(name, .., args, _) => {
+            ExprKind::MethodCall(name, .., [recv, ..], _) => {
                 if is_trait_method(cx, e, sym::Into) && name.ident.as_str() == "into" {
                     let a = cx.typeck_results().expr_ty(e);
-                    let b = cx.typeck_results().expr_ty(&args[0]);
+                    let b = cx.typeck_results().expr_ty(recv);
                     if same_type_and_consts(a, b) {
-                        let sugg = snippet_with_macro_callsite(cx, args[0].span, "<expr>").to_string();
+                        let sugg = snippet_with_macro_callsite(cx, recv.span, "<expr>").to_string();
                         span_lint_and_sugg(
                             cx,
                             USELESS_CONVERSION,
@@ -90,9 +90,9 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                         }
                     }
                     let a = cx.typeck_results().expr_ty(e);
-                    let b = cx.typeck_results().expr_ty(&args[0]);
+                    let b = cx.typeck_results().expr_ty(recv);
                     if same_type_and_consts(a, b) {
-                        let sugg = snippet(cx, args[0].span, "<expr>").into_owned();
+                        let sugg = snippet(cx, recv.span, "<expr>").into_owned();
                         span_lint_and_sugg(
                             cx,
                             USELESS_CONVERSION,
@@ -107,7 +107,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                 if_chain! {
                     if is_trait_method(cx, e, sym::TryInto) && name.ident.name == sym::try_into;
                     let a = cx.typeck_results().expr_ty(e);
-                    let b = cx.typeck_results().expr_ty(&args[0]);
+                    let b = cx.typeck_results().expr_ty(recv);
                     if is_type_diagnostic_item(cx, a, sym::Result);
                     if let ty::Adt(_, substs) = a.kind();
                     if let Some(a_type) = substs.types().next();
@@ -126,14 +126,13 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                 }
             },
 
-            ExprKind::Call(path, args) => {
+            ExprKind::Call(path, [arg]) => {
                 if_chain! {
-                    if args.len() == 1;
                     if let ExprKind::Path(ref qpath) = path.kind;
                     if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id();
                     then {
                         let a = cx.typeck_results().expr_ty(e);
-                        let b = cx.typeck_results().expr_ty(&args[0]);
+                        let b = cx.typeck_results().expr_ty(arg);
                         if_chain! {
                             if match_def_path(cx, def_id, &paths::TRY_FROM);
                             if is_type_diagnostic_item(cx, a, sym::Result);
@@ -159,7 +158,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                             if same_type_and_consts(a, b);
 
                             then {
-                                let sugg = Sugg::hir_with_macro_callsite(cx, &args[0], "<expr>").maybe_par();
+                                let sugg = Sugg::hir_with_macro_callsite(cx, arg, "<expr>").maybe_par();
                                 let sugg_msg =
                                     format!("consider removing `{}()`", snippet(cx, path.span, "From::from"));
                                 span_lint_and_sugg(
index 6e033b3be2d87a60e5d6e21f913e09ac79eef269..3faae9ac0d2b2af6232568015f6874955174c811 100644 (file)
@@ -30,7 +30,7 @@
     "MinGW",
     "CamelCase",
 ];
-const DEFAULT_BLACKLISTED_NAMES: &[&str] = &["foo", "baz", "quux"];
+const DEFAULT_DISALLOWED_NAMES: &[&str] = &["foo", "baz", "quux"];
 
 /// Holds information used by `MISSING_ENFORCED_IMPORT_RENAMES` lint.
 #[derive(Clone, Debug, Deserialize)]
@@ -68,6 +68,7 @@ pub enum DisallowedType {
 pub struct TryConf {
     pub conf: Conf,
     pub errors: Vec<Box<dyn Error>>,
+    pub warnings: Vec<Box<dyn Error>>,
 }
 
 impl TryConf {
@@ -75,6 +76,7 @@ fn from_error(error: impl Error + 'static) -> Self {
         Self {
             conf: Conf::default(),
             errors: vec![Box::new(error)],
+            warnings: vec![],
         }
     }
 }
@@ -90,14 +92,14 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 
 impl Error for ConfError {}
 
-fn conf_error(s: String) -> Box<dyn Error> {
-    Box::new(ConfError(s))
+fn conf_error(s: impl Into<String>) -> Box<dyn Error> {
+    Box::new(ConfError(s.into()))
 }
 
 macro_rules! define_Conf {
     ($(
         $(#[doc = $doc:literal])+
-        $(#[conf_deprecated($dep:literal)])?
+        $(#[conf_deprecated($dep:literal, $new_conf:ident)])?
         ($name:ident: $ty:ty = $default:expr),
     )*) => {
         /// Clippy lint configuration
@@ -137,17 +139,29 @@ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
 
             fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error> where V: MapAccess<'de> {
                 let mut errors = Vec::new();
+                let mut warnings = Vec::new();
                 $(let mut $name = None;)*
                 // could get `Field` here directly, but get `str` first for diagnostics
                 while let Some(name) = map.next_key::<&str>()? {
                     match Field::deserialize(name.into_deserializer())? {
                         $(Field::$name => {
-                            $(errors.push(conf_error(format!("deprecated field `{}`. {}", name, $dep)));)?
+                            $(warnings.push(conf_error(format!("deprecated field `{}`. {}", name, $dep)));)?
                             match map.next_value() {
                                 Err(e) => errors.push(conf_error(e.to_string())),
                                 Ok(value) => match $name {
                                     Some(_) => errors.push(conf_error(format!("duplicate field `{}`", name))),
-                                    None => $name = Some(value),
+                                    None => {
+                                        $name = Some(value);
+                                        // $new_conf is the same as one of the defined `$name`s, so
+                                        // this variable is defined in line 2 of this function.
+                                        $(match $new_conf {
+                                            Some(_) => errors.push(conf_error(concat!(
+                                                "duplicate field `", stringify!($new_conf),
+                                                "` (provided as `", stringify!($name), "`)"
+                                            ))),
+                                            None => $new_conf = $name.clone(),
+                                        })?
+                                    },
                                 }
                             }
                         })*
@@ -156,7 +170,7 @@ fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error> where V: MapA
                     }
                 }
                 let conf = Conf { $($name: $name.unwrap_or_else(defaults::$name),)* };
-                Ok(TryConf { conf, errors })
+                Ok(TryConf { conf, errors, warnings })
             }
         }
 
@@ -203,12 +217,11 @@ pub(crate) fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
     ///
     /// The minimum rust version that the project supports
     (msrv: Option<String> = None),
-    /// Lint: BLACKLISTED_NAME.
+    /// DEPRECATED LINT: BLACKLISTED_NAME.
     ///
-    /// The list of blacklisted names to lint about. NB: `bar` is not here since it has legitimate uses. The value
-    /// `".."` can be used as part of the list to indicate, that the configured values should be appended to the
-    /// default configuration of Clippy. By default any configuraction will replace the default value.
-    (blacklisted_names: Vec<String> = super::DEFAULT_BLACKLISTED_NAMES.iter().map(ToString::to_string).collect()),
+    /// Use the Disallowed Names lint instead
+    #[conf_deprecated("Please use `disallowed-names` instead", disallowed_names)]
+    (blacklisted_names: Vec<String> = Vec::new()),
     /// Lint: COGNITIVE_COMPLEXITY.
     ///
     /// The maximum cognitive complexity a function can have
@@ -216,8 +229,14 @@ pub(crate) fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
     /// DEPRECATED LINT: CYCLOMATIC_COMPLEXITY.
     ///
     /// Use the Cognitive Complexity lint instead.
-    #[conf_deprecated("Please use `cognitive-complexity-threshold` instead")]
-    (cyclomatic_complexity_threshold: Option<u64> = None),
+    #[conf_deprecated("Please use `cognitive-complexity-threshold` instead", cognitive_complexity_threshold)]
+    (cyclomatic_complexity_threshold: u64 = 25),
+    /// Lint: DISALLOWED_NAMES.
+    ///
+    /// The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value
+    /// `".."` can be used as part of the list to indicate, that the configured values should be appended to the
+    /// default configuration of Clippy. By default any configuration will replace the default value.
+    (disallowed_names: Vec<String> = super::DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect()),
     /// Lint: DOC_MARKDOWN.
     ///
     /// The list of words this lint should not consider as identifiers needing ticks. The value
@@ -420,7 +439,7 @@ pub fn read(path: &Path) -> TryConf {
     match toml::from_str::<TryConf>(&content) {
         Ok(mut conf) => {
             extend_vec_if_indicator_present(&mut conf.conf.doc_valid_idents, DEFAULT_DOC_VALID_IDENTS);
-            extend_vec_if_indicator_present(&mut conf.conf.blacklisted_names, DEFAULT_BLACKLISTED_NAMES);
+            extend_vec_if_indicator_present(&mut conf.conf.disallowed_names, DEFAULT_DISALLOWED_NAMES);
 
             conf
         },
index b309653291b11ce58d3d1d3a45eb696705490cbd..5dcacd604be45f6b0a4c4844e05ece2e13287198 100644 (file)
@@ -496,12 +496,14 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
                     cx,
                 };
                 let body_id = cx.tcx.hir().body_owned_by(
-                    impl_item_refs
-                        .iter()
-                        .find(|iiref| iiref.ident.as_str() == "get_lints")
-                        .expect("LintPass needs to implement get_lints")
-                        .id
-                        .hir_id(),
+                    cx.tcx.hir().local_def_id(
+                        impl_item_refs
+                            .iter()
+                            .find(|iiref| iiref.ident.as_str() == "get_lints")
+                            .expect("LintPass needs to implement get_lints")
+                            .id
+                            .hir_id(),
+                    ),
                 );
                 collector.visit_expr(&cx.tcx.hir().body(body_id).value);
             }
@@ -569,7 +571,7 @@ fn check_invalid_clippy_version_attribute(cx: &LateContext<'_>, item: &'_ Item<'
                 item.span,
                 "this item has an invalid `clippy::version` attribute",
                 None,
-                "please use a valid sematic version, see `doc/adding_lints.md`",
+                "please use a valid semantic version, see `doc/adding_lints.md`",
             );
         }
     } else {
index 92934c16d4b406a252e121355671e60dfc425dbe..92cf42c7ad43f0459fe10051fd2ea4baac6109eb 100644 (file)
@@ -619,7 +619,7 @@ fn check_item(&mut self, cx: &LateContext<'hir>, item: &'hir Item<'_>) {
             if_chain! {
                 // item validation
                 if is_lint_ref_type(cx, ty);
-                // blacklist check
+                // disallow check
                 let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase();
                 if !BLACK_LISTED_LINTS.contains(&lint_name.as_str());
                 // metadata extraction
@@ -644,7 +644,7 @@ fn check_item(&mut self, cx: &LateContext<'hir>, item: &'hir Item<'_>) {
 
             if_chain! {
                 if is_deprecated_lint(cx, ty);
-                // blacklist check
+                // disallow check
                 let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase();
                 if !BLACK_LISTED_LINTS.contains(&lint_name.as_str());
                 // Metadata the little we can get from a deprecated lint
index 8e2ddd225fdb3bd239c2e73288e6a5a794be0bca..afd0077a658049160feb972d23c7a0391769602c 100644 (file)
@@ -61,10 +61,10 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
 
 fn is_file_read_to_end<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
     if_chain! {
-        if let ExprKind::MethodCall(method_name, exprs, _) = expr.kind;
+        if let ExprKind::MethodCall(method_name, [recv, ..], _) = expr.kind;
         if method_name.ident.as_str() == "read_to_end";
-        if let ExprKind::Path(QPath::Resolved(None, _)) = &exprs[0].kind;
-        let ty = cx.typeck_results().expr_ty(&exprs[0]);
+        if let ExprKind::Path(QPath::Resolved(None, _)) = &recv.kind;
+        let ty = cx.typeck_results().expr_ty(recv);
         if match_type(cx, ty, &paths::FILE);
         then {
             return true
index 3a99d1b417fee1c96373112e6e35d2143ba570f3..32718200c0b3a037a2793855e81d0f835bbddcab 100644 (file)
@@ -441,7 +441,7 @@ fn push(&mut self, arg: rustc_parse_format::Argument<'_>, span: Span) {
         };
 
         match arg.position {
-            ArgumentIs(n, _) | ArgumentImplicitlyIs(n) => {
+            ArgumentIs(n) | ArgumentImplicitlyIs(n) => {
                 if self.unnamed.len() <= n {
                     // Use a dummy span to mark all unseen arguments.
                     self.unnamed.resize_with(n, || vec![DUMMY_SP]);
@@ -462,7 +462,7 @@ fn push(&mut self, arg: rustc_parse_format::Argument<'_>, span: Span) {
                     }
                 }
             },
-            ArgumentNamed(n, _) => {
+            ArgumentNamed(n) => {
                 let n = Symbol::intern(n);
                 if let Some(x) = self.named.iter_mut().find(|x| x.0 == n) {
                     match x.1.as_slice() {
index bb443bdc1168fc97ee0b363b9908c0cd1c423aac..a688050f63a6ad659603b248aa78ca785edcf093 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "clippy_utils"
-version = "0.1.64"
+version = "0.1.65"
 edition = "2021"
 publish = false
 
index b226026323be835a7f5be3231f8fe70f491bdc80..9f74729bdfa18487463011020784ac9c8873bbc7 100644 (file)
@@ -147,7 +147,9 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
         (Array(l), Array(r)) | (Tup(l), Tup(r)) => over(l, r, |l, r| eq_expr(l, r)),
         (Repeat(le, ls), Repeat(re, rs)) => eq_expr(le, re) && eq_expr(&ls.value, &rs.value),
         (Call(lc, la), Call(rc, ra)) => eq_expr(lc, rc) && over(la, ra, |l, r| eq_expr(l, r)),
-        (MethodCall(lc, la, _), MethodCall(rc, ra, _)) => eq_path_seg(lc, rc) && over(la, ra, |l, r| eq_expr(l, r)),
+        (MethodCall(lc, ls, la, _), MethodCall(rc, rs, ra, _)) => {
+            eq_path_seg(lc, rc) && eq_expr(ls, rs) && over(la, ra, |l, r| eq_expr(l, r))
+        },
         (Binary(lo, ll, lr), Binary(ro, rl, rr)) => lo.node == ro.node && eq_expr(ll, rl) && eq_expr(lr, rr),
         (Unary(lo, l), Unary(ro, r)) => mem::discriminant(lo) == mem::discriminant(ro) && eq_expr(l, r),
         (Lit(l), Lit(r)) => l.kind == r.kind,
diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
new file mode 100644 (file)
index 0000000..8335ffa
--- /dev/null
@@ -0,0 +1,329 @@
+//! This module handles checking if the span given is from a proc-macro or not.
+//!
+//! Proc-macros are capable of setting the span of every token they output to a few possible spans.
+//! This includes spans we can detect easily as coming from a proc-macro (e.g. the call site
+//! or the def site), and spans we can't easily detect as such (e.g. the span of any token
+//! passed into the proc macro). This capability means proc-macros are capable of generating code
+//! with a span that looks like it was written by the user, but which should not be linted by clippy
+//! as it was generated by an external macro.
+//!
+//! That brings us to this module. The current approach is to determine a small bit of text which
+//! must exist at both the start and the end of an item (e.g. an expression or a path) assuming the
+//! code was written, and check if the span contains that text. Note this will only work correctly
+//! if the span is not from a `macro_rules` based macro.
+
+use rustc_ast::ast::{IntTy, LitIntType, LitKind, StrStyle, UintTy};
+use rustc_hir::{
+    intravisit::FnKind, Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, HirId,
+    Impl, ImplItem, ImplItemKind, IsAuto, Item, ItemKind, LoopSource, MatchSource, Node, QPath, TraitItem,
+    TraitItemKind, UnOp, UnsafeSource, Unsafety, Variant, VariantData, YieldSource,
+};
+use rustc_lint::{LateContext, LintContext};
+use rustc_middle::ty::TyCtxt;
+use rustc_session::Session;
+use rustc_span::{Span, Symbol};
+use rustc_target::spec::abi::Abi;
+
+/// The search pattern to look for. Used by `span_matches_pat`
+#[derive(Clone, Copy)]
+pub enum Pat {
+    /// A single string.
+    Str(&'static str),
+    /// Any of the given strings.
+    MultiStr(&'static [&'static str]),
+    /// The string representation of the symbol.
+    Sym(Symbol),
+    /// Any decimal or hexadecimal digit depending on the location.
+    Num,
+}
+
+/// Checks if the start and the end of the span's text matches the patterns. This will return false
+/// if the span crosses multiple files or if source is not available.
+fn span_matches_pat(sess: &Session, span: Span, start_pat: Pat, end_pat: Pat) -> bool {
+    let pos = sess.source_map().lookup_byte_offset(span.lo());
+    let Some(ref src) = pos.sf.src else {
+        return false;
+    };
+    let end = span.hi() - pos.sf.start_pos;
+    src.get(pos.pos.0 as usize..end.0 as usize).map_or(false, |s| {
+        // Spans can be wrapped in a mixture or parenthesis, whitespace, and trailing commas.
+        let start_str = s.trim_start_matches(|c: char| c.is_whitespace() || c == '(');
+        let end_str = s.trim_end_matches(|c: char| c.is_whitespace() || c == ')' || c == ',');
+        (match start_pat {
+            Pat::Str(text) => start_str.starts_with(text),
+            Pat::MultiStr(texts) => texts.iter().any(|s| start_str.starts_with(s)),
+            Pat::Sym(sym) => start_str.starts_with(sym.as_str()),
+            Pat::Num => start_str.as_bytes().first().map_or(false, u8::is_ascii_digit),
+        } && match end_pat {
+            Pat::Str(text) => end_str.ends_with(text),
+            Pat::MultiStr(texts) => texts.iter().any(|s| start_str.ends_with(s)),
+            Pat::Sym(sym) => end_str.ends_with(sym.as_str()),
+            Pat::Num => end_str.as_bytes().last().map_or(false, u8::is_ascii_hexdigit),
+        })
+    })
+}
+
+/// Get the search patterns to use for the given literal
+fn lit_search_pat(lit: &LitKind) -> (Pat, Pat) {
+    match lit {
+        LitKind::Str(_, StrStyle::Cooked) => (Pat::Str("\""), Pat::Str("\"")),
+        LitKind::Str(_, StrStyle::Raw(0)) => (Pat::Str("r"), Pat::Str("\"")),
+        LitKind::Str(_, StrStyle::Raw(_)) => (Pat::Str("r#"), Pat::Str("#")),
+        LitKind::ByteStr(_) => (Pat::Str("b\""), Pat::Str("\"")),
+        LitKind::Byte(_) => (Pat::Str("b'"), Pat::Str("'")),
+        LitKind::Char(_) => (Pat::Str("'"), Pat::Str("'")),
+        LitKind::Int(_, LitIntType::Signed(IntTy::Isize)) => (Pat::Num, Pat::Str("isize")),
+        LitKind::Int(_, LitIntType::Unsigned(UintTy::Usize)) => (Pat::Num, Pat::Str("usize")),
+        LitKind::Int(..) => (Pat::Num, Pat::Num),
+        LitKind::Float(..) => (Pat::Num, Pat::Str("")),
+        LitKind::Bool(true) => (Pat::Str("true"), Pat::Str("true")),
+        LitKind::Bool(false) => (Pat::Str("false"), Pat::Str("false")),
+        _ => (Pat::Str(""), Pat::Str("")),
+    }
+}
+
+/// Get the search patterns to use for the given path
+fn qpath_search_pat(path: &QPath<'_>) -> (Pat, Pat) {
+    match path {
+        QPath::Resolved(ty, path) => {
+            let start = if ty.is_some() {
+                Pat::Str("<")
+            } else {
+                path.segments
+                    .first()
+                    .map_or(Pat::Str(""), |seg| Pat::Sym(seg.ident.name))
+            };
+            let end = path.segments.last().map_or(Pat::Str(""), |seg| {
+                if seg.args.is_some() {
+                    Pat::Str(">")
+                } else {
+                    Pat::Sym(seg.ident.name)
+                }
+            });
+            (start, end)
+        },
+        QPath::TypeRelative(_, name) => (Pat::Str(""), Pat::Sym(name.ident.name)),
+        QPath::LangItem(..) => (Pat::Str(""), Pat::Str("")),
+    }
+}
+
+/// Get the search patterns to use for the given expression
+fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) {
+    match e.kind {
+        ExprKind::Box(e) => (Pat::Str("box"), expr_search_pat(tcx, e).1),
+        ExprKind::ConstBlock(_) => (Pat::Str("const"), Pat::Str("}")),
+        ExprKind::Tup([]) => (Pat::Str(")"), Pat::Str("(")),
+        ExprKind::Unary(UnOp::Deref, e) => (Pat::Str("*"), expr_search_pat(tcx, e).1),
+        ExprKind::Unary(UnOp::Not, e) => (Pat::Str("!"), expr_search_pat(tcx, e).1),
+        ExprKind::Unary(UnOp::Neg, e) => (Pat::Str("-"), expr_search_pat(tcx, e).1),
+        ExprKind::Lit(ref lit) => lit_search_pat(&lit.node),
+        ExprKind::Array(_) | ExprKind::Repeat(..) => (Pat::Str("["), Pat::Str("]")),
+        ExprKind::Call(e, []) | ExprKind::MethodCall(_, [e], _) => (expr_search_pat(tcx, e).0, Pat::Str("(")),
+        ExprKind::Call(first, [.., last])
+        | ExprKind::MethodCall(_, [first, .., last], _)
+        | ExprKind::Binary(_, first, last)
+        | ExprKind::Tup([first, .., last])
+        | ExprKind::Assign(first, last, _)
+        | ExprKind::AssignOp(_, first, last) => (expr_search_pat(tcx, first).0, expr_search_pat(tcx, last).1),
+        ExprKind::Tup([e]) | ExprKind::DropTemps(e) => expr_search_pat(tcx, e),
+        ExprKind::Cast(e, _) | ExprKind::Type(e, _) => (expr_search_pat(tcx, e).0, Pat::Str("")),
+        ExprKind::Let(let_expr) => (Pat::Str("let"), expr_search_pat(tcx, let_expr.init).1),
+        ExprKind::If(..) => (Pat::Str("if"), Pat::Str("}")),
+        ExprKind::Loop(_, Some(_), _, _) | ExprKind::Block(_, Some(_)) => (Pat::Str("'"), Pat::Str("}")),
+        ExprKind::Loop(_, None, LoopSource::Loop, _) => (Pat::Str("loop"), Pat::Str("}")),
+        ExprKind::Loop(_, None, LoopSource::While, _) => (Pat::Str("while"), Pat::Str("}")),
+        ExprKind::Loop(_, None, LoopSource::ForLoop, _) | ExprKind::Match(_, _, MatchSource::ForLoopDesugar) => {
+            (Pat::Str("for"), Pat::Str("}"))
+        },
+        ExprKind::Match(_, _, MatchSource::Normal) => (Pat::Str("match"), Pat::Str("}")),
+        ExprKind::Match(e, _, MatchSource::TryDesugar) => (expr_search_pat(tcx, e).0, Pat::Str("?")),
+        ExprKind::Match(e, _, MatchSource::AwaitDesugar) | ExprKind::Yield(e, YieldSource::Await { .. }) => {
+            (expr_search_pat(tcx, e).0, Pat::Str("await"))
+        },
+        ExprKind::Closure(&Closure { body, .. }) => (Pat::Str(""), expr_search_pat(tcx, &tcx.hir().body(body).value).1),
+        ExprKind::Block(
+            Block {
+                rules: BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided),
+                ..
+            },
+            None,
+        ) => (Pat::Str("unsafe"), Pat::Str("}")),
+        ExprKind::Block(_, None) => (Pat::Str("{"), Pat::Str("}")),
+        ExprKind::Field(e, name) => (expr_search_pat(tcx, e).0, Pat::Sym(name.name)),
+        ExprKind::Index(e, _) => (expr_search_pat(tcx, e).0, Pat::Str("]")),
+        ExprKind::Path(ref path) => qpath_search_pat(path),
+        ExprKind::AddrOf(_, _, e) => (Pat::Str("&"), expr_search_pat(tcx, e).1),
+        ExprKind::Break(Destination { label: None, .. }, None) => (Pat::Str("break"), Pat::Str("break")),
+        ExprKind::Break(Destination { label: Some(name), .. }, None) => (Pat::Str("break"), Pat::Sym(name.ident.name)),
+        ExprKind::Break(_, Some(e)) => (Pat::Str("break"), expr_search_pat(tcx, e).1),
+        ExprKind::Continue(Destination { label: None, .. }) => (Pat::Str("continue"), Pat::Str("continue")),
+        ExprKind::Continue(Destination { label: Some(name), .. }) => (Pat::Str("continue"), Pat::Sym(name.ident.name)),
+        ExprKind::Ret(None) => (Pat::Str("return"), Pat::Str("return")),
+        ExprKind::Ret(Some(e)) => (Pat::Str("return"), expr_search_pat(tcx, e).1),
+        ExprKind::Struct(path, _, _) => (qpath_search_pat(path).0, Pat::Str("}")),
+        ExprKind::Yield(e, YieldSource::Yield) => (Pat::Str("yield"), expr_search_pat(tcx, e).1),
+        _ => (Pat::Str(""), Pat::Str("")),
+    }
+}
+
+fn fn_header_search_pat(header: FnHeader) -> Pat {
+    if header.is_async() {
+        Pat::Str("async")
+    } else if header.is_const() {
+        Pat::Str("const")
+    } else if header.is_unsafe() {
+        Pat::Str("unsafe")
+    } else if header.abi != Abi::Rust {
+        Pat::Str("extern")
+    } else {
+        Pat::MultiStr(&["fn", "extern"])
+    }
+}
+
+fn item_search_pat(item: &Item<'_>) -> (Pat, Pat) {
+    let (start_pat, end_pat) = match &item.kind {
+        ItemKind::ExternCrate(_) => (Pat::Str("extern"), Pat::Str(";")),
+        ItemKind::Static(..) => (Pat::Str("static"), Pat::Str(";")),
+        ItemKind::Const(..) => (Pat::Str("const"), Pat::Str(";")),
+        ItemKind::Fn(sig, ..) => (fn_header_search_pat(sig.header), Pat::Str("")),
+        ItemKind::ForeignMod { .. } => (Pat::Str("extern"), Pat::Str("}")),
+        ItemKind::TyAlias(..) | ItemKind::OpaqueTy(_) => (Pat::Str("type"), Pat::Str(";")),
+        ItemKind::Enum(..) => (Pat::Str("enum"), Pat::Str("}")),
+        ItemKind::Struct(VariantData::Struct(..), _) => (Pat::Str("struct"), Pat::Str("}")),
+        ItemKind::Struct(..) => (Pat::Str("struct"), Pat::Str(";")),
+        ItemKind::Union(..) => (Pat::Str("union"), Pat::Str("}")),
+        ItemKind::Trait(_, Unsafety::Unsafe, ..)
+        | ItemKind::Impl(Impl {
+            unsafety: Unsafety::Unsafe,
+            ..
+        }) => (Pat::Str("unsafe"), Pat::Str("}")),
+        ItemKind::Trait(IsAuto::Yes, ..) => (Pat::Str("auto"), Pat::Str("}")),
+        ItemKind::Trait(..) => (Pat::Str("trait"), Pat::Str("}")),
+        ItemKind::Impl(_) => (Pat::Str("impl"), Pat::Str("}")),
+        _ => return (Pat::Str(""), Pat::Str("")),
+    };
+    if item.vis_span.is_empty() {
+        (start_pat, end_pat)
+    } else {
+        (Pat::Str("pub"), end_pat)
+    }
+}
+
+fn trait_item_search_pat(item: &TraitItem<'_>) -> (Pat, Pat) {
+    match &item.kind {
+        TraitItemKind::Const(..) => (Pat::Str("const"), Pat::Str(";")),
+        TraitItemKind::Type(..) => (Pat::Str("type"), Pat::Str(";")),
+        TraitItemKind::Fn(sig, ..) => (fn_header_search_pat(sig.header), Pat::Str("")),
+    }
+}
+
+fn impl_item_search_pat(item: &ImplItem<'_>) -> (Pat, Pat) {
+    let (start_pat, end_pat) = match &item.kind {
+        ImplItemKind::Const(..) => (Pat::Str("const"), Pat::Str(";")),
+        ImplItemKind::TyAlias(..) => (Pat::Str("type"), Pat::Str(";")),
+        ImplItemKind::Fn(sig, ..) => (fn_header_search_pat(sig.header), Pat::Str("")),
+    };
+    if item.vis_span.is_empty() {
+        (start_pat, end_pat)
+    } else {
+        (Pat::Str("pub"), end_pat)
+    }
+}
+
+fn field_def_search_pat(def: &FieldDef<'_>) -> (Pat, Pat) {
+    if def.vis_span.is_empty() {
+        if def.is_positional() {
+            (Pat::Str(""), Pat::Str(""))
+        } else {
+            (Pat::Sym(def.ident.name), Pat::Str(""))
+        }
+    } else {
+        (Pat::Str("pub"), Pat::Str(""))
+    }
+}
+
+fn variant_search_pat(v: &Variant<'_>) -> (Pat, Pat) {
+    match v.data {
+        VariantData::Struct(..) => (Pat::Sym(v.ident.name), Pat::Str("}")),
+        VariantData::Tuple(..) => (Pat::Sym(v.ident.name), Pat::Str("")),
+        VariantData::Unit(..) => (Pat::Sym(v.ident.name), Pat::Sym(v.ident.name)),
+    }
+}
+
+fn fn_kind_pat(tcx: TyCtxt<'_>, kind: &FnKind<'_>, body: &Body<'_>, hir_id: HirId) -> (Pat, Pat) {
+    let (start_pat, end_pat) = match kind {
+        FnKind::ItemFn(.., header) => (fn_header_search_pat(*header), Pat::Str("")),
+        FnKind::Method(.., sig) => (fn_header_search_pat(sig.header), Pat::Str("")),
+        FnKind::Closure => return (Pat::Str(""), expr_search_pat(tcx, &body.value).1),
+    };
+    let start_pat = match tcx.hir().get(hir_id) {
+        Node::Item(Item { vis_span, .. }) | Node::ImplItem(ImplItem { vis_span, .. }) => {
+            if vis_span.is_empty() {
+                start_pat
+            } else {
+                Pat::Str("pub")
+            }
+        },
+        Node::TraitItem(_) => start_pat,
+        _ => Pat::Str(""),
+    };
+    (start_pat, end_pat)
+}
+
+pub trait WithSearchPat {
+    type Context: LintContext;
+    fn search_pat(&self, cx: &Self::Context) -> (Pat, Pat);
+    fn span(&self) -> Span;
+}
+macro_rules! impl_with_search_pat {
+    ($cx:ident: $ty:ident with $fn:ident $(($tcx:ident))?) => {
+        impl<'cx> WithSearchPat for $ty<'cx> {
+            type Context = $cx<'cx>;
+            #[allow(unused_variables)]
+            fn search_pat(&self, cx: &Self::Context) -> (Pat, Pat) {
+                $(let $tcx = cx.tcx;)?
+                $fn($($tcx,)? self)
+            }
+            fn span(&self) -> Span {
+                self.span
+            }
+        }
+    };
+}
+impl_with_search_pat!(LateContext: Expr with expr_search_pat(tcx));
+impl_with_search_pat!(LateContext: Item with item_search_pat);
+impl_with_search_pat!(LateContext: TraitItem with trait_item_search_pat);
+impl_with_search_pat!(LateContext: ImplItem with impl_item_search_pat);
+impl_with_search_pat!(LateContext: FieldDef with field_def_search_pat);
+impl_with_search_pat!(LateContext: Variant with variant_search_pat);
+
+impl<'cx> WithSearchPat for (&FnKind<'cx>, &Body<'cx>, HirId, Span) {
+    type Context = LateContext<'cx>;
+
+    fn search_pat(&self, cx: &Self::Context) -> (Pat, Pat) {
+        fn_kind_pat(cx.tcx, self.0, self.1, self.2)
+    }
+
+    fn span(&self) -> Span {
+        self.3
+    }
+}
+
+/// Checks if the item likely came from a proc-macro.
+///
+/// This should be called after `in_external_macro` and the initial pattern matching of the ast as
+/// it is significantly slower than both of those.
+pub fn is_from_proc_macro<T: WithSearchPat>(cx: &T::Context, item: &T) -> bool {
+    let (start_pat, end_pat) = item.search_pat(cx);
+    !span_matches_pat(cx.sess(), item.span(), start_pat, end_pat)
+}
+
+/// Checks if the span actually refers to a match expression
+pub fn is_span_match(cx: &impl LintContext, span: Span) -> bool {
+    span_matches_pat(cx.sess(), span, Pat::Str("match"), Pat::Str("}"))
+}
+
+/// Checks if the span actually refers to an if expression
+pub fn is_span_if(cx: &impl LintContext, span: Span) -> bool {
+    span_matches_pat(cx.sess(), span, Pat::Str("if"), Pat::Str("}"))
+}
index eaf260ddfb832d05d7d9cc7be5d87922ae14b2c8..1834e2a2de8720b861a8690b57313f33c5297996 100644 (file)
@@ -141,7 +141,7 @@ fn eq_block(&mut self, left: &Block<'_>, right: &Block<'_>) -> bool {
                 let mut left_pos = 0;
                 let left = tokenize(&left)
                     .map(|t| {
-                        let end = left_pos + t.len;
+                        let end = left_pos + t.len as usize;
                         let s = &left[left_pos..end];
                         left_pos = end;
                         (t, s)
@@ -156,7 +156,7 @@ fn eq_block(&mut self, left: &Block<'_>, right: &Block<'_>) -> bool {
                 let mut right_pos = 0;
                 let right = tokenize(&right)
                     .map(|t| {
-                        let end = right_pos + t.len;
+                        let end = right_pos + t.len as usize;
                         let s = &right[right_pos..end];
                         right_pos = end;
                         (t, s)
index 7493a8685dff85875928f9a5fc600bcd65d5341f..2616a578bb884271153d00ca9c038efa6f730058 100644 (file)
@@ -39,6 +39,7 @@
 
 pub mod ast_utils;
 pub mod attrs;
+mod check_proc_macro;
 pub mod comparisons;
 pub mod consts;
 pub mod diagnostics;
@@ -59,6 +60,7 @@
 pub mod visitors;
 
 pub use self::attrs::*;
+pub use self::check_proc_macro::{is_from_proc_macro, is_span_if, is_span_match};
 pub use self::hir_utils::{
     both, count_eq, eq_expr_value, hash_expr, hash_stmt, over, HirEqInterExpr, SpanlessEq, SpanlessHash,
 };
index 3fb5415ce02999b93ecb171475fca4712a287b17..80098d9766c67b47c0e2e9604cbd76ac6e9ac3ce 100644 (file)
@@ -223,10 +223,12 @@ pub fn group_digits(output: &mut String, input: &str, group_size: usize, partial
 
 fn split_suffix<'a>(src: &'a str, lit_kind: &LitKind) -> (&'a str, Option<&'a str>) {
     debug_assert!(lit_kind.is_numeric());
-    lit_suffix_length(lit_kind).map_or((src, None), |suffix_length| {
-        let (unsuffixed, suffix) = src.split_at(src.len() - suffix_length);
-        (unsuffixed, Some(suffix))
-    })
+    lit_suffix_length(lit_kind)
+        .and_then(|suffix_length| src.len().checked_sub(suffix_length))
+        .map_or((src, None), |split_pos| {
+            let (unsuffixed, suffix) = src.split_at(split_pos);
+            (unsuffixed, Some(suffix))
+        })
 }
 
 fn lit_suffix_length(lit_kind: &LitKind) -> Option<usize> {
index 05429d05d9ebe8285698298b598daeaab5eb1347..8d697a301c444c354efd1ee383a5be24eae64099 100644 (file)
 pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"];
 pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"];
 pub const PTR_NON_NULL: [&str; 4] = ["core", "ptr", "non_null", "NonNull"];
+pub const INSTANT_NOW: [&str; 4] = ["std", "time", "Instant", "now"];
+pub const INSTANT: [&str; 3] = ["std", "time", "Instant"];
index 1197fe914de46853dd3dcdde12daec9a6097fbcc..d85f591fb9a42f0c087f61dfe95da170d65db5aa 100644 (file)
 use rustc_span::{BytePos, Pos, Span, SpanData, SyntaxContext};
 use std::borrow::Cow;
 
-/// Checks if the span starts with the given text. This will return false if the span crosses
-/// multiple files or if source is not available.
-///
-/// This is used to check for proc macros giving unhelpful spans to things.
-pub fn span_starts_with<T: LintContext>(cx: &T, span: Span, text: &str) -> bool {
-    fn helper(sm: &SourceMap, span: Span, text: &str) -> bool {
-        let pos = sm.lookup_byte_offset(span.lo());
-        let Some(ref src) = pos.sf.src else {
-            return false;
-        };
-        let end = span.hi() - pos.sf.start_pos;
-        src.get(pos.pos.0 as usize..end.0 as usize)
-            // Expression spans can include wrapping parenthesis. Remove them first.
-            .map_or(false, |s| s.trim_start_matches('(').starts_with(text))
-    }
-    helper(cx.sess().source_map(), span, text)
-}
-
 /// Like `snippet_block`, but add braces if the expr is not an `ExprKind::Block`.
 /// Also takes an `Option<String>` which can be put inside the braces.
 pub fn expr_block<'a, T: LintContext>(
index bad291dfc2513f6a0318437107dff89432b03e55..081c98e2f3ce726ccf9019a46fc4631eefde9a29 100644 (file)
@@ -315,6 +315,12 @@ pub fn blockify(self) -> Sugg<'static> {
         Sugg::NonParen(Cow::Owned(format!("{{ {} }}", self)))
     }
 
+    /// Convenience method to prefix the expression with the `async` keyword.
+    /// Can be used after `blockify` to create an async block.
+    pub fn asyncify(self) -> Sugg<'static> {
+        Sugg::NonParen(Cow::Owned(format!("async {}", self)))
+    }
+
     /// Convenience method to create the `<lhs>..<rhs>` or `<lhs>...<rhs>`
     /// suggestion.
     pub fn range(self, end: &Self, limit: ast::RangeLimits) -> Sugg<'static> {
index a05d633d980c3247b18f9e94140d379a80dd9c9c..e7d670766a050203793c22970b12c09bc26c2806 100644 (file)
@@ -503,7 +503,7 @@ pub fn all_predicates_of(tcx: TyCtxt<'_>, id: DefId) -> impl Iterator<Item = &(P
 pub enum ExprFnSig<'tcx> {
     Sig(Binder<'tcx, FnSig<'tcx>>, Option<DefId>),
     Closure(Option<&'tcx FnDecl<'tcx>>, Binder<'tcx, FnSig<'tcx>>),
-    Trait(Binder<'tcx, Ty<'tcx>>, Option<Binder<'tcx, Ty<'tcx>>>),
+    Trait(Binder<'tcx, Ty<'tcx>>, Option<Binder<'tcx, Ty<'tcx>>>, Option<DefId>),
 }
 impl<'tcx> ExprFnSig<'tcx> {
     /// Gets the argument type at the given offset. This will return `None` when the index is out of
@@ -518,7 +518,7 @@ pub fn input(self, i: usize) -> Option<Binder<'tcx, Ty<'tcx>>> {
                 }
             },
             Self::Closure(_, sig) => Some(sig.input(0).map_bound(|ty| ty.tuple_fields()[i])),
-            Self::Trait(inputs, _) => Some(inputs.map_bound(|ty| ty.tuple_fields()[i])),
+            Self::Trait(inputs, _, _) => Some(inputs.map_bound(|ty| ty.tuple_fields()[i])),
         }
     }
 
@@ -541,7 +541,7 @@ pub fn input_with_hir(self, i: usize) -> Option<(Option<&'tcx hir::Ty<'tcx>>, Bi
                 decl.and_then(|decl| decl.inputs.get(i)),
                 sig.input(0).map_bound(|ty| ty.tuple_fields()[i]),
             )),
-            Self::Trait(inputs, _) => Some((None, inputs.map_bound(|ty| ty.tuple_fields()[i]))),
+            Self::Trait(inputs, _, _) => Some((None, inputs.map_bound(|ty| ty.tuple_fields()[i]))),
         }
     }
 
@@ -550,12 +550,16 @@ pub fn input_with_hir(self, i: usize) -> Option<(Option<&'tcx hir::Ty<'tcx>>, Bi
     pub fn output(self) -> Option<Binder<'tcx, Ty<'tcx>>> {
         match self {
             Self::Sig(sig, _) | Self::Closure(_, sig) => Some(sig.output()),
-            Self::Trait(_, output) => output,
+            Self::Trait(_, output, _) => output,
         }
     }
 
     pub fn predicates_id(&self) -> Option<DefId> {
-        if let ExprFnSig::Sig(_, id) = *self { id } else { None }
+        if let ExprFnSig::Sig(_, id) | ExprFnSig::Trait(_, _, id) = *self {
+            id
+        } else {
+            None
+        }
     }
 }
 
@@ -568,7 +572,8 @@ pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<ExprFnS
     }
 }
 
-fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'tcx>> {
+/// If the type is function like, get the signature for it.
+pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'tcx>> {
     if ty.is_box() {
         return ty_sig(cx, ty.boxed_ty());
     }
@@ -580,7 +585,7 @@ fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'tcx>>
             Some(ExprFnSig::Closure(decl, subs.as_closure().sig()))
         },
         ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.bound_fn_sig(id).subst(cx.tcx, subs), Some(id))),
-        ty::Opaque(id, _) => ty_sig(cx, cx.tcx.type_of(id)),
+        ty::Opaque(id, _) => sig_from_bounds(cx, ty, cx.tcx.item_bounds(id), cx.tcx.opt_parent(id)),
         ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)),
         ty::Dynamic(bounds, _) => {
             let lang_items = cx.tcx.lang_items();
@@ -594,26 +599,31 @@ fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'tcx>>
                         .projection_bounds()
                         .find(|p| lang_items.fn_once_output().map_or(false, |id| id == p.item_def_id()))
                         .map(|p| p.map_bound(|p| p.term.ty().unwrap()));
-                    Some(ExprFnSig::Trait(bound.map_bound(|b| b.substs.type_at(0)), output))
+                    Some(ExprFnSig::Trait(bound.map_bound(|b| b.substs.type_at(0)), output, None))
                 },
                 _ => None,
             }
         },
         ty::Projection(proj) => match cx.tcx.try_normalize_erasing_regions(cx.param_env, ty) {
             Ok(normalized_ty) if normalized_ty != ty => ty_sig(cx, normalized_ty),
-            _ => sig_for_projection(cx, proj).or_else(|| sig_from_bounds(cx, ty)),
+            _ => sig_for_projection(cx, proj).or_else(|| sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None)),
         },
-        ty::Param(_) => sig_from_bounds(cx, ty),
+        ty::Param(_) => sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None),
         _ => None,
     }
 }
 
-fn sig_from_bounds<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'tcx>> {
+fn sig_from_bounds<'tcx>(
+    cx: &LateContext<'tcx>,
+    ty: Ty<'tcx>,
+    predicates: &'tcx [Predicate<'tcx>],
+    predicates_id: Option<DefId>,
+) -> Option<ExprFnSig<'tcx>> {
     let mut inputs = None;
     let mut output = None;
     let lang_items = cx.tcx.lang_items();
 
-    for (pred, _) in all_predicates_of(cx.tcx, cx.typeck_results().hir_owner.to_def_id()) {
+    for pred in predicates {
         match pred.kind().skip_binder() {
             PredicateKind::Trait(p)
                 if (lang_items.fn_trait() == Some(p.def_id())
@@ -621,11 +631,12 @@ fn sig_from_bounds<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnS
                     || lang_items.fn_once_trait() == Some(p.def_id()))
                     && p.self_ty() == ty =>
             {
-                if inputs.is_some() {
+                let i = pred.kind().rebind(p.trait_ref.substs.type_at(1));
+                if inputs.map_or(false, |inputs| i != inputs) {
                     // Multiple different fn trait impls. Is this even allowed?
                     return None;
                 }
-                inputs = Some(pred.kind().rebind(p.trait_ref.substs.type_at(1)));
+                inputs = Some(i);
             },
             PredicateKind::Projection(p)
                 if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output()
@@ -641,7 +652,7 @@ fn sig_from_bounds<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnS
         }
     }
 
-    inputs.map(|ty| ExprFnSig::Trait(ty, output))
+    inputs.map(|ty| ExprFnSig::Trait(ty, output, predicates_id))
 }
 
 fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> Option<ExprFnSig<'tcx>> {
@@ -661,14 +672,15 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> O
                     || lang_items.fn_mut_trait() == Some(p.def_id())
                     || lang_items.fn_once_trait() == Some(p.def_id())) =>
             {
-                if inputs.is_some() {
+                let i = pred
+                    .map_bound(|pred| pred.kind().rebind(p.trait_ref.substs.type_at(1)))
+                    .subst(cx.tcx, ty.substs);
+
+                if inputs.map_or(false, |inputs| inputs != i) {
                     // Multiple different fn trait impls. Is this even allowed?
                     return None;
                 }
-                inputs = Some(
-                    pred.map_bound(|pred| pred.kind().rebind(p.trait_ref.substs.type_at(1)))
-                        .subst(cx.tcx, ty.substs),
-                );
+                inputs = Some(i);
             },
             PredicateKind::Projection(p) if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() => {
                 if output.is_some() {
@@ -684,7 +696,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> O
         }
     }
 
-    inputs.map(|ty| ExprFnSig::Trait(ty, output))
+    inputs.map(|ty| ExprFnSig::Trait(ty, output, None))
 }
 
 #[derive(Clone, Copy)]
index 23ba7c712779efb0b788652c35a02faedeec5c6e..7e14df4feea66316953a53425dcde75eee8bf066 100644 (file)
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2022-07-28"
+channel = "nightly-2022-08-11"
 components = ["cargo", "llvm-tools-preview", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
index 5331075885c1d92b0bb961ca65ec63e8301596f3..2aa4de490bcf6b99e1dbdf9ca076a366dc15b9f9 100644 (file)
@@ -16,7 +16,7 @@ note: the lint level is defined here
 LL | #![deny(clippy::internal)]
    |         ^^^^^^^^^^^^^^^^
    = note: `#[deny(clippy::invalid_clippy_version_attribute)]` implied by `#[deny(clippy::internal)]`
-   = help: please use a valid sematic version, see `doc/adding_lints.md`
+   = help: please use a valid semantic version, see `doc/adding_lints.md`
    = note: this error originates in the macro `$crate::declare_tool_lint` which comes from the expansion of the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: this item has an invalid `clippy::version` attribute
@@ -31,7 +31,7 @@ LL | |     report_in_external_macro: true
 LL | | }
    | |_^
    |
-   = help: please use a valid sematic version, see `doc/adding_lints.md`
+   = help: please use a valid semantic version, see `doc/adding_lints.md`
    = note: this error originates in the macro `$crate::declare_tool_lint` which comes from the expansion of the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: this lint is missing the `clippy::version` attribute or version value
index 168675394d7f45124940fcfa3433aab378c1fbd8..d48bab08f690bc0ca6cdba4e38471e8bbc66b261 100644 (file)
@@ -1 +1 @@
-blacklisted-names = 42
+disallowed-names = 42
index c7bc261de6c5a3f8c10af3ffc10ae0a47df5d579..e3ec60192040e32d3a6b8921ff5db80b3e7fda13 100644 (file)
@@ -1,4 +1,4 @@
-error: error reading Clippy's configuration file `$DIR/clippy.toml`: invalid type: integer `42`, expected a sequence for key `blacklisted-names`
+error: error reading Clippy's configuration file `$DIR/clippy.toml`: invalid type: integer `42`, expected a sequence for key `disallowed-names`
 
 error: aborting due to previous error
 
diff --git a/src/tools/clippy/tests/ui-toml/blacklisted_names_append/blacklisted_names.rs b/src/tools/clippy/tests/ui-toml/blacklisted_names_append/blacklisted_names.rs
deleted file mode 100644 (file)
index fb2395c..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#[warn(clippy::blacklisted_name)]
-
-fn main() {
-    // `foo` is part of the default configuration
-    let foo = "bar";
-    // `ducks` was unrightfully blacklisted
-    let ducks = ["quack", "quack"];
-    // `fox` is okay
-    let fox = ["what", "does", "the", "fox", "say", "?"];
-}
diff --git a/src/tools/clippy/tests/ui-toml/blacklisted_names_append/blacklisted_names.stderr b/src/tools/clippy/tests/ui-toml/blacklisted_names_append/blacklisted_names.stderr
deleted file mode 100644 (file)
index 9169bb0..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-error: use of a blacklisted/placeholder name `foo`
-  --> $DIR/blacklisted_names.rs:5:9
-   |
-LL |     let foo = "bar";
-   |         ^^^
-   |
-   = note: `-D clippy::blacklisted-name` implied by `-D warnings`
-
-error: use of a blacklisted/placeholder name `ducks`
-  --> $DIR/blacklisted_names.rs:7:9
-   |
-LL |     let ducks = ["quack", "quack"];
-   |         ^^^^^
-
-error: aborting due to 2 previous errors
-
diff --git a/src/tools/clippy/tests/ui-toml/blacklisted_names_append/clippy.toml b/src/tools/clippy/tests/ui-toml/blacklisted_names_append/clippy.toml
deleted file mode 100644 (file)
index 0e052ef..0000000
+++ /dev/null
@@ -1 +0,0 @@
-blacklisted-names = ["ducks", ".."]
diff --git a/src/tools/clippy/tests/ui-toml/blacklisted_names_replace/blacklisted_names.rs b/src/tools/clippy/tests/ui-toml/blacklisted_names_replace/blacklisted_names.rs
deleted file mode 100644 (file)
index fb2395c..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#[warn(clippy::blacklisted_name)]
-
-fn main() {
-    // `foo` is part of the default configuration
-    let foo = "bar";
-    // `ducks` was unrightfully blacklisted
-    let ducks = ["quack", "quack"];
-    // `fox` is okay
-    let fox = ["what", "does", "the", "fox", "say", "?"];
-}
diff --git a/src/tools/clippy/tests/ui-toml/blacklisted_names_replace/blacklisted_names.stderr b/src/tools/clippy/tests/ui-toml/blacklisted_names_replace/blacklisted_names.stderr
deleted file mode 100644 (file)
index ec6f7f0..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-error: use of a blacklisted/placeholder name `ducks`
-  --> $DIR/blacklisted_names.rs:7:9
-   |
-LL |     let ducks = ["quack", "quack"];
-   |         ^^^^^
-   |
-   = note: `-D clippy::blacklisted-name` implied by `-D warnings`
-
-error: aborting due to previous error
-
diff --git a/src/tools/clippy/tests/ui-toml/blacklisted_names_replace/clippy.toml b/src/tools/clippy/tests/ui-toml/blacklisted_names_replace/clippy.toml
deleted file mode 100644 (file)
index 4582f1c..0000000
+++ /dev/null
@@ -1 +0,0 @@
-blacklisted-names = ["ducks"]
index ac47b195042ebfb3682978d7847888ef49a2f40f..d79a98d05af48221c7fcfd414c7bf31229d6fdf7 100644 (file)
@@ -1,5 +1,6 @@
-# that one is an error
-cyclomatic-complexity-threshold = 42
+# Expect errors from these deprecated configs
+cyclomatic-complexity-threshold = 2
+blacklisted-names = [ "..", "wibble" ]
 
 # that one is white-listed
 [third-party]
index f328e4d9d04c31d0d70d16d21a07d1613be9d577..b4e677ea124b7d673b14c90e1ea08607ae311dbd 100644 (file)
@@ -1 +1,11 @@
 fn main() {}
+
+#[warn(clippy::cognitive_complexity)]
+fn cognitive_complexity() {
+    let x = vec![1, 2, 3];
+    for i in x {
+        if i == 1 {
+            println!("{}", i);
+        }
+    }
+}
index 90021a034a3d3b358ae1eb472f733904ee8649d1..4c560299ebdd1385bdfd0878d8970989ba45683e 100644 (file)
@@ -1,4 +1,15 @@
-error: error reading Clippy's configuration file `$DIR/clippy.toml`: deprecated field `cyclomatic-complexity-threshold`. Please use `cognitive-complexity-threshold` instead
+warning: error reading Clippy's configuration file `$DIR/clippy.toml`: deprecated field `cyclomatic-complexity-threshold`. Please use `cognitive-complexity-threshold` instead
 
-error: aborting due to previous error
+warning: error reading Clippy's configuration file `$DIR/clippy.toml`: deprecated field `blacklisted-names`. Please use `disallowed-names` instead
+
+error: the function has a cognitive complexity of (3/2)
+  --> $DIR/conf_deprecated_key.rs:4:4
+   |
+LL | fn cognitive_complexity() {
+   |    ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::cognitive-complexity` implied by `-D warnings`
+   = help: you could split it up into multiple smaller functions
+
+error: aborting due to previous error; 2 warnings emitted
 
diff --git a/src/tools/clippy/tests/ui-toml/disallowed_names_append/clippy.toml b/src/tools/clippy/tests/ui-toml/disallowed_names_append/clippy.toml
new file mode 100644 (file)
index 0000000..6df96a3
--- /dev/null
@@ -0,0 +1 @@
+disallowed-names = ["ducks", ".."]
diff --git a/src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.rs b/src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.rs
new file mode 100644 (file)
index 0000000..a2e2b46
--- /dev/null
@@ -0,0 +1,10 @@
+#[warn(clippy::disallowed_names)]
+
+fn main() {
+    // `foo` is part of the default configuration
+    let foo = "bar";
+    // `ducks` was unrightfully disallowed
+    let ducks = ["quack", "quack"];
+    // `fox` is okay
+    let fox = ["what", "does", "the", "fox", "say", "?"];
+}
diff --git a/src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.stderr b/src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.stderr
new file mode 100644 (file)
index 0000000..23c3e96
--- /dev/null
@@ -0,0 +1,16 @@
+error: use of a disallowed/placeholder name `foo`
+  --> $DIR/disallowed_names.rs:5:9
+   |
+LL |     let foo = "bar";
+   |         ^^^
+   |
+   = note: `-D clippy::disallowed-names` implied by `-D warnings`
+
+error: use of a disallowed/placeholder name `ducks`
+  --> $DIR/disallowed_names.rs:7:9
+   |
+LL |     let ducks = ["quack", "quack"];
+   |         ^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/disallowed_names_replace/clippy.toml b/src/tools/clippy/tests/ui-toml/disallowed_names_replace/clippy.toml
new file mode 100644 (file)
index 0000000..a1c5156
--- /dev/null
@@ -0,0 +1 @@
+disallowed-names = ["ducks"]
diff --git a/src/tools/clippy/tests/ui-toml/disallowed_names_replace/disallowed_names.rs b/src/tools/clippy/tests/ui-toml/disallowed_names_replace/disallowed_names.rs
new file mode 100644 (file)
index 0000000..a2e2b46
--- /dev/null
@@ -0,0 +1,10 @@
+#[warn(clippy::disallowed_names)]
+
+fn main() {
+    // `foo` is part of the default configuration
+    let foo = "bar";
+    // `ducks` was unrightfully disallowed
+    let ducks = ["quack", "quack"];
+    // `fox` is okay
+    let fox = ["what", "does", "the", "fox", "say", "?"];
+}
diff --git a/src/tools/clippy/tests/ui-toml/disallowed_names_replace/disallowed_names.stderr b/src/tools/clippy/tests/ui-toml/disallowed_names_replace/disallowed_names.stderr
new file mode 100644 (file)
index 0000000..d961fa3
--- /dev/null
@@ -0,0 +1,10 @@
+error: use of a disallowed/placeholder name `ducks`
+  --> $DIR/disallowed_names.rs:7:9
+   |
+LL |     let ducks = ["quack", "quack"];
+   |         ^^^^^
+   |
+   = note: `-D clippy::disallowed-names` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui-toml/duplicated_keys/clippy.toml b/src/tools/clippy/tests/ui-toml/duplicated_keys/clippy.toml
new file mode 100644 (file)
index 0000000..63a893c
--- /dev/null
@@ -0,0 +1,5 @@
+cognitive-complexity-threshold = 2
+# This is the deprecated name for the same key
+cyclomatic-complexity-threshold = 3
+# Check we get duplication warning regardless of order
+cognitive-complexity-threshold = 4
diff --git a/src/tools/clippy/tests/ui-toml/duplicated_keys/duplicated_keys.rs b/src/tools/clippy/tests/ui-toml/duplicated_keys/duplicated_keys.rs
new file mode 100644 (file)
index 0000000..f328e4d
--- /dev/null
@@ -0,0 +1 @@
+fn main() {}
diff --git a/src/tools/clippy/tests/ui-toml/duplicated_keys/duplicated_keys.stderr b/src/tools/clippy/tests/ui-toml/duplicated_keys/duplicated_keys.stderr
new file mode 100644 (file)
index 0000000..d99490a
--- /dev/null
@@ -0,0 +1,8 @@
+error: error reading Clippy's configuration file `$DIR/clippy.toml`: duplicate field `cognitive_complexity_threshold` (provided as `cyclomatic_complexity_threshold`)
+
+error: error reading Clippy's configuration file `$DIR/clippy.toml`: duplicate field `cognitive-complexity-threshold`
+
+warning: error reading Clippy's configuration file `$DIR/clippy.toml`: deprecated field `cyclomatic-complexity-threshold`. Please use `cognitive-complexity-threshold` instead
+
+error: aborting due to 2 previous errors; 1 warning emitted
+
index 9cb2199ed21cb0604af19671c66f490b79f50408..c5d95cb8a147f71fbc8c5e335ea4e77f78b94a8b 100644 (file)
@@ -5,7 +5,7 @@ LL |     let _ = opt.expect("");
    |             ^^^^^^^^^^^^^^
    |
    = note: `-D clippy::expect-used` implied by `-D warnings`
-   = help: if this value is an `None`, it will panic
+   = help: if this value is `None`, it will panic
 
 error: used `expect()` on `a Result` value
   --> $DIR/expect_used.rs:11:13
diff --git a/src/tools/clippy/tests/ui-toml/toml_blacklist/clippy.toml b/src/tools/clippy/tests/ui-toml/toml_blacklist/clippy.toml
deleted file mode 100644 (file)
index 6abe5a3..0000000
+++ /dev/null
@@ -1 +0,0 @@
-blacklisted-names = ["toto", "tata", "titi"]
diff --git a/src/tools/clippy/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.rs b/src/tools/clippy/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.rs
deleted file mode 100644 (file)
index cb35d0e..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#![allow(dead_code)]
-#![allow(clippy::single_match)]
-#![allow(unused_variables)]
-#![warn(clippy::blacklisted_name)]
-
-fn test(toto: ()) {}
-
-fn main() {
-    let toto = 42;
-    let tata = 42;
-    let titi = 42;
-
-    let tatab = 42;
-    let tatatataic = 42;
-
-    match (42, Some(1337), Some(0)) {
-        (toto, Some(tata), titi @ Some(_)) => (),
-        _ => (),
-    }
-}
diff --git a/src/tools/clippy/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.stderr b/src/tools/clippy/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.stderr
deleted file mode 100644 (file)
index 84ba778..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-error: use of a blacklisted/placeholder name `toto`
-  --> $DIR/conf_french_blacklisted_name.rs:6:9
-   |
-LL | fn test(toto: ()) {}
-   |         ^^^^
-   |
-   = note: `-D clippy::blacklisted-name` implied by `-D warnings`
-
-error: use of a blacklisted/placeholder name `toto`
-  --> $DIR/conf_french_blacklisted_name.rs:9:9
-   |
-LL |     let toto = 42;
-   |         ^^^^
-
-error: use of a blacklisted/placeholder name `tata`
-  --> $DIR/conf_french_blacklisted_name.rs:10:9
-   |
-LL |     let tata = 42;
-   |         ^^^^
-
-error: use of a blacklisted/placeholder name `titi`
-  --> $DIR/conf_french_blacklisted_name.rs:11:9
-   |
-LL |     let titi = 42;
-   |         ^^^^
-
-error: use of a blacklisted/placeholder name `toto`
-  --> $DIR/conf_french_blacklisted_name.rs:17:10
-   |
-LL |         (toto, Some(tata), titi @ Some(_)) => (),
-   |          ^^^^
-
-error: use of a blacklisted/placeholder name `tata`
-  --> $DIR/conf_french_blacklisted_name.rs:17:21
-   |
-LL |         (toto, Some(tata), titi @ Some(_)) => (),
-   |                     ^^^^
-
-error: use of a blacklisted/placeholder name `titi`
-  --> $DIR/conf_french_blacklisted_name.rs:17:28
-   |
-LL |         (toto, Some(tata), titi @ Some(_)) => (),
-   |                            ^^^^
-
-error: aborting due to 7 previous errors
-
diff --git a/src/tools/clippy/tests/ui-toml/toml_disallow/clippy.toml b/src/tools/clippy/tests/ui-toml/toml_disallow/clippy.toml
new file mode 100644 (file)
index 0000000..e4f0cb6
--- /dev/null
@@ -0,0 +1 @@
+disallowed-names = ["toto", "tata", "titi"]
diff --git a/src/tools/clippy/tests/ui-toml/toml_disallow/conf_french_disallowed_name.rs b/src/tools/clippy/tests/ui-toml/toml_disallow/conf_french_disallowed_name.rs
new file mode 100644 (file)
index 0000000..2f86b3e
--- /dev/null
@@ -0,0 +1,20 @@
+#![allow(dead_code)]
+#![allow(clippy::single_match)]
+#![allow(unused_variables)]
+#![warn(clippy::disallowed_names)]
+
+fn test(toto: ()) {}
+
+fn main() {
+    let toto = 42;
+    let tata = 42;
+    let titi = 42;
+
+    let tatab = 42;
+    let tatatataic = 42;
+
+    match (42, Some(1337), Some(0)) {
+        (toto, Some(tata), titi @ Some(_)) => (),
+        _ => (),
+    }
+}
diff --git a/src/tools/clippy/tests/ui-toml/toml_disallow/conf_french_disallowed_name.stderr b/src/tools/clippy/tests/ui-toml/toml_disallow/conf_french_disallowed_name.stderr
new file mode 100644 (file)
index 0000000..9082c1c
--- /dev/null
@@ -0,0 +1,46 @@
+error: use of a disallowed/placeholder name `toto`
+  --> $DIR/conf_french_disallowed_name.rs:6:9
+   |
+LL | fn test(toto: ()) {}
+   |         ^^^^
+   |
+   = note: `-D clippy::disallowed-names` implied by `-D warnings`
+
+error: use of a disallowed/placeholder name `toto`
+  --> $DIR/conf_french_disallowed_name.rs:9:9
+   |
+LL |     let toto = 42;
+   |         ^^^^
+
+error: use of a disallowed/placeholder name `tata`
+  --> $DIR/conf_french_disallowed_name.rs:10:9
+   |
+LL |     let tata = 42;
+   |         ^^^^
+
+error: use of a disallowed/placeholder name `titi`
+  --> $DIR/conf_french_disallowed_name.rs:11:9
+   |
+LL |     let titi = 42;
+   |         ^^^^
+
+error: use of a disallowed/placeholder name `toto`
+  --> $DIR/conf_french_disallowed_name.rs:17:10
+   |
+LL |         (toto, Some(tata), titi @ Some(_)) => (),
+   |          ^^^^
+
+error: use of a disallowed/placeholder name `tata`
+  --> $DIR/conf_french_disallowed_name.rs:17:21
+   |
+LL |         (toto, Some(tata), titi @ Some(_)) => (),
+   |                     ^^^^
+
+error: use of a disallowed/placeholder name `titi`
+  --> $DIR/conf_french_disallowed_name.rs:17:28
+   |
+LL |         (toto, Some(tata), titi @ Some(_)) => (),
+   |                            ^^^^
+
+error: aborting due to 7 previous errors
+
index fe5139c47680c2b449e5823a77af031a10530c8f..9f8e778b3b9d1d36b526de62226c03462ab1dff4 100644 (file)
@@ -12,6 +12,7 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie
            cognitive-complexity-threshold
            cyclomatic-complexity-threshold
            disallowed-methods
+           disallowed-names
            disallowed-types
            doc-valid-idents
            enable-raw-pointer-heuristic-for-send
index 7bde72e4b6b57dfdf22f5b002b1f5455012319e0..795f435f24cd40b3e713959334ff266aaba3cc9f 100644 (file)
@@ -27,6 +27,14 @@ fn main() {
     let r: Result<Foo, Foo> = Ok(Foo);
     assert!(r.is_ok());
 
+    // test ok with some messages
+    let r: Result<Foo, DebugFoo> = Ok(Foo);
+    assert!(r.is_ok(), "oops");
+
+    // test ok with unit error
+    let r: Result<Foo, ()> = Ok(Foo);
+    assert!(r.is_ok());
+
     // test temporary ok
     fn get_ok() -> Result<Foo, DebugFoo> {
         Ok(Foo)
index 4c5af81efc23fbac1ae73a27fda862eeb9f1ddd2..1101aec1e1b34d5cfc29a591b1292ff6bc35d3f6 100644 (file)
@@ -27,6 +27,14 @@ fn main() {
     let r: Result<Foo, Foo> = Ok(Foo);
     assert!(r.is_ok());
 
+    // test ok with some messages
+    let r: Result<Foo, DebugFoo> = Ok(Foo);
+    assert!(r.is_ok(), "oops");
+
+    // test ok with unit error
+    let r: Result<Foo, ()> = Ok(Foo);
+    assert!(r.is_ok());
+
     // test temporary ok
     fn get_ok() -> Result<Foo, DebugFoo> {
         Ok(Foo)
index 13c2dd877a976c524e9db0c35df98cb314b6189c..97a5f3dfca4a65f93f8d49f1f326fea941531c04 100644 (file)
@@ -7,31 +7,31 @@ LL |     assert!(r.is_ok());
    = note: `-D clippy::assertions-on-result-states` implied by `-D warnings`
 
 error: called `assert!` with `Result::is_ok`
-  --> $DIR/assertions_on_result_states.rs:34:5
+  --> $DIR/assertions_on_result_states.rs:42:5
    |
 LL |     assert!(get_ok().is_ok());
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `get_ok().unwrap()`
 
 error: called `assert!` with `Result::is_ok`
-  --> $DIR/assertions_on_result_states.rs:37:5
+  --> $DIR/assertions_on_result_states.rs:45:5
    |
 LL |     assert!(get_ok_macro!().is_ok());
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `get_ok_macro!().unwrap()`
 
 error: called `assert!` with `Result::is_ok`
-  --> $DIR/assertions_on_result_states.rs:50:5
+  --> $DIR/assertions_on_result_states.rs:58:5
    |
 LL |     assert!(r.is_ok());
    |     ^^^^^^^^^^^^^^^^^^ help: replace with: `r.unwrap()`
 
 error: called `assert!` with `Result::is_ok`
-  --> $DIR/assertions_on_result_states.rs:56:9
+  --> $DIR/assertions_on_result_states.rs:64:9
    |
 LL |         assert!(r.is_ok());
    |         ^^^^^^^^^^^^^^^^^^ help: replace with: `r.unwrap()`
 
 error: called `assert!` with `Result::is_err`
-  --> $DIR/assertions_on_result_states.rs:64:5
+  --> $DIR/assertions_on_result_states.rs:72:5
    |
 LL |     assert!(r.is_err());
    |     ^^^^^^^^^^^^^^^^^^^ help: replace with: `r.unwrap_err()`
diff --git a/src/tools/clippy/tests/ui/blacklisted_name.rs b/src/tools/clippy/tests/ui/blacklisted_name.rs
deleted file mode 100644 (file)
index 27df732..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-#![allow(
-    dead_code,
-    clippy::similar_names,
-    clippy::single_match,
-    clippy::toplevel_ref_arg,
-    unused_mut,
-    unused_variables
-)]
-#![warn(clippy::blacklisted_name)]
-
-fn test(foo: ()) {}
-
-fn main() {
-    let foo = 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 food = 42;
-    let foodstuffs = 42;
-    let bazaar = 42;
-
-    match (42, Some(1337), Some(0)) {
-        (foo, Some(baz), quux @ Some(_)) => (),
-        _ => (),
-    }
-}
-
-fn issue_1647(mut foo: u8) {
-    let mut baz = 0;
-    if let Some(mut quux) = Some(42) {}
-}
-
-fn issue_1647_ref() {
-    let ref baz = 0;
-    if let Some(ref quux) = Some(42) {}
-}
-
-fn issue_1647_ref_mut() {
-    let ref mut baz = 0;
-    if let Some(ref mut quux) = Some(42) {}
-}
-
-mod tests {
-    fn issue_7305() {
-        // `blacklisted_name` lint should not be triggered inside of the test code.
-        let foo = 0;
-
-        // Check that even in nested functions warning is still not triggered.
-        fn nested() {
-            let foo = 0;
-        }
-    }
-}
diff --git a/src/tools/clippy/tests/ui/blacklisted_name.stderr b/src/tools/clippy/tests/ui/blacklisted_name.stderr
deleted file mode 100644 (file)
index 70dbdae..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-error: use of a blacklisted/placeholder name `foo`
-  --> $DIR/blacklisted_name.rs:11:9
-   |
-LL | fn test(foo: ()) {}
-   |         ^^^
-   |
-   = note: `-D clippy::blacklisted-name` implied by `-D warnings`
-
-error: use of a blacklisted/placeholder name `foo`
-  --> $DIR/blacklisted_name.rs:14:9
-   |
-LL |     let foo = 42;
-   |         ^^^
-
-error: use of a blacklisted/placeholder name `baz`
-  --> $DIR/blacklisted_name.rs:15:9
-   |
-LL |     let baz = 42;
-   |         ^^^
-
-error: use of a blacklisted/placeholder name `quux`
-  --> $DIR/blacklisted_name.rs:16:9
-   |
-LL |     let quux = 42;
-   |         ^^^^
-
-error: use of a blacklisted/placeholder name `foo`
-  --> $DIR/blacklisted_name.rs:27:10
-   |
-LL |         (foo, Some(baz), quux @ Some(_)) => (),
-   |          ^^^
-
-error: use of a blacklisted/placeholder name `baz`
-  --> $DIR/blacklisted_name.rs:27:20
-   |
-LL |         (foo, Some(baz), quux @ Some(_)) => (),
-   |                    ^^^
-
-error: use of a blacklisted/placeholder name `quux`
-  --> $DIR/blacklisted_name.rs:27:26
-   |
-LL |         (foo, Some(baz), quux @ Some(_)) => (),
-   |                          ^^^^
-
-error: use of a blacklisted/placeholder name `foo`
-  --> $DIR/blacklisted_name.rs:32:19
-   |
-LL | fn issue_1647(mut foo: u8) {
-   |                   ^^^
-
-error: use of a blacklisted/placeholder name `baz`
-  --> $DIR/blacklisted_name.rs:33:13
-   |
-LL |     let mut baz = 0;
-   |             ^^^
-
-error: use of a blacklisted/placeholder name `quux`
-  --> $DIR/blacklisted_name.rs:34:21
-   |
-LL |     if let Some(mut quux) = Some(42) {}
-   |                     ^^^^
-
-error: use of a blacklisted/placeholder name `baz`
-  --> $DIR/blacklisted_name.rs:38:13
-   |
-LL |     let ref baz = 0;
-   |             ^^^
-
-error: use of a blacklisted/placeholder name `quux`
-  --> $DIR/blacklisted_name.rs:39:21
-   |
-LL |     if let Some(ref quux) = Some(42) {}
-   |                     ^^^^
-
-error: use of a blacklisted/placeholder name `baz`
-  --> $DIR/blacklisted_name.rs:43:17
-   |
-LL |     let ref mut baz = 0;
-   |                 ^^^
-
-error: use of a blacklisted/placeholder name `quux`
-  --> $DIR/blacklisted_name.rs:44:25
-   |
-LL |     if let Some(ref mut quux) = Some(42) {}
-   |                         ^^^^
-
-error: aborting due to 14 previous errors
-
index b606f773cfbad1d603b31df22311e3745d02e515..35ed87b0f182fd921e10ee68394a755b39614301 100644 (file)
@@ -1,5 +1,5 @@
 #![deny(clippy::borrowed_box)]
-#![allow(clippy::blacklisted_name)]
+#![allow(clippy::disallowed_names)]
 #![allow(unused_variables)]
 #![allow(dead_code)]
 
index 2289f7875f04c7007e54cdf1666b5fc820cc01aa..f13733af3d0d18a04244d716541c232c85700347 100644 (file)
@@ -2,6 +2,7 @@
 // As the most common case is the `http` crate, it replicates `http::HeadewrName`'s structure.
 
 #![allow(clippy::declare_interior_mutable_const)]
+#![allow(unused_tuple_struct_fields)]
 
 use std::sync::atomic::AtomicUsize;
 
index 1a74cdb3ff65926ab94e679bdcbea64d4e51db0f..0780c8f0586e0a4740754920ff3d783226b2d22f 100644 (file)
@@ -2,7 +2,7 @@
 #![allow(
     clippy::boxed_local,
     clippy::needless_pass_by_value,
-    clippy::blacklisted_name,
+    clippy::disallowed_names,
     unused
 )]
 
index a68b32b097e85ae9c0d0877e9b67c4d18bd501ee..7ecefd7b13439f5e7df85c5ad3fff049371be523 100644 (file)
@@ -26,4 +26,6 @@ fn main() {
     let _ = a.unsigned_abs() as u32;
     let _ = a.unsigned_abs() as u64;
     let _ = a.unsigned_abs() as u128;
+
+    let _ = (x as i64 - y as i64).unsigned_abs() as u32;
 }
index 110fbc6c2dfb637db23f49fd96e0b136e2bbd2bb..30c603fca9a149265ac7d4b0d5a43d9811a71c9b 100644 (file)
@@ -26,4 +26,6 @@ fn main() {
     let _ = a.abs() as u32;
     let _ = a.abs() as u64;
     let _ = a.abs() as u128;
+
+    let _ = (x as i64 - y as i64).abs() as u32;
 }
index 02c24e10659aceb8a94a3d652f16156241e849cd..0455377452676fe855f8994121c3309b1517dc08 100644 (file)
@@ -96,5 +96,11 @@ error: casting the result of `isize::abs()` to u128
 LL |     let _ = a.abs() as u128;
    |             ^^^^^^^ help: replace with: `a.unsigned_abs()`
 
-error: aborting due to 16 previous errors
+error: casting the result of `i64::abs()` to u32
+  --> $DIR/cast_abs_to_unsigned.rs:30:13
+   |
+LL |     let _ = (x as i64 - y as i64).abs() as u32;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `(x as i64 - y as i64).unsigned_abs()`
+
+error: aborting due to 17 previous errors
 
index dc062762604e063a4d1dac5f9554a7276898e65e..72b1222709819447cd8a4589f6e9c92a7dbc546a 100644 (file)
@@ -21,7 +21,7 @@ fn is_ascii(ch: char) -> bool {
     ch.is_ascii()
 }
 
-fn clone_on_copy() {
+fn clone_on_copy() -> Option<(i32)> {
     42;
 
     vec![1].clone(); // ok, not a Copy type
@@ -71,4 +71,9 @@ fn clone_on_copy() {
     // Issue #5436
     let mut vec = Vec::new();
     vec.push(42);
+
+    //  Issue #9277
+    let opt: &Option<i32> = &None;
+    let value = (*opt)?; // operator precedence needed (*opt)?
+    None
 }
index 8c39d0d55dd8bdbf23e48a37bdd194bbd930cc6b..03e210ebad98c302819ab8b8ed9c5426fa9a6a34 100644 (file)
@@ -21,7 +21,7 @@ fn is_ascii(ch: char) -> bool {
     ch.is_ascii()
 }
 
-fn clone_on_copy() {
+fn clone_on_copy() -> Option<(i32)> {
     42.clone();
 
     vec![1].clone(); // ok, not a Copy type
@@ -71,4 +71,9 @@ impl core::ops::Deref for Wrap {
     // Issue #5436
     let mut vec = Vec::new();
     vec.push(42.clone());
+
+    //  Issue #9277
+    let opt: &Option<i32> = &None;
+    let value = opt.clone()?; // operator precedence needed (*opt)?
+    None
 }
index 861543d0aa904566aac464ca4071ddd23aee4153..42ae227777c7082a20849bfb489b2332850a6ac9 100644 (file)
@@ -48,5 +48,11 @@ error: using `clone` on type `i32` which implements the `Copy` trait
 LL |     vec.push(42.clone());
    |              ^^^^^^^^^^ help: try removing the `clone` call: `42`
 
-error: aborting due to 8 previous errors
+error: using `clone` on type `std::option::Option<i32>` which implements the `Copy` trait
+  --> $DIR/clone_on_copy.rs:77:17
+   |
+LL |     let value = opt.clone()?; // operator precedence needed (*opt)?
+   |                 ^^^^^^^^^^^ help: try dereferencing it: `(*opt)`
+
+error: aborting due to 9 previous errors
 
index f1a229f3f4faf3a706ee0e721ad6c26b973b6135..61ef24804986ef82682f7c7b23bc48d8d4cfefcf 100644 (file)
@@ -1,6 +1,6 @@
 #![allow(
     unused_variables,
-    clippy::blacklisted_name,
+    clippy::disallowed_names,
     clippy::needless_pass_by_value,
     dead_code
 )]
index 02c49aa0d7c1f4a0e9e8d2dd22c49cedbd9b2c88..b402052882adc3010d82788392092cafec2dbdcd 100644 (file)
@@ -1,5 +1,5 @@
 #![warn(clippy::all)]
-#![allow(clippy::blacklisted_name, clippy::equatable_if_let)]
+#![allow(clippy::disallowed_names, clippy::equatable_if_let)]
 #![allow(unused)]
 
 /// Test for https://github.com/rust-lang/rust-clippy/issues/3462
index 6f9d98bbfe7f341b8b166800314b77495ba0697a..55a8b403407cd8039f97303fc190cb0fea67fa71 100644 (file)
@@ -1,4 +1,4 @@
-#![allow(clippy::blacklisted_name)]
+#![allow(clippy::disallowed_names)]
 
 pub fn foo(bar: *const u8) {
     println!("{:#p}", bar);
index 156c88e2e45b7d902e8dc3fa3f28f083210c2758..a7da8f89aa3d45e6abcafb37876d5051732d69b6 100644 (file)
@@ -1,4 +1,3 @@
-// ignore-windows
 // ignore-macos
 
 #![feature(no_core, lang_items, start)]
index 40d355e9a2e3e871bbe730bb01b6e4e440652bf3..6210d7c6cfd80c1d32369494f3010694b606dc65 100644 (file)
@@ -1,5 +1,5 @@
 error: methods called `as_*` usually take `self` by reference or `self` by mutable reference
-  --> $DIR/def_id_nocore.rs:28:19
+  --> $DIR/def_id_nocore.rs:27:19
    |
 LL |     pub fn as_ref(self) -> &'static str {
    |                   ^^^^
index 264dd4efaeb8699648f3818c20f845704ac963c9..fce66eb175963ee4b78247e85e5d12545567dbcb 100644 (file)
@@ -1,8 +1,12 @@
 // run-rustfix
+// aux-build: proc_macro_with_span.rs
 
 #![allow(unused_imports, dead_code)]
 #![deny(clippy::default_trait_access)]
 
+extern crate proc_macro_with_span;
+
+use proc_macro_with_span::with_span;
 use std::default;
 use std::default::Default as D2;
 use std::string;
@@ -51,6 +55,8 @@ fn main() {
         ..Default::default()
     };
 
+    let _s21: String = with_span!(s Default::default());
+
     println!(
         "[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}]",
         s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16, s17, s18, s19, s20,
index a0930fab8e7c89db4214ab966975f9dd0381c506..3e8e898b7bc61aa8311ae64e29059105747af577 100644 (file)
@@ -1,8 +1,12 @@
 // run-rustfix
+// aux-build: proc_macro_with_span.rs
 
 #![allow(unused_imports, dead_code)]
 #![deny(clippy::default_trait_access)]
 
+extern crate proc_macro_with_span;
+
+use proc_macro_with_span::with_span;
 use std::default;
 use std::default::Default as D2;
 use std::string;
@@ -51,6 +55,8 @@ fn main() {
         ..Default::default()
     };
 
+    let _s21: String = with_span!(s Default::default());
+
     println!(
         "[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}]",
         s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16, s17, s18, s19, s20,
index df8a5b94ddcf3c81468744a3263fdd0b316964c5..3493de37a55be55beb0d9d736bd2ea6a882581c2 100644 (file)
@@ -1,53 +1,53 @@
 error: calling `std::string::String::default()` is more clear than this expression
-  --> $DIR/default_trait_access.rs:11:22
+  --> $DIR/default_trait_access.rs:15:22
    |
 LL |     let s1: String = Default::default();
    |                      ^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()`
    |
 note: the lint level is defined here
-  --> $DIR/default_trait_access.rs:4:9
+  --> $DIR/default_trait_access.rs:5:9
    |
 LL | #![deny(clippy::default_trait_access)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: calling `std::string::String::default()` is more clear than this expression
-  --> $DIR/default_trait_access.rs:15:22
+  --> $DIR/default_trait_access.rs:19:22
    |
 LL |     let s3: String = D2::default();
    |                      ^^^^^^^^^^^^^ help: try: `std::string::String::default()`
 
 error: calling `std::string::String::default()` is more clear than this expression
-  --> $DIR/default_trait_access.rs:17:22
+  --> $DIR/default_trait_access.rs:21:22
    |
 LL |     let s4: String = std::default::Default::default();
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()`
 
 error: calling `std::string::String::default()` is more clear than this expression
-  --> $DIR/default_trait_access.rs:21:22
+  --> $DIR/default_trait_access.rs:25:22
    |
 LL |     let s6: String = default::Default::default();
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()`
 
 error: calling `GenericDerivedDefault::default()` is more clear than this expression
-  --> $DIR/default_trait_access.rs:31:46
+  --> $DIR/default_trait_access.rs:35:46
    |
 LL |     let s11: GenericDerivedDefault<String> = Default::default();
    |                                              ^^^^^^^^^^^^^^^^^^ help: try: `GenericDerivedDefault::default()`
 
 error: calling `TupleDerivedDefault::default()` is more clear than this expression
-  --> $DIR/default_trait_access.rs:37:36
+  --> $DIR/default_trait_access.rs:41:36
    |
 LL |     let s14: TupleDerivedDefault = Default::default();
    |                                    ^^^^^^^^^^^^^^^^^^ help: try: `TupleDerivedDefault::default()`
 
 error: calling `ArrayDerivedDefault::default()` is more clear than this expression
-  --> $DIR/default_trait_access.rs:39:36
+  --> $DIR/default_trait_access.rs:43:36
    |
 LL |     let s15: ArrayDerivedDefault = Default::default();
    |                                    ^^^^^^^^^^^^^^^^^^ help: try: `ArrayDerivedDefault::default()`
 
 error: calling `TupleStructDerivedDefault::default()` is more clear than this expression
-  --> $DIR/default_trait_access.rs:43:42
+  --> $DIR/default_trait_access.rs:47:42
    |
 LL |     let s17: TupleStructDerivedDefault = Default::default();
    |                                          ^^^^^^^^^^^^^^^^^^ help: try: `TupleStructDerivedDefault::default()`
diff --git a/src/tools/clippy/tests/ui/disallowed_names.rs b/src/tools/clippy/tests/ui/disallowed_names.rs
new file mode 100644 (file)
index 0000000..e937c49
--- /dev/null
@@ -0,0 +1,57 @@
+#![allow(
+    dead_code,
+    clippy::similar_names,
+    clippy::single_match,
+    clippy::toplevel_ref_arg,
+    unused_mut,
+    unused_variables
+)]
+#![warn(clippy::disallowed_names)]
+
+fn test(foo: ()) {}
+
+fn main() {
+    let foo = 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 food = 42;
+    let foodstuffs = 42;
+    let bazaar = 42;
+
+    match (42, Some(1337), Some(0)) {
+        (foo, Some(baz), quux @ Some(_)) => (),
+        _ => (),
+    }
+}
+
+fn issue_1647(mut foo: u8) {
+    let mut baz = 0;
+    if let Some(mut quux) = Some(42) {}
+}
+
+fn issue_1647_ref() {
+    let ref baz = 0;
+    if let Some(ref quux) = Some(42) {}
+}
+
+fn issue_1647_ref_mut() {
+    let ref mut baz = 0;
+    if let Some(ref mut quux) = Some(42) {}
+}
+
+mod tests {
+    fn issue_7305() {
+        // `disallowed_names` lint should not be triggered inside of the test code.
+        let foo = 0;
+
+        // Check that even in nested functions warning is still not triggered.
+        fn nested() {
+            let foo = 0;
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/disallowed_names.stderr b/src/tools/clippy/tests/ui/disallowed_names.stderr
new file mode 100644 (file)
index 0000000..78cb550
--- /dev/null
@@ -0,0 +1,88 @@
+error: use of a disallowed/placeholder name `foo`
+  --> $DIR/disallowed_names.rs:11:9
+   |
+LL | fn test(foo: ()) {}
+   |         ^^^
+   |
+   = note: `-D clippy::disallowed-names` implied by `-D warnings`
+
+error: use of a disallowed/placeholder name `foo`
+  --> $DIR/disallowed_names.rs:14:9
+   |
+LL |     let foo = 42;
+   |         ^^^
+
+error: use of a disallowed/placeholder name `baz`
+  --> $DIR/disallowed_names.rs:15:9
+   |
+LL |     let baz = 42;
+   |         ^^^
+
+error: use of a disallowed/placeholder name `quux`
+  --> $DIR/disallowed_names.rs:16:9
+   |
+LL |     let quux = 42;
+   |         ^^^^
+
+error: use of a disallowed/placeholder name `foo`
+  --> $DIR/disallowed_names.rs:27:10
+   |
+LL |         (foo, Some(baz), quux @ Some(_)) => (),
+   |          ^^^
+
+error: use of a disallowed/placeholder name `baz`
+  --> $DIR/disallowed_names.rs:27:20
+   |
+LL |         (foo, Some(baz), quux @ Some(_)) => (),
+   |                    ^^^
+
+error: use of a disallowed/placeholder name `quux`
+  --> $DIR/disallowed_names.rs:27:26
+   |
+LL |         (foo, Some(baz), quux @ Some(_)) => (),
+   |                          ^^^^
+
+error: use of a disallowed/placeholder name `foo`
+  --> $DIR/disallowed_names.rs:32:19
+   |
+LL | fn issue_1647(mut foo: u8) {
+   |                   ^^^
+
+error: use of a disallowed/placeholder name `baz`
+  --> $DIR/disallowed_names.rs:33:13
+   |
+LL |     let mut baz = 0;
+   |             ^^^
+
+error: use of a disallowed/placeholder name `quux`
+  --> $DIR/disallowed_names.rs:34:21
+   |
+LL |     if let Some(mut quux) = Some(42) {}
+   |                     ^^^^
+
+error: use of a disallowed/placeholder name `baz`
+  --> $DIR/disallowed_names.rs:38:13
+   |
+LL |     let ref baz = 0;
+   |             ^^^
+
+error: use of a disallowed/placeholder name `quux`
+  --> $DIR/disallowed_names.rs:39:21
+   |
+LL |     if let Some(ref quux) = Some(42) {}
+   |                     ^^^^
+
+error: use of a disallowed/placeholder name `baz`
+  --> $DIR/disallowed_names.rs:43:17
+   |
+LL |     let ref mut baz = 0;
+   |                 ^^^
+
+error: use of a disallowed/placeholder name `quux`
+  --> $DIR/disallowed_names.rs:44:25
+   |
+LL |     if let Some(ref mut quux) = Some(42) {}
+   |                         ^^^^
+
+error: aborting due to 14 previous errors
+
index e27f9fea708ee16c0bcfd889cf27ad6ed7b39b8d..e8f992e6ddedbff2d27ffa3c27ca4301b21c3ddc 100644 (file)
@@ -1,5 +1,5 @@
 #![warn(clippy::diverging_sub_expression)]
-#![allow(clippy::match_same_arms, clippy::logic_bug)]
+#![allow(clippy::match_same_arms, clippy::overly_complex_bool_expr)]
 #[allow(clippy::empty_loop)]
 fn diverge() -> ! {
     loop {}
index 235e0fc51799fad3d001e5b80cb54c481e164d77..e742b396fcde080256206a9523a65281e788e636 100644 (file)
@@ -1,6 +1,5 @@
 // compile-flags: -Clink-arg=-nostartfiles
 // ignore-macos
-// ignore-windows
 
 #![warn(clippy::empty_loop)]
 #![feature(lang_items, start, libc)]
index 520248fcb689c4e52b3a39c65873f0e2fc4d547d..5ded35a6f0d8da3f4a88eaf9415d181178d035ba 100644 (file)
@@ -1,5 +1,5 @@
 error: empty `loop {}` wastes CPU cycles
-  --> $DIR/empty_loop_no_std.rs:14:5
+  --> $DIR/empty_loop_no_std.rs:13:5
    |
 LL |     loop {}
    |     ^^^^^^^
@@ -8,7 +8,7 @@ LL |     loop {}
    = help: you should either use `panic!()` or add a call pausing or sleeping the thread to the loop body
 
 error: empty `loop {}` wastes CPU cycles
-  --> $DIR/empty_loop_no_std.rs:26:5
+  --> $DIR/empty_loop_no_std.rs:25:5
    |
 LL |     loop {}
    |     ^^^^^^^
index 9d3fc7df15cc7a9de6f73efca2de52e3f4a93a3c..ab28aac45563b1cd7bfd3192ad5b192f86638451 100644 (file)
@@ -5,7 +5,7 @@ LL |     let _ = opt.expect("");
    |             ^^^^^^^^^^^^^^
    |
    = note: `-D clippy::expect-used` implied by `-D warnings`
-   = help: if this value is an `None`, it will panic
+   = help: if this value is `None`, it will panic
 
 error: used `expect()` on `a Result` value
   --> $DIR/expect.rs:10:13
index 28b37f96e9118138918ce22f36a59e1eabe7c972..0415e33b3fa1017fabc10e63c4ae43bea086a557 100644 (file)
@@ -98,7 +98,7 @@ fn baz() {
         let _ = if true { 42 } else { 42 };
     }
 
-    #[expect(clippy::logic_bug)]
+    #[expect(clippy::overly_complex_bool_expr)]
     fn burger() {
         let a = false;
         let b = true;
@@ -127,7 +127,7 @@ fn baz() {
         let _ = if true { 33 } else { 42 };
     }
 
-    #[expect(clippy::logic_bug)]
+    #[expect(clippy::overly_complex_bool_expr)]
     fn burger() {
         let a = false;
         let b = true;
index db29e85a82191abf6529511704d4fb83f6725fb6..7ce9e855b5e05579ee69a46a6d91d10eec93470d 100644 (file)
@@ -33,8 +33,8 @@ LL |     #[expect(clippy::if_same_then_else)]
 error: this lint expectation is unfulfilled
   --> $DIR/expect_tool_lint_rfc_2383.rs:130:14
    |
-LL |     #[expect(clippy::logic_bug)]
-   |              ^^^^^^^^^^^^^^^^^
+LL |     #[expect(clippy::overly_complex_bool_expr)]
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 6 previous errors
 
index a650fdc1f897256ab98026823f52aaeec250c19e..d1d35e5c0eb46f493aaa3c7b07fdda965be3bef4 100644 (file)
@@ -1,5 +1,6 @@
 // run-rustfix
 
+#![feature(closure_lifetime_binder)]
 #![warn(clippy::explicit_auto_deref)]
 #![allow(
     dead_code,
@@ -67,6 +68,8 @@ fn main() {
     let s = String::new();
 
     let _: &str = &s;
+    let _: &str = &{ String::new() };
+    let _: &str = &mut { String::new() };
     let _ = &*s; // Don't lint. Inferred type would change.
     let _: &_ = &*s; // Don't lint. Inferred type would change.
 
@@ -215,4 +218,52 @@ fn main() {
     let s = &"str";
     let _ = || return *s;
     let _ = || -> &'static str { return s };
+
+    struct X;
+    struct Y(X);
+    impl core::ops::Deref for Y {
+        type Target = X;
+        fn deref(&self) -> &Self::Target {
+            &self.0
+        }
+    }
+    let _: &X = &*{ Y(X) };
+    let _: &X = &*match 0 {
+        #[rustfmt::skip]
+        0 => { Y(X) },
+        _ => panic!(),
+    };
+    let _: &X = &*if true { Y(X) } else { panic!() };
+
+    fn deref_to_u<U, T: core::ops::Deref<Target = U>>(x: &T) -> &U {
+        x
+    }
+
+    let _ = |x: &'static Box<dyn Iterator<Item = u32>>| -> &'static dyn Iterator<Item = u32> { &**x };
+    fn ret_any(x: &Box<dyn std::any::Any>) -> &dyn std::any::Any {
+        &**x
+    }
+
+    let x = String::new();
+    let _: *const str = &*x;
+
+    struct S7([u32; 1]);
+    impl core::ops::Deref for S7 {
+        type Target = [u32; 1];
+        fn deref(&self) -> &Self::Target {
+            &self.0
+        }
+    }
+    let x = S7([0]);
+    let _: &[u32] = &*x;
+
+    let c1 = |_: &Vec<&u32>| {};
+    let x = &&vec![&1u32];
+    c1(x);
+    let _ = for<'a, 'b> |x: &'a &'a Vec<&'b u32>, b: bool| -> &'a Vec<&'b u32> {
+        if b {
+            return x;
+        }
+        x
+    };
 }
index 8f4f352576a734514f2648b826205efc4eb219e9..deedafad153b97ae0edd6d777637516d65c33410 100644 (file)
@@ -1,5 +1,6 @@
 // run-rustfix
 
+#![feature(closure_lifetime_binder)]
 #![warn(clippy::explicit_auto_deref)]
 #![allow(
     dead_code,
@@ -67,6 +68,8 @@ fn main() {
     let s = String::new();
 
     let _: &str = &*s;
+    let _: &str = &*{ String::new() };
+    let _: &str = &mut *{ String::new() };
     let _ = &*s; // Don't lint. Inferred type would change.
     let _: &_ = &*s; // Don't lint. Inferred type would change.
 
@@ -215,4 +218,52 @@ fn _f5(x: &u32) -> u32 {
     let s = &"str";
     let _ = || return *s;
     let _ = || -> &'static str { return *s };
+
+    struct X;
+    struct Y(X);
+    impl core::ops::Deref for Y {
+        type Target = X;
+        fn deref(&self) -> &Self::Target {
+            &self.0
+        }
+    }
+    let _: &X = &*{ Y(X) };
+    let _: &X = &*match 0 {
+        #[rustfmt::skip]
+        0 => { Y(X) },
+        _ => panic!(),
+    };
+    let _: &X = &*if true { Y(X) } else { panic!() };
+
+    fn deref_to_u<U, T: core::ops::Deref<Target = U>>(x: &T) -> &U {
+        &**x
+    }
+
+    let _ = |x: &'static Box<dyn Iterator<Item = u32>>| -> &'static dyn Iterator<Item = u32> { &**x };
+    fn ret_any(x: &Box<dyn std::any::Any>) -> &dyn std::any::Any {
+        &**x
+    }
+
+    let x = String::new();
+    let _: *const str = &*x;
+
+    struct S7([u32; 1]);
+    impl core::ops::Deref for S7 {
+        type Target = [u32; 1];
+        fn deref(&self) -> &Self::Target {
+            &self.0
+        }
+    }
+    let x = S7([0]);
+    let _: &[u32] = &*x;
+
+    let c1 = |_: &Vec<&u32>| {};
+    let x = &&vec![&1u32];
+    c1(*x);
+    let _ = for<'a, 'b> |x: &'a &'a Vec<&'b u32>, b: bool| -> &'a Vec<&'b u32> {
+        if b {
+            return *x;
+        }
+        *x
+    };
 }
index 92765307ea73d55f30a30ecdbc984ba42a645066..91863abcc5d2436cb297493c45c8f88a74e88703 100644 (file)
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:69:20
+  --> $DIR/explicit_auto_deref.rs:70:19
    |
 LL |     let _: &str = &*s;
-   |                    ^^ help: try this: `s`
+   |                   ^^^ help: try this: `&s`
    |
    = note: `-D clippy::explicit-auto-deref` implied by `-D warnings`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:73:12
+  --> $DIR/explicit_auto_deref.rs:71:19
+   |
+LL |     let _: &str = &*{ String::new() };
+   |                   ^^^^^^^^^^^^^^^^^^^ help: try this: `&{ String::new() }`
+
+error: deref which would be done by auto-deref
+  --> $DIR/explicit_auto_deref.rs:72:19
+   |
+LL |     let _: &str = &mut *{ String::new() };
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&mut { String::new() }`
+
+error: deref which would be done by auto-deref
+  --> $DIR/explicit_auto_deref.rs:76:11
    |
 LL |     f_str(&*s);
-   |            ^^ help: try this: `s`
+   |           ^^^ help: try this: `&s`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:77:14
+  --> $DIR/explicit_auto_deref.rs:80:13
    |
 LL |     f_str_t(&*s, &*s); // Don't lint second param.
-   |              ^^ help: try this: `s`
+   |             ^^^ help: try this: `&s`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:80:25
+  --> $DIR/explicit_auto_deref.rs:83:24
    |
 LL |     let _: &Box<i32> = &**b;
-   |                         ^^^ help: try this: `b`
+   |                        ^^^^ help: try this: `&b`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:86:8
+  --> $DIR/explicit_auto_deref.rs:89:7
    |
 LL |     c(&*s);
-   |        ^^ help: try this: `s`
+   |       ^^^ help: try this: `&s`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:92:9
+  --> $DIR/explicit_auto_deref.rs:95:9
    |
 LL |         &**x
    |         ^^^^ help: try this: `x`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:96:11
+  --> $DIR/explicit_auto_deref.rs:99:11
    |
 LL |         { &**x }
    |           ^^^^ help: try this: `x`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:100:9
+  --> $DIR/explicit_auto_deref.rs:103:9
    |
 LL |         &**{ x }
    |         ^^^^^^^^ help: try this: `{ x }`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:104:9
+  --> $DIR/explicit_auto_deref.rs:107:9
    |
 LL |         &***x
    |         ^^^^^ help: try this: `x`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:121:13
+  --> $DIR/explicit_auto_deref.rs:124:12
    |
 LL |         f1(&*x);
-   |             ^^ help: try this: `x`
+   |            ^^^ help: try this: `&x`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:122:13
+  --> $DIR/explicit_auto_deref.rs:125:12
    |
 LL |         f2(&*x);
-   |             ^^ help: try this: `x`
+   |            ^^^ help: try this: `&x`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:123:13
+  --> $DIR/explicit_auto_deref.rs:126:12
    |
 LL |         f3(&*x);
-   |             ^^ help: try this: `x`
+   |            ^^^ help: try this: `&x`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:124:28
+  --> $DIR/explicit_auto_deref.rs:127:27
    |
 LL |         f4.callable_str()(&*x);
-   |                            ^^ help: try this: `x`
+   |                           ^^^ help: try this: `&x`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:125:13
+  --> $DIR/explicit_auto_deref.rs:128:12
    |
 LL |         f5(&*x);
-   |             ^^ help: try this: `x`
+   |            ^^^ help: try this: `&x`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:126:13
+  --> $DIR/explicit_auto_deref.rs:129:12
    |
 LL |         f6(&*x);
-   |             ^^ help: try this: `x`
+   |            ^^^ help: try this: `&x`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:127:28
+  --> $DIR/explicit_auto_deref.rs:130:27
    |
 LL |         f7.callable_str()(&*x);
-   |                            ^^ help: try this: `x`
+   |                           ^^^ help: try this: `&x`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:128:26
+  --> $DIR/explicit_auto_deref.rs:131:25
    |
 LL |         f8.callable_t()(&*x);
-   |                          ^^ help: try this: `x`
+   |                         ^^^ help: try this: `&x`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:129:13
+  --> $DIR/explicit_auto_deref.rs:132:12
    |
 LL |         f9(&*x);
-   |             ^^ help: try this: `x`
+   |            ^^^ help: try this: `&x`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:130:14
+  --> $DIR/explicit_auto_deref.rs:133:13
    |
 LL |         f10(&*x);
-   |              ^^ help: try this: `x`
+   |             ^^^ help: try this: `&x`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:131:27
+  --> $DIR/explicit_auto_deref.rs:134:26
    |
 LL |         f11.callable_t()(&*x);
-   |                           ^^ help: try this: `x`
+   |                          ^^^ help: try this: `&x`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:135:17
+  --> $DIR/explicit_auto_deref.rs:138:16
    |
 LL |     let _ = S1(&*s);
-   |                 ^^ help: try this: `s`
+   |                ^^^ help: try this: `&s`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:140:22
+  --> $DIR/explicit_auto_deref.rs:143:21
    |
 LL |     let _ = S2 { s: &*s };
-   |                      ^^ help: try this: `s`
+   |                     ^^^ help: try this: `&s`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:156:30
+  --> $DIR/explicit_auto_deref.rs:159:30
    |
 LL |             let _ = Self::S1(&**s);
    |                              ^^^^ help: try this: `s`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:157:35
+  --> $DIR/explicit_auto_deref.rs:160:35
    |
 LL |             let _ = Self::S2 { s: &**s };
    |                                   ^^^^ help: try this: `s`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:160:21
+  --> $DIR/explicit_auto_deref.rs:163:20
    |
 LL |     let _ = E1::S1(&*s);
-   |                     ^^ help: try this: `s`
+   |                    ^^^ help: try this: `&s`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:161:26
+  --> $DIR/explicit_auto_deref.rs:164:25
    |
 LL |     let _ = E1::S2 { s: &*s };
-   |                          ^^ help: try this: `s`
+   |                         ^^^ help: try this: `&s`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:179:13
+  --> $DIR/explicit_auto_deref.rs:182:13
    |
 LL |     let _ = (*b).foo;
    |             ^^^^ help: try this: `b`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:180:13
+  --> $DIR/explicit_auto_deref.rs:183:13
    |
 LL |     let _ = (**b).foo;
    |             ^^^^^ help: try this: `b`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:195:19
+  --> $DIR/explicit_auto_deref.rs:198:19
    |
 LL |     let _ = f_str(*ref_str);
    |                   ^^^^^^^^ help: try this: `ref_str`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:197:19
+  --> $DIR/explicit_auto_deref.rs:200:19
    |
 LL |     let _ = f_str(**ref_ref_str);
    |                   ^^^^^^^^^^^^^ help: try this: `ref_ref_str`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:207:13
+  --> $DIR/explicit_auto_deref.rs:210:13
    |
 LL |     f_str(&&*ref_str); // `needless_borrow` will suggest removing both references
    |             ^^^^^^^^ help: try this: `ref_str`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:208:12
+  --> $DIR/explicit_auto_deref.rs:211:12
    |
 LL |     f_str(&&**ref_str); // `needless_borrow` will suggest removing only one reference
    |            ^^^^^^^^^^ help: try this: `ref_str`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:217:41
+  --> $DIR/explicit_auto_deref.rs:220:41
    |
 LL |     let _ = || -> &'static str { return *s };
    |                                         ^^ help: try this: `s`
 
-error: aborting due to 33 previous errors
+error: deref which would be done by auto-deref
+  --> $DIR/explicit_auto_deref.rs:239:9
+   |
+LL |         &**x
+   |         ^^^^ help: try this: `x`
+
+error: deref which would be done by auto-deref
+  --> $DIR/explicit_auto_deref.rs:262:8
+   |
+LL |     c1(*x);
+   |        ^^ help: try this: `x`
+
+error: deref which would be done by auto-deref
+  --> $DIR/explicit_auto_deref.rs:265:20
+   |
+LL |             return *x;
+   |                    ^^ help: try this: `x`
+
+error: deref which would be done by auto-deref
+  --> $DIR/explicit_auto_deref.rs:267:9
+   |
+LL |         *x
+   |         ^^ help: try this: `x`
+
+error: aborting due to 39 previous errors
 
index f4db2d20c713c0b4dc1d83591e6b6eceb00fe7cc..6b754f3bd7103bb3f6ff068ab637acc368f85c7c 100644 (file)
@@ -1,6 +1,7 @@
 // run-rustfix
 
 #![allow(
+    unused_tuple_struct_fields,
     clippy::print_literal,
     clippy::redundant_clone,
     clippy::to_string_in_format_args,
index bf687cb1e96c79cf864252d9ec156f80597345fd..ca9826b356ec8aea1642450c6f3789244323f071 100644 (file)
@@ -1,6 +1,7 @@
 // run-rustfix
 
 #![allow(
+    unused_tuple_struct_fields,
     clippy::print_literal,
     clippy::redundant_clone,
     clippy::to_string_in_format_args,
index a0f8e7d19379110b1ffef5a8f7a82389421c795a..6c35caeb034d0fe5e817b2c51700a771dd68666d 100644 (file)
@@ -1,5 +1,5 @@
 error: useless use of `format!`
-  --> $DIR/format.rs:18:5
+  --> $DIR/format.rs:19:5
    |
 LL |     format!("foo");
    |     ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
@@ -7,19 +7,19 @@ LL |     format!("foo");
    = note: `-D clippy::useless-format` implied by `-D warnings`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:19:5
+  --> $DIR/format.rs:20:5
    |
 LL |     format!("{{}}");
    |     ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{}".to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:20:5
+  --> $DIR/format.rs:21:5
    |
 LL |     format!("{{}} abc {{}}");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{} abc {}".to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:21:5
+  --> $DIR/format.rs:22:5
    |
 LL | /     format!(
 LL | |         r##"foo {{}}
@@ -34,91 +34,91 @@ LL ~ " bar"##.to_string();
    |
 
 error: useless use of `format!`
-  --> $DIR/format.rs:26:13
+  --> $DIR/format.rs:27:13
    |
 LL |     let _ = format!("");
    |             ^^^^^^^^^^^ help: consider using `String::new()`: `String::new()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:28:5
+  --> $DIR/format.rs:29:5
    |
 LL |     format!("{}", "foo");
    |     ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:32:5
+  --> $DIR/format.rs:33:5
    |
 LL |     format!("{:+}", "foo"); // Warn when the format makes no difference.
    |     ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:33:5
+  --> $DIR/format.rs:34:5
    |
 LL |     format!("{:<}", "foo"); // Warn when the format makes no difference.
    |     ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:38:5
+  --> $DIR/format.rs:39:5
    |
 LL |     format!("{}", arg);
    |     ^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:42:5
+  --> $DIR/format.rs:43:5
    |
 LL |     format!("{:+}", arg); // Warn when the format makes no difference.
    |     ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:43:5
+  --> $DIR/format.rs:44:5
    |
 LL |     format!("{:<}", arg); // Warn when the format makes no difference.
    |     ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:70:5
+  --> $DIR/format.rs:71:5
    |
 LL |     format!("{}", 42.to_string());
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `42.to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:72:5
+  --> $DIR/format.rs:73:5
    |
 LL |     format!("{}", x.display().to_string());
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.display().to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:76:18
+  --> $DIR/format.rs:77:18
    |
 LL |     let _ = Some(format!("{}", a + "bar"));
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `a + "bar"`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:80:22
+  --> $DIR/format.rs:81:22
    |
 LL |     let _s: String = format!("{}", &*v.join("/n"));
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `(&*v.join("/n")).to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:86:13
+  --> $DIR/format.rs:87:13
    |
 LL |     let _ = format!("{x}");
    |             ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:88:13
+  --> $DIR/format.rs:89:13
    |
 LL |     let _ = format!("{y}", y = x);
    |             ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:92:13
+  --> $DIR/format.rs:93:13
    |
 LL |     let _ = format!("{abc}");
    |             ^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `abc.to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:94:13
+  --> $DIR/format.rs:95:13
    |
 LL |     let _ = format!("{xx}");
    |             ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `xx.to_string()`
index 403c3b3e44380ef3a971ab36504d48b2bd0537bb..48f8093311cbdb41ad7c1700873457cb1154a8be 100644 (file)
@@ -1,7 +1,7 @@
 // run-rustfix
 
 #![warn(clippy::from_iter_instead_of_collect)]
-#![allow(unused_imports)]
+#![allow(unused_imports, unused_tuple_struct_fields)]
 
 use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque};
 
index fefc7b01a65bbaebf786046d5406f99d414d500c..ebe0ad278be30f9502a29aade0f99821092f37fe 100644 (file)
@@ -1,7 +1,7 @@
 // run-rustfix
 
 #![warn(clippy::from_iter_instead_of_collect)]
-#![allow(unused_imports)]
+#![allow(unused_imports, unused_tuple_struct_fields)]
 
 use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque};
 
index 2598c2ab426d31fbf46d770da687bff9f2bcda2e..07d2002eb27f83d1482c0004282d88d9ae3398a3 100644 (file)
@@ -1,6 +1,6 @@
 #![warn(clippy::if_same_then_else)]
 #![allow(
-    clippy::blacklisted_name,
+    clippy::disallowed_names,
     clippy::eq_op,
     clippy::never_loop,
     clippy::no_effect,
index 0016009a02f5858b39461dba03a777ba713ebf39..58167f4446dba86a8614b6af3ca3db0160220b83 100644 (file)
@@ -1,6 +1,6 @@
 #![warn(clippy::if_same_then_else)]
 #![allow(
-    clippy::blacklisted_name,
+    clippy::disallowed_names,
     clippy::collapsible_else_if,
     clippy::equatable_if_let,
     clippy::collapsible_if,
index 80e9839ff40bd30df3bfdfaec456c1d44aa8154e..9850fc0919e12b76d78fc709353484d809a00ba8 100644 (file)
@@ -32,9 +32,9 @@ fn ifs_same_cond() {
     };
 
     let mut v = vec![1];
-    if v.pop() == None {
+    if v.pop().is_none() {
         // ok, functions
-    } else if v.pop() == None {
+    } else if v.pop().is_none() {
     }
 
     if v.len() == 42 {
index 2db4c2bee7f2bc62db61af4877891a091dcba504..d56d623b5268e9a06b15495e58e6ca47924ce9d5 100644 (file)
@@ -2,7 +2,7 @@
 // aux-build:option_helpers.rs
 
 #![warn(clippy::iter_skip_next)]
-#![allow(clippy::blacklisted_name)]
+#![allow(clippy::disallowed_names)]
 #![allow(clippy::iter_nth)]
 #![allow(unused_mut, dead_code)]
 
index 692edb9aed9396386c1a04cc1e97d6725e337871..3ec5d1b82142671f8d5409d111fd78827a305db9 100644 (file)
@@ -2,7 +2,7 @@
 // aux-build:option_helpers.rs
 
 #![warn(clippy::iter_skip_next)]
-#![allow(clippy::blacklisted_name)]
+#![allow(clippy::disallowed_names)]
 #![allow(clippy::iter_nth)]
 #![allow(unused_mut, dead_code)]
 
index c5cb2eb1fe1c2e66a727e317a0a13ffa169b8df2..959567f686703176ca41dff403c0e37c27a60ea1 100644 (file)
@@ -2,7 +2,7 @@
     unused_variables,
     unused_assignments,
     clippy::similar_names,
-    clippy::blacklisted_name,
+    clippy::disallowed_names,
     clippy::branches_sharing_code,
     clippy::needless_late_init
 )]
diff --git a/src/tools/clippy/tests/ui/logic_bug.rs b/src/tools/clippy/tests/ui/logic_bug.rs
deleted file mode 100644 (file)
index dd6b1db..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-#![feature(lint_reasons)]
-#![allow(unused, clippy::diverging_sub_expression)]
-#![warn(clippy::logic_bug)]
-
-fn main() {
-    let a: bool = unimplemented!();
-    let b: bool = unimplemented!();
-    let c: bool = unimplemented!();
-    let d: bool = unimplemented!();
-    let e: bool = unimplemented!();
-    let _ = a && b || a;
-    let _ = !(a && b);
-    let _ = false && a;
-    // don't lint on cfgs
-    let _ = cfg!(you_shall_not_not_pass) && a;
-    let _ = a || !b || !c || !d || !e;
-    let _ = !(a && b || c);
-}
-
-fn equality_stuff() {
-    let a: i32 = unimplemented!();
-    let b: i32 = unimplemented!();
-    let _ = a == b && a != b;
-    let _ = a < b && a >= b;
-    let _ = a > b && a <= b;
-    let _ = a > b && a == b;
-}
-
-fn check_expect() {
-    let a: i32 = unimplemented!();
-    let b: i32 = unimplemented!();
-    #[expect(clippy::logic_bug)]
-    let _ = a < b && a >= b;
-}
diff --git a/src/tools/clippy/tests/ui/logic_bug.stderr b/src/tools/clippy/tests/ui/logic_bug.stderr
deleted file mode 100644 (file)
index 4021fbf..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-error: this boolean expression contains a logic bug
-  --> $DIR/logic_bug.rs:11:13
-   |
-LL |     let _ = a && b || a;
-   |             ^^^^^^^^^^^ help: it would look like the following: `a`
-   |
-   = note: `-D clippy::logic-bug` implied by `-D warnings`
-help: this expression can be optimized out by applying boolean operations to the outer expression
-  --> $DIR/logic_bug.rs:11:18
-   |
-LL |     let _ = a && b || a;
-   |                  ^
-
-error: this boolean expression contains a logic bug
-  --> $DIR/logic_bug.rs:13:13
-   |
-LL |     let _ = false && a;
-   |             ^^^^^^^^^^ help: it would look like the following: `false`
-   |
-help: this expression can be optimized out by applying boolean operations to the outer expression
-  --> $DIR/logic_bug.rs:13:22
-   |
-LL |     let _ = false && a;
-   |                      ^
-
-error: this boolean expression contains a logic bug
-  --> $DIR/logic_bug.rs:23:13
-   |
-LL |     let _ = a == b && a != b;
-   |             ^^^^^^^^^^^^^^^^ help: it would look like the following: `false`
-   |
-help: this expression can be optimized out by applying boolean operations to the outer expression
-  --> $DIR/logic_bug.rs:23:13
-   |
-LL |     let _ = a == b && a != b;
-   |             ^^^^^^
-
-error: this boolean expression contains a logic bug
-  --> $DIR/logic_bug.rs:24:13
-   |
-LL |     let _ = a < b && a >= b;
-   |             ^^^^^^^^^^^^^^^ help: it would look like the following: `false`
-   |
-help: this expression can be optimized out by applying boolean operations to the outer expression
-  --> $DIR/logic_bug.rs:24:13
-   |
-LL |     let _ = a < b && a >= b;
-   |             ^^^^^
-
-error: this boolean expression contains a logic bug
-  --> $DIR/logic_bug.rs:25:13
-   |
-LL |     let _ = a > b && a <= b;
-   |             ^^^^^^^^^^^^^^^ help: it would look like the following: `false`
-   |
-help: this expression can be optimized out by applying boolean operations to the outer expression
-  --> $DIR/logic_bug.rs:25:13
-   |
-LL |     let _ = a > b && a <= b;
-   |             ^^^^^
-
-error: aborting due to 5 previous errors
-
index d0bc640db88994c7c59312de4dfcb001aa984a78..65598f1eaccc54e928026ccdad249f28f43711a6 100644 (file)
@@ -17,7 +17,7 @@ fn main() {
     let c = Some(2);
     if !a.is_empty()
         && a.len() == 3
-        && c != None
+        && c.is_some()
         && !a.is_empty()
         && a.len() == 3
         && !a.is_empty()
index d0bc640db88994c7c59312de4dfcb001aa984a78..65598f1eaccc54e928026ccdad249f28f43711a6 100644 (file)
@@ -17,7 +17,7 @@ fn main() {
     let c = Some(2);
     if !a.is_empty()
         && a.len() == 3
-        && c != None
+        && c.is_some()
         && !a.is_empty()
         && a.len() == 3
         && !a.is_empty()
index 6c2a25c37d8d73f6a1bd5960dbe8a8db954c91f7..a2393674fe6129dae1a74fe21562dceb014dafd3 100644 (file)
@@ -11,7 +11,7 @@ fn main() {
     let c = Some(2);
     if !a.is_empty()
         && a.len() == 3
-        && c != None
+        && c.is_some()
         && !a.is_empty()
         && a.len() == 3
         && !a.is_empty()
index 027747d8386319431e82d9a836cf095063d2f2b9..4d2706dd6211380804c40f004ca9c86569e644ed 100644 (file)
@@ -17,7 +17,7 @@ fn main() {
     let c = Some(2);
     if !a.is_empty()
         && a.len() == 3
-        && c != None
+        && c.is_some()
         && !a.is_empty()
         && a.len() == 3
         && !a.is_empty()
diff --git a/src/tools/clippy/tests/ui/manual_instant_elapsed.fixed b/src/tools/clippy/tests/ui/manual_instant_elapsed.fixed
new file mode 100644 (file)
index 0000000..0fa776b
--- /dev/null
@@ -0,0 +1,27 @@
+// run-rustfix
+#![warn(clippy::manual_instant_elapsed)]
+#![allow(clippy::unnecessary_operation)]
+#![allow(unused_variables)]
+#![allow(unused_must_use)]
+
+use std::time::Instant;
+
+fn main() {
+    let prev_instant = Instant::now();
+
+    {
+        // don't influence
+        let another_instant = Instant::now();
+    }
+
+    let duration = prev_instant.elapsed();
+
+    // don't catch
+    let duration = prev_instant.elapsed();
+
+    Instant::now() - duration;
+
+    let ref_to_instant = &Instant::now();
+
+    (*ref_to_instant).elapsed(); // to ensure parens are added correctly
+}
diff --git a/src/tools/clippy/tests/ui/manual_instant_elapsed.rs b/src/tools/clippy/tests/ui/manual_instant_elapsed.rs
new file mode 100644 (file)
index 0000000..5b11b84
--- /dev/null
@@ -0,0 +1,27 @@
+// run-rustfix
+#![warn(clippy::manual_instant_elapsed)]
+#![allow(clippy::unnecessary_operation)]
+#![allow(unused_variables)]
+#![allow(unused_must_use)]
+
+use std::time::Instant;
+
+fn main() {
+    let prev_instant = Instant::now();
+
+    {
+        // don't influence
+        let another_instant = Instant::now();
+    }
+
+    let duration = Instant::now() - prev_instant;
+
+    // don't catch
+    let duration = prev_instant.elapsed();
+
+    Instant::now() - duration;
+
+    let ref_to_instant = &Instant::now();
+
+    Instant::now() - *ref_to_instant; // to ensure parens are added correctly
+}
diff --git a/src/tools/clippy/tests/ui/manual_instant_elapsed.stderr b/src/tools/clippy/tests/ui/manual_instant_elapsed.stderr
new file mode 100644 (file)
index 0000000..5537f56
--- /dev/null
@@ -0,0 +1,16 @@
+error: manual implementation of `Instant::elapsed`
+  --> $DIR/manual_instant_elapsed.rs:17:20
+   |
+LL |     let duration = Instant::now() - prev_instant;
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `prev_instant.elapsed()`
+   |
+   = note: `-D clippy::manual-instant-elapsed` implied by `-D warnings`
+
+error: manual implementation of `Instant::elapsed`
+  --> $DIR/manual_instant_elapsed.rs:26:5
+   |
+LL |     Instant::now() - *ref_to_instant; // to ensure parens are added correctly
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(*ref_to_instant).elapsed()`
+
+error: aborting due to 2 previous errors
+
index 887a97d7a01734dafb5269bcac6c57b62a2978db..d864f85545349669a72ac1fd8ed3fcaac6bdb3f3 100644 (file)
@@ -1,6 +1,6 @@
 // run-rustfix
 #![warn(clippy::manual_ok_or)]
-#![allow(clippy::blacklisted_name)]
+#![allow(clippy::disallowed_names)]
 #![allow(clippy::redundant_closure)]
 #![allow(dead_code)]
 #![allow(unused_must_use)]
index 3c99872f5022a32cb4a35394fe12e8ba46b0e362..6264768460ef60539e1379f1dbc28c16af415b7d 100644 (file)
@@ -1,6 +1,6 @@
 // run-rustfix
 #![warn(clippy::manual_ok_or)]
-#![allow(clippy::blacklisted_name)]
+#![allow(clippy::disallowed_names)]
 #![allow(clippy::redundant_closure)]
 #![allow(dead_code)]
 #![allow(unused_must_use)]
index 7aba5b447d5537f25fd0be12684a1986f5b2463b..61793e80c98d42591db0781ba8f16e5b4c6ac73d 100644 (file)
@@ -1,5 +1,5 @@
 #![warn(clippy::match_same_arms)]
-#![allow(clippy::blacklisted_name, clippy::diverging_sub_expression)]
+#![allow(clippy::disallowed_names, clippy::diverging_sub_expression)]
 
 fn bar<T>(_: T) {}
 fn foo() -> bool {
index 1970c2eae531420a9dbc6f36964d7bba80890d8a..6f22366eab29adab0ab9f830524a8dffbb8a14f7 100644 (file)
@@ -2,7 +2,7 @@
 
 #![warn(clippy::all, clippy::pedantic)]
 #![allow(
-    clippy::blacklisted_name,
+    clippy::disallowed_names,
     clippy::default_trait_access,
     clippy::missing_docs_in_private_items,
     clippy::missing_safety_doc,
index 8c0da84d8e975a5e160608bf74714d79c7daca84..40c1fcae1fd3fb172004276a8f8a8df3ae8821c6 100644 (file)
@@ -1,5 +1,5 @@
 #![warn(clippy::mismatching_type_param_order)]
-#![allow(clippy::blacklisted_name)]
+#![allow(clippy::disallowed_names)]
 
 fn main() {
     struct Foo<A, B> {
diff --git a/src/tools/clippy/tests/ui/missing-doc-crate-missing.rs b/src/tools/clippy/tests/ui/missing-doc-crate-missing.rs
deleted file mode 100644 (file)
index 51fd57d..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#![warn(clippy::missing_docs_in_private_items)]
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/missing-doc-crate-missing.stderr b/src/tools/clippy/tests/ui/missing-doc-crate-missing.stderr
deleted file mode 100644 (file)
index d56c5cc..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-error: missing documentation for the crate
-  --> $DIR/missing-doc-crate-missing.rs:1:1
-   |
-LL | / #![warn(clippy::missing_docs_in_private_items)]
-LL | |
-LL | | fn main() {}
-   | |____________^
-   |
-   = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings`
-
-error: aborting due to previous error
-
diff --git a/src/tools/clippy/tests/ui/missing-doc-crate.rs b/src/tools/clippy/tests/ui/missing-doc-crate.rs
deleted file mode 100644 (file)
index e00c7fb..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#![warn(clippy::missing_docs_in_private_items)]
-#![doc = include_str!("../../README.md")]
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/missing-doc-impl.rs b/src/tools/clippy/tests/ui/missing-doc-impl.rs
deleted file mode 100644 (file)
index d5724bf..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-#![warn(clippy::missing_docs_in_private_items)]
-#![allow(dead_code)]
-#![feature(associated_type_defaults)]
-
-//! Some garbage docs for the crate here
-#![doc = "More garbage"]
-
-struct Foo {
-    a: isize,
-    b: isize,
-}
-
-pub struct PubFoo {
-    pub a: isize,
-    b: isize,
-}
-
-#[allow(clippy::missing_docs_in_private_items)]
-pub struct PubFoo2 {
-    pub a: isize,
-    pub c: isize,
-}
-
-/// dox
-pub trait A {
-    /// dox
-    fn foo(&self);
-    /// dox
-    fn foo_with_impl(&self) {}
-}
-
-#[allow(clippy::missing_docs_in_private_items)]
-trait B {
-    fn foo(&self);
-    fn foo_with_impl(&self) {}
-}
-
-pub trait C {
-    fn foo(&self);
-    fn foo_with_impl(&self) {}
-}
-
-#[allow(clippy::missing_docs_in_private_items)]
-pub trait D {
-    fn dummy(&self) {}
-}
-
-/// dox
-pub trait E: Sized {
-    type AssociatedType;
-    type AssociatedTypeDef = Self;
-
-    /// dox
-    type DocumentedType;
-    /// dox
-    type DocumentedTypeDef = Self;
-    /// dox
-    fn dummy(&self) {}
-}
-
-impl Foo {
-    pub fn new() -> Self {
-        Foo { a: 0, b: 0 }
-    }
-    fn bar() {}
-}
-
-impl PubFoo {
-    pub fn foo() {}
-    /// dox
-    pub fn foo1() {}
-    #[must_use = "yep"]
-    fn foo2() -> u32 {
-        1
-    }
-    #[allow(clippy::missing_docs_in_private_items)]
-    pub fn foo3() {}
-}
-
-#[allow(clippy::missing_docs_in_private_items)]
-trait F {
-    fn a();
-    fn b(&self);
-}
-
-// should need to redefine documentation for implementations of traits
-impl F for Foo {
-    fn a() {}
-    fn b(&self) {}
-}
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/missing-doc-impl.stderr b/src/tools/clippy/tests/ui/missing-doc-impl.stderr
deleted file mode 100644 (file)
index bda63d6..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-error: missing documentation for a struct
-  --> $DIR/missing-doc-impl.rs:8:1
-   |
-LL | / struct Foo {
-LL | |     a: isize,
-LL | |     b: isize,
-LL | | }
-   | |_^
-   |
-   = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings`
-
-error: missing documentation for a struct field
-  --> $DIR/missing-doc-impl.rs:9:5
-   |
-LL |     a: isize,
-   |     ^^^^^^^^
-
-error: missing documentation for a struct field
-  --> $DIR/missing-doc-impl.rs:10:5
-   |
-LL |     b: isize,
-   |     ^^^^^^^^
-
-error: missing documentation for a struct
-  --> $DIR/missing-doc-impl.rs:13:1
-   |
-LL | / pub struct PubFoo {
-LL | |     pub a: isize,
-LL | |     b: isize,
-LL | | }
-   | |_^
-
-error: missing documentation for a struct field
-  --> $DIR/missing-doc-impl.rs:14:5
-   |
-LL |     pub a: isize,
-   |     ^^^^^^^^^^^^
-
-error: missing documentation for a struct field
-  --> $DIR/missing-doc-impl.rs:15:5
-   |
-LL |     b: isize,
-   |     ^^^^^^^^
-
-error: missing documentation for a trait
-  --> $DIR/missing-doc-impl.rs:38:1
-   |
-LL | / pub trait C {
-LL | |     fn foo(&self);
-LL | |     fn foo_with_impl(&self) {}
-LL | | }
-   | |_^
-
-error: missing documentation for an associated function
-  --> $DIR/missing-doc-impl.rs:39:5
-   |
-LL |     fn foo(&self);
-   |     ^^^^^^^^^^^^^^
-
-error: missing documentation for an associated function
-  --> $DIR/missing-doc-impl.rs:40:5
-   |
-LL |     fn foo_with_impl(&self) {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: missing documentation for an associated type
-  --> $DIR/missing-doc-impl.rs:50:5
-   |
-LL |     type AssociatedType;
-   |     ^^^^^^^^^^^^^^^^^^^^
-
-error: missing documentation for an associated type
-  --> $DIR/missing-doc-impl.rs:51:5
-   |
-LL |     type AssociatedTypeDef = Self;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: missing documentation for an associated function
-  --> $DIR/missing-doc-impl.rs:62:5
-   |
-LL | /     pub fn new() -> Self {
-LL | |         Foo { a: 0, b: 0 }
-LL | |     }
-   | |_____^
-
-error: missing documentation for an associated function
-  --> $DIR/missing-doc-impl.rs:65:5
-   |
-LL |     fn bar() {}
-   |     ^^^^^^^^^^^
-
-error: missing documentation for an associated function
-  --> $DIR/missing-doc-impl.rs:69:5
-   |
-LL |     pub fn foo() {}
-   |     ^^^^^^^^^^^^^^^
-
-error: missing documentation for an associated function
-  --> $DIR/missing-doc-impl.rs:73:5
-   |
-LL | /     fn foo2() -> u32 {
-LL | |         1
-LL | |     }
-   | |_____^
-
-error: aborting due to 15 previous errors
-
diff --git a/src/tools/clippy/tests/ui/missing-doc.rs b/src/tools/clippy/tests/ui/missing-doc.rs
deleted file mode 100644 (file)
index 6e2e710..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-#![warn(clippy::missing_docs_in_private_items)]
-// When denying at the crate level, be sure to not get random warnings from the
-// injected intrinsics by the compiler.
-#![allow(dead_code)]
-//! Some garbage docs for the crate here
-#![doc = "More garbage"]
-
-use std::arch::global_asm;
-
-type Typedef = String;
-pub type PubTypedef = String;
-
-mod module_no_dox {}
-pub mod pub_module_no_dox {}
-
-/// dox
-pub fn foo() {}
-pub fn foo2() {}
-fn foo3() {}
-#[allow(clippy::missing_docs_in_private_items)]
-pub fn foo4() {}
-
-// It sure is nice if doc(hidden) implies allow(missing_docs), and that it
-// applies recursively
-#[doc(hidden)]
-mod a {
-    pub fn baz() {}
-    pub mod b {
-        pub fn baz() {}
-    }
-}
-
-enum Baz {
-    BazA { a: isize, b: isize },
-    BarB,
-}
-
-pub enum PubBaz {
-    PubBazA { a: isize },
-}
-
-/// dox
-pub enum PubBaz2 {
-    /// dox
-    PubBaz2A {
-        /// dox
-        a: isize,
-    },
-}
-
-#[allow(clippy::missing_docs_in_private_items)]
-pub enum PubBaz3 {
-    PubBaz3A { b: isize },
-}
-
-#[doc(hidden)]
-pub fn baz() {}
-
-const FOO: u32 = 0;
-/// dox
-pub const FOO1: u32 = 0;
-#[allow(clippy::missing_docs_in_private_items)]
-pub const FOO2: u32 = 0;
-#[doc(hidden)]
-pub const FOO3: u32 = 0;
-pub const FOO4: u32 = 0;
-
-static BAR: u32 = 0;
-/// dox
-pub static BAR1: u32 = 0;
-#[allow(clippy::missing_docs_in_private_items)]
-pub static BAR2: u32 = 0;
-#[doc(hidden)]
-pub static BAR3: u32 = 0;
-pub static BAR4: u32 = 0;
-
-mod internal_impl {
-    /// dox
-    pub fn documented() {}
-    pub fn undocumented1() {}
-    pub fn undocumented2() {}
-    fn undocumented3() {}
-    /// dox
-    pub mod globbed {
-        /// dox
-        pub fn also_documented() {}
-        pub fn also_undocumented1() {}
-        fn also_undocumented2() {}
-    }
-}
-/// dox
-pub mod public_interface {
-    pub use crate::internal_impl::documented as foo;
-    pub use crate::internal_impl::globbed::*;
-    pub use crate::internal_impl::undocumented1 as bar;
-    pub use crate::internal_impl::{documented, undocumented2};
-}
-
-fn main() {}
-
-// Ensure global asm doesn't require documentation.
-global_asm! { "" }
diff --git a/src/tools/clippy/tests/ui/missing-doc.stderr b/src/tools/clippy/tests/ui/missing-doc.stderr
deleted file mode 100644 (file)
index a876dc0..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-error: missing documentation for a type alias
-  --> $DIR/missing-doc.rs:10:1
-   |
-LL | type Typedef = String;
-   | ^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings`
-
-error: missing documentation for a type alias
-  --> $DIR/missing-doc.rs:11:1
-   |
-LL | pub type PubTypedef = String;
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: missing documentation for a module
-  --> $DIR/missing-doc.rs:13:1
-   |
-LL | mod module_no_dox {}
-   | ^^^^^^^^^^^^^^^^^^^^
-
-error: missing documentation for a module
-  --> $DIR/missing-doc.rs:14:1
-   |
-LL | pub mod pub_module_no_dox {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: missing documentation for a function
-  --> $DIR/missing-doc.rs:18:1
-   |
-LL | pub fn foo2() {}
-   | ^^^^^^^^^^^^^^^^
-
-error: missing documentation for a function
-  --> $DIR/missing-doc.rs:19:1
-   |
-LL | fn foo3() {}
-   | ^^^^^^^^^^^^
-
-error: missing documentation for an enum
-  --> $DIR/missing-doc.rs:33:1
-   |
-LL | / enum Baz {
-LL | |     BazA { a: isize, b: isize },
-LL | |     BarB,
-LL | | }
-   | |_^
-
-error: missing documentation for a variant
-  --> $DIR/missing-doc.rs:34:5
-   |
-LL |     BazA { a: isize, b: isize },
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: missing documentation for a struct field
-  --> $DIR/missing-doc.rs:34:12
-   |
-LL |     BazA { a: isize, b: isize },
-   |            ^^^^^^^^
-
-error: missing documentation for a struct field
-  --> $DIR/missing-doc.rs:34:22
-   |
-LL |     BazA { a: isize, b: isize },
-   |                      ^^^^^^^^
-
-error: missing documentation for a variant
-  --> $DIR/missing-doc.rs:35:5
-   |
-LL |     BarB,
-   |     ^^^^
-
-error: missing documentation for an enum
-  --> $DIR/missing-doc.rs:38:1
-   |
-LL | / pub enum PubBaz {
-LL | |     PubBazA { a: isize },
-LL | | }
-   | |_^
-
-error: missing documentation for a variant
-  --> $DIR/missing-doc.rs:39:5
-   |
-LL |     PubBazA { a: isize },
-   |     ^^^^^^^^^^^^^^^^^^^^
-
-error: missing documentation for a struct field
-  --> $DIR/missing-doc.rs:39:15
-   |
-LL |     PubBazA { a: isize },
-   |               ^^^^^^^^
-
-error: missing documentation for a constant
-  --> $DIR/missing-doc.rs:59:1
-   |
-LL | const FOO: u32 = 0;
-   | ^^^^^^^^^^^^^^^^^^^
-
-error: missing documentation for a constant
-  --> $DIR/missing-doc.rs:66:1
-   |
-LL | pub const FOO4: u32 = 0;
-   | ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: missing documentation for a static
-  --> $DIR/missing-doc.rs:68:1
-   |
-LL | static BAR: u32 = 0;
-   | ^^^^^^^^^^^^^^^^^^^^
-
-error: missing documentation for a static
-  --> $DIR/missing-doc.rs:75:1
-   |
-LL | pub static BAR4: u32 = 0;
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: missing documentation for a module
-  --> $DIR/missing-doc.rs:77:1
-   |
-LL | / mod internal_impl {
-LL | |     /// dox
-LL | |     pub fn documented() {}
-LL | |     pub fn undocumented1() {}
-...  |
-LL | |     }
-LL | | }
-   | |_^
-
-error: missing documentation for a function
-  --> $DIR/missing-doc.rs:80:5
-   |
-LL |     pub fn undocumented1() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: missing documentation for a function
-  --> $DIR/missing-doc.rs:81:5
-   |
-LL |     pub fn undocumented2() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: missing documentation for a function
-  --> $DIR/missing-doc.rs:82:5
-   |
-LL |     fn undocumented3() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^
-
-error: missing documentation for a function
-  --> $DIR/missing-doc.rs:87:9
-   |
-LL |         pub fn also_undocumented1() {}
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: missing documentation for a function
-  --> $DIR/missing-doc.rs:88:9
-   |
-LL |         fn also_undocumented2() {}
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 24 previous errors
-
index aa60d0504e5e60c1181351c9444736b62d740b5a..b950248ef942024d0e003fc5be16c8ba0c249101 100644 (file)
@@ -3,12 +3,16 @@
 //! The .stderr output of this test should be empty. Otherwise it's a bug somewhere.
 
 // aux-build:helper.rs
+// aux-build:../../auxiliary/proc_macro_with_span.rs
 
 #![warn(clippy::missing_const_for_fn)]
 #![feature(start)]
 #![feature(custom_inner_attributes)]
 
 extern crate helper;
+extern crate proc_macro_with_span;
+
+use proc_macro_with_span::with_span;
 
 struct Game;
 
@@ -119,3 +123,8 @@ fn const_fn_stabilized_after_msrv(byte: u8) {
         byte.is_ascii_digit();
     }
 }
+
+with_span! {
+    span
+    fn dont_check_in_proc_macro() {}
+}
diff --git a/src/tools/clippy/tests/ui/missing_doc.rs b/src/tools/clippy/tests/ui/missing_doc.rs
new file mode 100644 (file)
index 0000000..29cc026
--- /dev/null
@@ -0,0 +1,115 @@
+// aux-build: proc_macro_with_span.rs
+
+#![warn(clippy::missing_docs_in_private_items)]
+// When denying at the crate level, be sure to not get random warnings from the
+// injected intrinsics by the compiler.
+#![allow(dead_code)]
+//! Some garbage docs for the crate here
+#![doc = "More garbage"]
+
+extern crate proc_macro_with_span;
+
+use proc_macro_with_span::with_span;
+use std::arch::global_asm;
+
+type Typedef = String;
+pub type PubTypedef = String;
+
+mod module_no_dox {}
+pub mod pub_module_no_dox {}
+
+/// dox
+pub fn foo() {}
+pub fn foo2() {}
+fn foo3() {}
+#[allow(clippy::missing_docs_in_private_items)]
+pub fn foo4() {}
+
+// It sure is nice if doc(hidden) implies allow(missing_docs), and that it
+// applies recursively
+#[doc(hidden)]
+mod a {
+    pub fn baz() {}
+    pub mod b {
+        pub fn baz() {}
+    }
+}
+
+enum Baz {
+    BazA { a: isize, b: isize },
+    BarB,
+}
+
+pub enum PubBaz {
+    PubBazA { a: isize },
+}
+
+/// dox
+pub enum PubBaz2 {
+    /// dox
+    PubBaz2A {
+        /// dox
+        a: isize,
+    },
+}
+
+#[allow(clippy::missing_docs_in_private_items)]
+pub enum PubBaz3 {
+    PubBaz3A { b: isize },
+}
+
+#[doc(hidden)]
+pub fn baz() {}
+
+const FOO: u32 = 0;
+/// dox
+pub const FOO1: u32 = 0;
+#[allow(clippy::missing_docs_in_private_items)]
+pub const FOO2: u32 = 0;
+#[doc(hidden)]
+pub const FOO3: u32 = 0;
+pub const FOO4: u32 = 0;
+
+static BAR: u32 = 0;
+/// dox
+pub static BAR1: u32 = 0;
+#[allow(clippy::missing_docs_in_private_items)]
+pub static BAR2: u32 = 0;
+#[doc(hidden)]
+pub static BAR3: u32 = 0;
+pub static BAR4: u32 = 0;
+
+mod internal_impl {
+    /// dox
+    pub fn documented() {}
+    pub fn undocumented1() {}
+    pub fn undocumented2() {}
+    fn undocumented3() {}
+    /// dox
+    pub mod globbed {
+        /// dox
+        pub fn also_documented() {}
+        pub fn also_undocumented1() {}
+        fn also_undocumented2() {}
+    }
+}
+/// dox
+pub mod public_interface {
+    pub use crate::internal_impl::documented as foo;
+    pub use crate::internal_impl::globbed::*;
+    pub use crate::internal_impl::undocumented1 as bar;
+    pub use crate::internal_impl::{documented, undocumented2};
+}
+
+fn main() {}
+
+// Ensure global asm doesn't require documentation.
+global_asm! { "" }
+
+// Don't lint proc macro output with an unexpected span.
+with_span!(span pub struct FooPm { pub field: u32});
+with_span!(span pub struct FooPm2;);
+with_span!(span pub enum FooPm3 { A, B(u32), C { field: u32 }});
+with_span!(span pub fn foo_pm() {});
+with_span!(span pub static FOO_PM: u32 = 0;);
+with_span!(span pub const FOO2_PM: u32 = 0;);
diff --git a/src/tools/clippy/tests/ui/missing_doc.stderr b/src/tools/clippy/tests/ui/missing_doc.stderr
new file mode 100644 (file)
index 0000000..6c8e66f
--- /dev/null
@@ -0,0 +1,159 @@
+error: missing documentation for a type alias
+  --> $DIR/missing_doc.rs:15:1
+   |
+LL | type Typedef = String;
+   | ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings`
+
+error: missing documentation for a type alias
+  --> $DIR/missing_doc.rs:16:1
+   |
+LL | pub type PubTypedef = String;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a module
+  --> $DIR/missing_doc.rs:18:1
+   |
+LL | mod module_no_dox {}
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a module
+  --> $DIR/missing_doc.rs:19:1
+   |
+LL | pub mod pub_module_no_dox {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a function
+  --> $DIR/missing_doc.rs:23:1
+   |
+LL | pub fn foo2() {}
+   | ^^^^^^^^^^^^^^^^
+
+error: missing documentation for a function
+  --> $DIR/missing_doc.rs:24:1
+   |
+LL | fn foo3() {}
+   | ^^^^^^^^^^^^
+
+error: missing documentation for an enum
+  --> $DIR/missing_doc.rs:38:1
+   |
+LL | / enum Baz {
+LL | |     BazA { a: isize, b: isize },
+LL | |     BarB,
+LL | | }
+   | |_^
+
+error: missing documentation for a variant
+  --> $DIR/missing_doc.rs:39:5
+   |
+LL |     BazA { a: isize, b: isize },
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a struct field
+  --> $DIR/missing_doc.rs:39:12
+   |
+LL |     BazA { a: isize, b: isize },
+   |            ^^^^^^^^
+
+error: missing documentation for a struct field
+  --> $DIR/missing_doc.rs:39:22
+   |
+LL |     BazA { a: isize, b: isize },
+   |                      ^^^^^^^^
+
+error: missing documentation for a variant
+  --> $DIR/missing_doc.rs:40:5
+   |
+LL |     BarB,
+   |     ^^^^
+
+error: missing documentation for an enum
+  --> $DIR/missing_doc.rs:43:1
+   |
+LL | / pub enum PubBaz {
+LL | |     PubBazA { a: isize },
+LL | | }
+   | |_^
+
+error: missing documentation for a variant
+  --> $DIR/missing_doc.rs:44:5
+   |
+LL |     PubBazA { a: isize },
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a struct field
+  --> $DIR/missing_doc.rs:44:15
+   |
+LL |     PubBazA { a: isize },
+   |               ^^^^^^^^
+
+error: missing documentation for a constant
+  --> $DIR/missing_doc.rs:64:1
+   |
+LL | const FOO: u32 = 0;
+   | ^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a constant
+  --> $DIR/missing_doc.rs:71:1
+   |
+LL | pub const FOO4: u32 = 0;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a static
+  --> $DIR/missing_doc.rs:73:1
+   |
+LL | static BAR: u32 = 0;
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a static
+  --> $DIR/missing_doc.rs:80:1
+   |
+LL | pub static BAR4: u32 = 0;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a module
+  --> $DIR/missing_doc.rs:82:1
+   |
+LL | / mod internal_impl {
+LL | |     /// dox
+LL | |     pub fn documented() {}
+LL | |     pub fn undocumented1() {}
+...  |
+LL | |     }
+LL | | }
+   | |_^
+
+error: missing documentation for a function
+  --> $DIR/missing_doc.rs:85:5
+   |
+LL |     pub fn undocumented1() {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a function
+  --> $DIR/missing_doc.rs:86:5
+   |
+LL |     pub fn undocumented2() {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a function
+  --> $DIR/missing_doc.rs:87:5
+   |
+LL |     fn undocumented3() {}
+   |     ^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a function
+  --> $DIR/missing_doc.rs:92:9
+   |
+LL |         pub fn also_undocumented1() {}
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a function
+  --> $DIR/missing_doc.rs:93:9
+   |
+LL |         fn also_undocumented2() {}
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 24 previous errors
+
diff --git a/src/tools/clippy/tests/ui/missing_doc_crate.rs b/src/tools/clippy/tests/ui/missing_doc_crate.rs
new file mode 100644 (file)
index 0000000..e00c7fb
--- /dev/null
@@ -0,0 +1,4 @@
+#![warn(clippy::missing_docs_in_private_items)]
+#![doc = include_str!("../../README.md")]
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/missing_doc_crate_missing.rs b/src/tools/clippy/tests/ui/missing_doc_crate_missing.rs
new file mode 100644 (file)
index 0000000..51fd57d
--- /dev/null
@@ -0,0 +1,3 @@
+#![warn(clippy::missing_docs_in_private_items)]
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/missing_doc_crate_missing.stderr b/src/tools/clippy/tests/ui/missing_doc_crate_missing.stderr
new file mode 100644 (file)
index 0000000..19516bf
--- /dev/null
@@ -0,0 +1,12 @@
+error: missing documentation for the crate
+  --> $DIR/missing_doc_crate_missing.rs:1:1
+   |
+LL | / #![warn(clippy::missing_docs_in_private_items)]
+LL | |
+LL | | fn main() {}
+   | |____________^
+   |
+   = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/missing_doc_impl.rs b/src/tools/clippy/tests/ui/missing_doc_impl.rs
new file mode 100644 (file)
index 0000000..0396d11
--- /dev/null
@@ -0,0 +1,107 @@
+// aux-build: proc_macro_with_span.rs
+
+#![warn(clippy::missing_docs_in_private_items)]
+#![allow(dead_code)]
+#![feature(associated_type_defaults)]
+
+//! Some garbage docs for the crate here
+#![doc = "More garbage"]
+
+extern crate proc_macro_with_span;
+use proc_macro_with_span::with_span;
+
+struct Foo {
+    a: isize,
+    b: isize,
+}
+
+pub struct PubFoo {
+    pub a: isize,
+    b: isize,
+}
+
+#[allow(clippy::missing_docs_in_private_items)]
+pub struct PubFoo2 {
+    pub a: isize,
+    pub c: isize,
+}
+
+/// dox
+pub trait A {
+    /// dox
+    fn foo(&self);
+    /// dox
+    fn foo_with_impl(&self) {}
+}
+
+#[allow(clippy::missing_docs_in_private_items)]
+trait B {
+    fn foo(&self);
+    fn foo_with_impl(&self) {}
+}
+
+pub trait C {
+    fn foo(&self);
+    fn foo_with_impl(&self) {}
+}
+
+#[allow(clippy::missing_docs_in_private_items)]
+pub trait D {
+    fn dummy(&self) {}
+}
+
+/// dox
+pub trait E: Sized {
+    type AssociatedType;
+    type AssociatedTypeDef = Self;
+
+    /// dox
+    type DocumentedType;
+    /// dox
+    type DocumentedTypeDef = Self;
+    /// dox
+    fn dummy(&self) {}
+}
+
+impl Foo {
+    pub fn new() -> Self {
+        Foo { a: 0, b: 0 }
+    }
+    fn bar() {}
+}
+
+impl PubFoo {
+    pub fn foo() {}
+    /// dox
+    pub fn foo1() {}
+    #[must_use = "yep"]
+    fn foo2() -> u32 {
+        1
+    }
+    #[allow(clippy::missing_docs_in_private_items)]
+    pub fn foo3() {}
+}
+
+#[allow(clippy::missing_docs_in_private_items)]
+trait F {
+    fn a();
+    fn b(&self);
+}
+
+// should need to redefine documentation for implementations of traits
+impl F for Foo {
+    fn a() {}
+    fn b(&self) {}
+}
+
+fn main() {}
+
+// don't lint proc macro output
+with_span!(span
+    pub struct FooPm;
+    impl FooPm {
+        pub fn foo() {}
+        pub const fn bar() {}
+        pub const X: u32 = 0;
+    }
+);
diff --git a/src/tools/clippy/tests/ui/missing_doc_impl.stderr b/src/tools/clippy/tests/ui/missing_doc_impl.stderr
new file mode 100644 (file)
index 0000000..f22fa19
--- /dev/null
@@ -0,0 +1,107 @@
+error: missing documentation for a struct
+  --> $DIR/missing_doc_impl.rs:13:1
+   |
+LL | / struct Foo {
+LL | |     a: isize,
+LL | |     b: isize,
+LL | | }
+   | |_^
+   |
+   = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings`
+
+error: missing documentation for a struct field
+  --> $DIR/missing_doc_impl.rs:14:5
+   |
+LL |     a: isize,
+   |     ^^^^^^^^
+
+error: missing documentation for a struct field
+  --> $DIR/missing_doc_impl.rs:15:5
+   |
+LL |     b: isize,
+   |     ^^^^^^^^
+
+error: missing documentation for a struct
+  --> $DIR/missing_doc_impl.rs:18:1
+   |
+LL | / pub struct PubFoo {
+LL | |     pub a: isize,
+LL | |     b: isize,
+LL | | }
+   | |_^
+
+error: missing documentation for a struct field
+  --> $DIR/missing_doc_impl.rs:19:5
+   |
+LL |     pub a: isize,
+   |     ^^^^^^^^^^^^
+
+error: missing documentation for a struct field
+  --> $DIR/missing_doc_impl.rs:20:5
+   |
+LL |     b: isize,
+   |     ^^^^^^^^
+
+error: missing documentation for a trait
+  --> $DIR/missing_doc_impl.rs:43:1
+   |
+LL | / pub trait C {
+LL | |     fn foo(&self);
+LL | |     fn foo_with_impl(&self) {}
+LL | | }
+   | |_^
+
+error: missing documentation for an associated function
+  --> $DIR/missing_doc_impl.rs:44:5
+   |
+LL |     fn foo(&self);
+   |     ^^^^^^^^^^^^^^
+
+error: missing documentation for an associated function
+  --> $DIR/missing_doc_impl.rs:45:5
+   |
+LL |     fn foo_with_impl(&self) {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for an associated type
+  --> $DIR/missing_doc_impl.rs:55:5
+   |
+LL |     type AssociatedType;
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for an associated type
+  --> $DIR/missing_doc_impl.rs:56:5
+   |
+LL |     type AssociatedTypeDef = Self;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for an associated function
+  --> $DIR/missing_doc_impl.rs:67:5
+   |
+LL | /     pub fn new() -> Self {
+LL | |         Foo { a: 0, b: 0 }
+LL | |     }
+   | |_____^
+
+error: missing documentation for an associated function
+  --> $DIR/missing_doc_impl.rs:70:5
+   |
+LL |     fn bar() {}
+   |     ^^^^^^^^^^^
+
+error: missing documentation for an associated function
+  --> $DIR/missing_doc_impl.rs:74:5
+   |
+LL |     pub fn foo() {}
+   |     ^^^^^^^^^^^^^^^
+
+error: missing documentation for an associated function
+  --> $DIR/missing_doc_impl.rs:78:5
+   |
+LL | /     fn foo2() -> u32 {
+LL | |         1
+LL | |     }
+   | |_____^
+
+error: aborting due to 15 previous errors
+
index a7b36d53cd26c7cc1011553d0a1ceb2fd88268ae..becb9562a8497212ebcadc13412f904ab39b36a9 100644 (file)
@@ -1,4 +1,5 @@
 // run-rustfix
+// aux-build: proc_macro_with_span.rs
 
 #![allow(
     dead_code,
@@ -9,6 +10,9 @@
     clippy::unusual_byte_groupings
 )]
 
+extern crate proc_macro_with_span;
+use proc_macro_with_span::with_span;
+
 fn main() {
     let fail14 = 2_i32;
     let fail15 = 4_i64;
@@ -40,4 +44,6 @@ fn main() {
     let ok38 = 124_64.0;
 
     let _ = 1.123_45E1_f32;
+
+    let _ = with_span!(1 2_u32);
 }
index c97b31965c75a7c4cd1f3030dccd3b042f23fd7c..ee841bcd7e4e995ba5b350d81df461ae2db6aaec 100644 (file)
@@ -1,4 +1,5 @@
 // run-rustfix
+// aux-build: proc_macro_with_span.rs
 
 #![allow(
     dead_code,
@@ -9,6 +10,9 @@
     clippy::unusual_byte_groupings
 )]
 
+extern crate proc_macro_with_span;
+use proc_macro_with_span::with_span;
+
 fn main() {
     let fail14 = 2_32;
     let fail15 = 4_64;
@@ -40,4 +44,6 @@ fn main() {
     let ok38 = 124_64.0;
 
     let _ = 1.12345E1_32;
+
+    let _ = with_span!(1 2_u32);
 }
index fb761d9bde45255085e56a861d791d370516c251..ef8e6a33d28f59a8c65009cdd19b573aa153c6ec 100644 (file)
@@ -1,5 +1,5 @@
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:13:18
+  --> $DIR/mistyped_literal_suffix.rs:17:18
    |
 LL |     let fail14 = 2_32;
    |                  ^^^^ help: did you mean to write: `2_i32`
@@ -7,91 +7,91 @@ LL |     let fail14 = 2_32;
    = note: `#[deny(clippy::mistyped_literal_suffixes)]` on by default
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:14:18
+  --> $DIR/mistyped_literal_suffix.rs:18:18
    |
 LL |     let fail15 = 4_64;
    |                  ^^^^ help: did you mean to write: `4_i64`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:15:18
+  --> $DIR/mistyped_literal_suffix.rs:19:18
    |
 LL |     let fail16 = 7_8; //
    |                  ^^^ help: did you mean to write: `7_i8`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:16:18
+  --> $DIR/mistyped_literal_suffix.rs:20:18
    |
 LL |     let fail17 = 23_16; //
    |                  ^^^^^ help: did you mean to write: `23_i16`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:19:18
+  --> $DIR/mistyped_literal_suffix.rs:23:18
    |
 LL |     let fail20 = 2__8; //
    |                  ^^^^ help: did you mean to write: `2_i8`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:20:18
+  --> $DIR/mistyped_literal_suffix.rs:24:18
    |
 LL |     let fail21 = 4___16; //
    |                  ^^^^^^ help: did you mean to write: `4_i16`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:23:18
+  --> $DIR/mistyped_literal_suffix.rs:27:18
    |
 LL |     let fail25 = 1E2_32;
    |                  ^^^^^^ help: did you mean to write: `1E2_f32`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:24:18
+  --> $DIR/mistyped_literal_suffix.rs:28:18
    |
 LL |     let fail26 = 43E7_64;
    |                  ^^^^^^^ help: did you mean to write: `43E7_f64`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:25:18
+  --> $DIR/mistyped_literal_suffix.rs:29:18
    |
 LL |     let fail27 = 243E17_32;
    |                  ^^^^^^^^^ help: did you mean to write: `243E17_f32`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:26:18
+  --> $DIR/mistyped_literal_suffix.rs:30:18
    |
 LL |     let fail28 = 241251235E723_64;
    |                  ^^^^^^^^^^^^^^^^ help: did you mean to write: `241_251_235E723_f64`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:30:18
+  --> $DIR/mistyped_literal_suffix.rs:34:18
    |
 LL |     let fail30 = 127_8; // should be i8
    |                  ^^^^^ help: did you mean to write: `127_i8`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:31:18
+  --> $DIR/mistyped_literal_suffix.rs:35:18
    |
 LL |     let fail31 = 240_8; // should be u8
    |                  ^^^^^ help: did you mean to write: `240_u8`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:33:18
+  --> $DIR/mistyped_literal_suffix.rs:37:18
    |
 LL |     let fail33 = 0x1234_16;
    |                  ^^^^^^^^^ help: did you mean to write: `0x1234_i16`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:34:18
+  --> $DIR/mistyped_literal_suffix.rs:38:18
    |
 LL |     let fail34 = 0xABCD_16;
    |                  ^^^^^^^^^ help: did you mean to write: `0xABCD_u16`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:36:18
+  --> $DIR/mistyped_literal_suffix.rs:40:18
    |
 LL |     let fail36 = 0xFFFF_FFFF_FFFF_FFFF_64; // u64
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean to write: `0xFFFF_FFFF_FFFF_FFFF_u64`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:42:13
+  --> $DIR/mistyped_literal_suffix.rs:46:13
    |
 LL |     let _ = 1.12345E1_32;
    |             ^^^^^^^^^^^^ help: did you mean to write: `1.123_45E1_f32`
index 7640057ab6e36da429072c4f5ac46950c22c8b49..6efc7657ec0c92349291ee1f8b250ab3d7d8cd01 100644 (file)
@@ -4,7 +4,7 @@
     unused_variables,
     clippy::no_effect,
     dead_code,
-    clippy::blacklisted_name
+    clippy::disallowed_names
 )]
 fn main() {
     let mut x = 0;
index 9556f6f82cc6313d39125487819635ce0b0eed7f..04a74a009e09213cb84581fb7ccce94700324a50 100644 (file)
@@ -1,6 +1,6 @@
 // run-rustfix
 #![feature(never_type)]
-#![allow(unused_mut, clippy::redundant_allocation)]
+#![allow(unused_mut, unused_tuple_struct_fields, clippy::redundant_allocation)]
 #![warn(clippy::must_use_candidate)]
 use std::rc::Rc;
 use std::sync::atomic::{AtomicBool, Ordering};
index 3732422017104ccaf788e747de9c07ac99eb758a..f04122f4eeab653057d27b5300e9e8c4ef3d2ebe 100644 (file)
@@ -1,6 +1,6 @@
 // run-rustfix
 #![feature(never_type)]
-#![allow(unused_mut, clippy::redundant_allocation)]
+#![allow(unused_mut, unused_tuple_struct_fields, clippy::redundant_allocation)]
 #![warn(clippy::must_use_candidate)]
 use std::rc::Rc;
 use std::sync::atomic::{AtomicBool, Ordering};
index 3710b3e9c81e0ac7263f3df216cbddbe77f00e74..68c987eb4c6771702ffac0374e4463631af244a9 100644 (file)
@@ -1,5 +1,6 @@
 //run-rustfix
 #![warn(clippy::init_numbered_fields)]
+#![allow(unused_tuple_struct_fields)]
 
 #[derive(Default)]
 struct TupleStruct(u32, u32, u8);
index 2af84bc0642a534683b963c3d51b37e85761eae4..2ef4fb4de5370becc102ce60feb1278f6ff267be 100644 (file)
@@ -1,5 +1,6 @@
 //run-rustfix
 #![warn(clippy::init_numbered_fields)]
+#![allow(unused_tuple_struct_fields)]
 
 #[derive(Default)]
 struct TupleStruct(u32, u32, u8);
index 01691c8b141e8a3ad7ac998739f5eb08b4f0a7c4..60c0d7898063f5f07087b3e1da51c47c1603f539 100644 (file)
@@ -1,5 +1,5 @@
 error: used a field initializer for a tuple struct
-  --> $DIR/numbered_fields.rs:18:13
+  --> $DIR/numbered_fields.rs:19:13
    |
 LL |       let _ = TupleStruct {
    |  _____________^
@@ -12,7 +12,7 @@ LL | |     };
    = note: `-D clippy::init-numbered-fields` implied by `-D warnings`
 
 error: used a field initializer for a tuple struct
-  --> $DIR/numbered_fields.rs:25:13
+  --> $DIR/numbered_fields.rs:26:13
    |
 LL |       let _ = TupleStruct {
    |  _____________^
index d8bf66603d9f5840f4878552bf4b34f4d62c5379..07226b0a1a83b272a250e20429b555b30f04bacd 100644 (file)
@@ -1,4 +1,4 @@
-#![allow(unused_variables, clippy::blacklisted_name)]
+#![allow(unused_variables, clippy::disallowed_names)]
 #![warn(clippy::op_ref)]
 use std::collections::HashSet;
 use std::ops::{BitAnd, Mul};
index e12e13a57f1f0b43286aa3b2cf498e385566342e..b6d5e106f057a36ab1503f701f144a37614e98db 100644 (file)
@@ -1,6 +1,7 @@
 // run-rustfix
 #![warn(clippy::option_if_let_else)]
 #![allow(
+    unused_tuple_struct_fields,
     clippy::redundant_closure,
     clippy::ref_option_ref,
     clippy::equatable_if_let,
index b5206fc26a9e13ae091cfe7cbdb528d56c19901a..35bae159343587be7ea1a98c959260a0cc3ab62b 100644 (file)
@@ -1,6 +1,7 @@
 // run-rustfix
 #![warn(clippy::option_if_let_else)]
 #![allow(
+    unused_tuple_struct_fields,
     clippy::redundant_closure,
     clippy::ref_option_ref,
     clippy::equatable_if_let,
index 40aef977b989bfd057c7c7fb1b4b7805fd79e08f..daba606004e114d68ed95d95682e94a4fd59c7f2 100644 (file)
@@ -1,5 +1,5 @@
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:11:5
+  --> $DIR/option_if_let_else.rs:12:5
    |
 LL | /     if let Some(x) = string {
 LL | |         (true, x)
@@ -11,19 +11,19 @@ LL | |     }
    = note: `-D clippy::option-if-let-else` implied by `-D warnings`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:29:13
+  --> $DIR/option_if_let_else.rs:30:13
    |
 LL |     let _ = if let Some(s) = *string { s.len() } else { 0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.map_or(0, |s| s.len())`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:30:13
+  --> $DIR/option_if_let_else.rs:31:13
    |
 LL |     let _ = if let Some(s) = &num { s } else { &0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:31:13
+  --> $DIR/option_if_let_else.rs:32:13
    |
 LL |       let _ = if let Some(s) = &mut num {
    |  _____________^
@@ -43,13 +43,13 @@ LL ~     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:37:13
+  --> $DIR/option_if_let_else.rs:38:13
    |
 LL |     let _ = if let Some(ref s) = num { s } else { &0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:38:13
+  --> $DIR/option_if_let_else.rs:39:13
    |
 LL |       let _ = if let Some(mut s) = num {
    |  _____________^
@@ -69,7 +69,7 @@ LL ~     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:44:13
+  --> $DIR/option_if_let_else.rs:45:13
    |
 LL |       let _ = if let Some(ref mut s) = num {
    |  _____________^
@@ -89,7 +89,7 @@ LL ~     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:53:5
+  --> $DIR/option_if_let_else.rs:54:5
    |
 LL | /     if let Some(x) = arg {
 LL | |         let y = x * x;
@@ -108,7 +108,7 @@ LL +     })
    |
 
 error: use Option::map_or_else instead of an if let/else
-  --> $DIR/option_if_let_else.rs:66:13
+  --> $DIR/option_if_let_else.rs:67:13
    |
 LL |       let _ = if let Some(x) = arg {
    |  _____________^
@@ -120,7 +120,7 @@ LL | |     };
    | |_____^ help: try: `arg.map_or_else(|| side_effect(), |x| x)`
 
 error: use Option::map_or_else instead of an if let/else
-  --> $DIR/option_if_let_else.rs:75:13
+  --> $DIR/option_if_let_else.rs:76:13
    |
 LL |       let _ = if let Some(x) = arg {
    |  _____________^
@@ -143,7 +143,7 @@ LL ~     }, |x| x * x * x * x);
    |
 
 error: use Option::map_or_else instead of an if let/else
-  --> $DIR/option_if_let_else.rs:108:13
+  --> $DIR/option_if_let_else.rs:109:13
    |
 LL | /             if let Some(idx) = s.find('.') {
 LL | |                 vec![s[..idx].to_string(), s[idx..].to_string()]
@@ -153,13 +153,13 @@ LL | |             }
    | |_____________^ help: try: `s.find('.').map_or_else(|| vec![s.to_string()], |idx| vec![s[..idx].to_string(), s[idx..].to_string()])`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:132:13
+  --> $DIR/option_if_let_else.rs:133:13
    |
 LL |     let _ = if let Some(x) = optional { x + 2 } else { 5 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:141:13
+  --> $DIR/option_if_let_else.rs:142:13
    |
 LL |       let _ = if let Some(x) = Some(0) {
    |  _____________^
@@ -181,13 +181,13 @@ LL ~         });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:169:13
+  --> $DIR/option_if_let_else.rs:170:13
    |
 LL |     let _ = if let Some(x) = Some(0) { s.len() + x } else { s.len() };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(0).map_or(s.len(), |x| s.len() + x)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:173:13
+  --> $DIR/option_if_let_else.rs:174:13
    |
 LL |       let _ = if let Some(x) = Some(0) {
    |  _____________^
diff --git a/src/tools/clippy/tests/ui/overly_complex_bool_expr.rs b/src/tools/clippy/tests/ui/overly_complex_bool_expr.rs
new file mode 100644 (file)
index 0000000..04a30a8
--- /dev/null
@@ -0,0 +1,34 @@
+#![feature(lint_reasons)]
+#![allow(unused, clippy::diverging_sub_expression)]
+#![warn(clippy::overly_complex_bool_expr)]
+
+fn main() {
+    let a: bool = unimplemented!();
+    let b: bool = unimplemented!();
+    let c: bool = unimplemented!();
+    let d: bool = unimplemented!();
+    let e: bool = unimplemented!();
+    let _ = a && b || a;
+    let _ = !(a && b);
+    let _ = false && a;
+    // don't lint on cfgs
+    let _ = cfg!(you_shall_not_not_pass) && a;
+    let _ = a || !b || !c || !d || !e;
+    let _ = !(a && b || c);
+}
+
+fn equality_stuff() {
+    let a: i32 = unimplemented!();
+    let b: i32 = unimplemented!();
+    let _ = a == b && a != b;
+    let _ = a < b && a >= b;
+    let _ = a > b && a <= b;
+    let _ = a > b && a == b;
+}
+
+fn check_expect() {
+    let a: i32 = unimplemented!();
+    let b: i32 = unimplemented!();
+    #[expect(clippy::overly_complex_bool_expr)]
+    let _ = a < b && a >= b;
+}
diff --git a/src/tools/clippy/tests/ui/overly_complex_bool_expr.stderr b/src/tools/clippy/tests/ui/overly_complex_bool_expr.stderr
new file mode 100644 (file)
index 0000000..158cae8
--- /dev/null
@@ -0,0 +1,63 @@
+error: this boolean expression contains a logic bug
+  --> $DIR/overly_complex_bool_expr.rs:11:13
+   |
+LL |     let _ = a && b || a;
+   |             ^^^^^^^^^^^ help: it would look like the following: `a`
+   |
+   = note: `-D clippy::overly-complex-bool-expr` implied by `-D warnings`
+help: this expression can be optimized out by applying boolean operations to the outer expression
+  --> $DIR/overly_complex_bool_expr.rs:11:18
+   |
+LL |     let _ = a && b || a;
+   |                  ^
+
+error: this boolean expression contains a logic bug
+  --> $DIR/overly_complex_bool_expr.rs:13:13
+   |
+LL |     let _ = false && a;
+   |             ^^^^^^^^^^ help: it would look like the following: `false`
+   |
+help: this expression can be optimized out by applying boolean operations to the outer expression
+  --> $DIR/overly_complex_bool_expr.rs:13:22
+   |
+LL |     let _ = false && a;
+   |                      ^
+
+error: this boolean expression contains a logic bug
+  --> $DIR/overly_complex_bool_expr.rs:23:13
+   |
+LL |     let _ = a == b && a != b;
+   |             ^^^^^^^^^^^^^^^^ help: it would look like the following: `false`
+   |
+help: this expression can be optimized out by applying boolean operations to the outer expression
+  --> $DIR/overly_complex_bool_expr.rs:23:13
+   |
+LL |     let _ = a == b && a != b;
+   |             ^^^^^^
+
+error: this boolean expression contains a logic bug
+  --> $DIR/overly_complex_bool_expr.rs:24:13
+   |
+LL |     let _ = a < b && a >= b;
+   |             ^^^^^^^^^^^^^^^ help: it would look like the following: `false`
+   |
+help: this expression can be optimized out by applying boolean operations to the outer expression
+  --> $DIR/overly_complex_bool_expr.rs:24:13
+   |
+LL |     let _ = a < b && a >= b;
+   |             ^^^^^
+
+error: this boolean expression contains a logic bug
+  --> $DIR/overly_complex_bool_expr.rs:25:13
+   |
+LL |     let _ = a > b && a <= b;
+   |             ^^^^^^^^^^^^^^^ help: it would look like the following: `false`
+   |
+help: this expression can be optimized out by applying boolean operations to the outer expression
+  --> $DIR/overly_complex_bool_expr.rs:25:13
+   |
+LL |     let _ = a > b && a <= b;
+   |             ^^^^^
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/partialeq_to_none.fixed b/src/tools/clippy/tests/ui/partialeq_to_none.fixed
new file mode 100644 (file)
index 0000000..f3e4c58
--- /dev/null
@@ -0,0 +1,62 @@
+// run-rustfix
+#![warn(clippy::partialeq_to_none)]
+
+struct Foobar;
+
+impl PartialEq<Option<()>> for Foobar {
+    fn eq(&self, _: &Option<()>) -> bool {
+        false
+    }
+}
+
+#[allow(dead_code)]
+fn foo(f: Option<u32>) -> &'static str {
+    if f.is_some() { "yay" } else { "nay" }
+}
+
+fn foobar() -> Option<()> {
+    None
+}
+
+fn bar() -> Result<(), ()> {
+    Ok(())
+}
+
+fn optref() -> &'static &'static Option<()> {
+    &&None
+}
+
+fn main() {
+    let x = Some(0);
+
+    let _ = x.is_none();
+    let _ = x.is_some();
+    let _ = x.is_none();
+    let _ = x.is_some();
+
+    if foobar().is_none() {}
+
+    if bar().ok().is_some() {}
+
+    let _ = Some(1 + 2).is_some();
+
+    let _ = { Some(0) }.is_none();
+
+    let _ = {
+        /*
+          This comment runs long
+        */
+        Some(1)
+    }.is_some();
+
+    // Should not trigger, as `Foobar` is not an `Option` and has no `is_none`
+    let _ = Foobar == None;
+
+    let _ = optref().is_none();
+    let _ = optref().is_some();
+    let _ = optref().is_none();
+    let _ = optref().is_some();
+
+    let x = Box::new(Option::<()>::None);
+    let _ = (*x).is_some();
+}
diff --git a/src/tools/clippy/tests/ui/partialeq_to_none.rs b/src/tools/clippy/tests/ui/partialeq_to_none.rs
new file mode 100644 (file)
index 0000000..767b2a3
--- /dev/null
@@ -0,0 +1,62 @@
+// run-rustfix
+#![warn(clippy::partialeq_to_none)]
+
+struct Foobar;
+
+impl PartialEq<Option<()>> for Foobar {
+    fn eq(&self, _: &Option<()>) -> bool {
+        false
+    }
+}
+
+#[allow(dead_code)]
+fn foo(f: Option<u32>) -> &'static str {
+    if f != None { "yay" } else { "nay" }
+}
+
+fn foobar() -> Option<()> {
+    None
+}
+
+fn bar() -> Result<(), ()> {
+    Ok(())
+}
+
+fn optref() -> &'static &'static Option<()> {
+    &&None
+}
+
+fn main() {
+    let x = Some(0);
+
+    let _ = x == None;
+    let _ = x != None;
+    let _ = None == x;
+    let _ = None != x;
+
+    if foobar() == None {}
+
+    if bar().ok() != None {}
+
+    let _ = Some(1 + 2) != None;
+
+    let _ = { Some(0) } == None;
+
+    let _ = {
+        /*
+          This comment runs long
+        */
+        Some(1)
+    } != None;
+
+    // Should not trigger, as `Foobar` is not an `Option` and has no `is_none`
+    let _ = Foobar == None;
+
+    let _ = optref() == &&None;
+    let _ = &&None != optref();
+    let _ = **optref() == None;
+    let _ = &None != *optref();
+
+    let x = Box::new(Option::<()>::None);
+    let _ = None != *x;
+}
diff --git a/src/tools/clippy/tests/ui/partialeq_to_none.stderr b/src/tools/clippy/tests/ui/partialeq_to_none.stderr
new file mode 100644 (file)
index 0000000..de15a9f
--- /dev/null
@@ -0,0 +1,110 @@
+error: binary comparison to literal `Option::None`
+  --> $DIR/partialeq_to_none.rs:14:8
+   |
+LL |     if f != None { "yay" } else { "nay" }
+   |        ^^^^^^^^^ help: use `Option::is_some()` instead: `f.is_some()`
+   |
+   = note: `-D clippy::partialeq-to-none` implied by `-D warnings`
+
+error: binary comparison to literal `Option::None`
+  --> $DIR/partialeq_to_none.rs:32:13
+   |
+LL |     let _ = x == None;
+   |             ^^^^^^^^^ help: use `Option::is_none()` instead: `x.is_none()`
+
+error: binary comparison to literal `Option::None`
+  --> $DIR/partialeq_to_none.rs:33:13
+   |
+LL |     let _ = x != None;
+   |             ^^^^^^^^^ help: use `Option::is_some()` instead: `x.is_some()`
+
+error: binary comparison to literal `Option::None`
+  --> $DIR/partialeq_to_none.rs:34:13
+   |
+LL |     let _ = None == x;
+   |             ^^^^^^^^^ help: use `Option::is_none()` instead: `x.is_none()`
+
+error: binary comparison to literal `Option::None`
+  --> $DIR/partialeq_to_none.rs:35:13
+   |
+LL |     let _ = None != x;
+   |             ^^^^^^^^^ help: use `Option::is_some()` instead: `x.is_some()`
+
+error: binary comparison to literal `Option::None`
+  --> $DIR/partialeq_to_none.rs:37:8
+   |
+LL |     if foobar() == None {}
+   |        ^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `foobar().is_none()`
+
+error: binary comparison to literal `Option::None`
+  --> $DIR/partialeq_to_none.rs:39:8
+   |
+LL |     if bar().ok() != None {}
+   |        ^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `bar().ok().is_some()`
+
+error: binary comparison to literal `Option::None`
+  --> $DIR/partialeq_to_none.rs:41:13
+   |
+LL |     let _ = Some(1 + 2) != None;
+   |             ^^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `Some(1 + 2).is_some()`
+
+error: binary comparison to literal `Option::None`
+  --> $DIR/partialeq_to_none.rs:43:13
+   |
+LL |     let _ = { Some(0) } == None;
+   |             ^^^^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `{ Some(0) }.is_none()`
+
+error: binary comparison to literal `Option::None`
+  --> $DIR/partialeq_to_none.rs:45:13
+   |
+LL |       let _ = {
+   |  _____________^
+LL | |         /*
+LL | |           This comment runs long
+LL | |         */
+LL | |         Some(1)
+LL | |     } != None;
+   | |_____________^
+   |
+help: use `Option::is_some()` instead
+   |
+LL ~     let _ = {
+LL +         /*
+LL +           This comment runs long
+LL +         */
+LL +         Some(1)
+LL ~     }.is_some();
+   |
+
+error: binary comparison to literal `Option::None`
+  --> $DIR/partialeq_to_none.rs:55:13
+   |
+LL |     let _ = optref() == &&None;
+   |             ^^^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `optref().is_none()`
+
+error: binary comparison to literal `Option::None`
+  --> $DIR/partialeq_to_none.rs:56:13
+   |
+LL |     let _ = &&None != optref();
+   |             ^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `optref().is_some()`
+
+error: binary comparison to literal `Option::None`
+  --> $DIR/partialeq_to_none.rs:57:13
+   |
+LL |     let _ = **optref() == None;
+   |             ^^^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `optref().is_none()`
+
+error: binary comparison to literal `Option::None`
+  --> $DIR/partialeq_to_none.rs:58:13
+   |
+LL |     let _ = &None != *optref();
+   |             ^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `optref().is_some()`
+
+error: binary comparison to literal `Option::None`
+  --> $DIR/partialeq_to_none.rs:61:13
+   |
+LL |     let _ = None != *x;
+   |             ^^^^^^^^^^ help: use `Option::is_some()` instead: `(*x).is_some()`
+
+error: aborting due to 15 previous errors
+
index 18e8a2e01e0227cc02478346c42822a45e4b1314..432972bbc31757e75681163fff8b4d9dd9774b1a 100644 (file)
@@ -1,5 +1,5 @@
 #![warn(clippy::rc_mutex)]
-#![allow(unused, clippy::blacklisted_name)]
+#![allow(unused, clippy::disallowed_names)]
 
 use std::rc::Rc;
 use std::sync::Mutex;
index cf7d8c6e349af2c685037126830a6bf0ac2eb029..574d34aed2d87d1260b8b8558c7d36e28785c346 100644 (file)
@@ -1,7 +1,5 @@
 #![warn(clippy::all)]
-#![allow(clippy::boxed_local, clippy::needless_pass_by_value)]
-#![allow(clippy::blacklisted_name, unused_variables, dead_code)]
-#![allow(unused_imports)]
+#![allow(clippy::boxed_local, clippy::disallowed_names)]
 
 pub struct MyStruct;
 
@@ -9,13 +7,7 @@ pub struct SubT<T> {
     foo: T,
 }
 
-pub enum MyEnum {
-    One,
-    Two,
-}
-
 mod outer_box {
-    use crate::MyEnum;
     use crate::MyStruct;
     use crate::SubT;
     use std::boxed::Box;
@@ -36,7 +28,6 @@ pub fn box_test9<T>(foo: Box<Arc<T>>) -> Box<Arc<SubT<T>>> {
 }
 
 mod outer_rc {
-    use crate::MyEnum;
     use crate::MyStruct;
     use crate::SubT;
     use std::boxed::Box;
@@ -57,7 +48,6 @@ pub fn rc_test9<T>(foo: Rc<Arc<T>>) -> Rc<Arc<SubT<T>>> {
 }
 
 mod outer_arc {
-    use crate::MyEnum;
     use crate::MyStruct;
     use crate::SubT;
     use std::boxed::Box;
index fab1b069fcbc72462394b367508cb6f34137c22d..54d4d88dba81933ae1962c267a88ffa35cfae47b 100644 (file)
@@ -1,5 +1,5 @@
 error: usage of `Box<Rc<T>>`
-  --> $DIR/redundant_allocation.rs:25:30
+  --> $DIR/redundant_allocation.rs:17:30
    |
 LL |     pub fn box_test6<T>(foo: Box<Rc<T>>) {}
    |                              ^^^^^^^^^^
@@ -9,7 +9,7 @@ LL |     pub fn box_test6<T>(foo: Box<Rc<T>>) {}
    = help: consider using just `Box<T>` or `Rc<T>`
 
 error: usage of `Box<Arc<T>>`
-  --> $DIR/redundant_allocation.rs:27:30
+  --> $DIR/redundant_allocation.rs:19:30
    |
 LL |     pub fn box_test7<T>(foo: Box<Arc<T>>) {}
    |                              ^^^^^^^^^^^
@@ -18,7 +18,7 @@ LL |     pub fn box_test7<T>(foo: Box<Arc<T>>) {}
    = help: consider using just `Box<T>` or `Arc<T>`
 
 error: usage of `Box<Rc<SubT<usize>>>`
-  --> $DIR/redundant_allocation.rs:29:27
+  --> $DIR/redundant_allocation.rs:21:27
    |
 LL |     pub fn box_test8() -> Box<Rc<SubT<usize>>> {
    |                           ^^^^^^^^^^^^^^^^^^^^
@@ -27,7 +27,7 @@ LL |     pub fn box_test8() -> Box<Rc<SubT<usize>>> {
    = help: consider using just `Box<SubT<usize>>` or `Rc<SubT<usize>>`
 
 error: usage of `Box<Arc<T>>`
-  --> $DIR/redundant_allocation.rs:33:30
+  --> $DIR/redundant_allocation.rs:25:30
    |
 LL |     pub fn box_test9<T>(foo: Box<Arc<T>>) -> Box<Arc<SubT<T>>> {
    |                              ^^^^^^^^^^^
@@ -36,7 +36,7 @@ LL |     pub fn box_test9<T>(foo: Box<Arc<T>>) -> Box<Arc<SubT<T>>> {
    = help: consider using just `Box<T>` or `Arc<T>`
 
 error: usage of `Box<Arc<SubT<T>>>`
-  --> $DIR/redundant_allocation.rs:33:46
+  --> $DIR/redundant_allocation.rs:25:46
    |
 LL |     pub fn box_test9<T>(foo: Box<Arc<T>>) -> Box<Arc<SubT<T>>> {
    |                                              ^^^^^^^^^^^^^^^^^
@@ -45,7 +45,7 @@ LL |     pub fn box_test9<T>(foo: Box<Arc<T>>) -> Box<Arc<SubT<T>>> {
    = help: consider using just `Box<SubT<T>>` or `Arc<SubT<T>>`
 
 error: usage of `Rc<Box<bool>>`
-  --> $DIR/redundant_allocation.rs:46:24
+  --> $DIR/redundant_allocation.rs:37:24
    |
 LL |     pub fn rc_test5(a: Rc<Box<bool>>) {}
    |                        ^^^^^^^^^^^^^
@@ -54,7 +54,7 @@ LL |     pub fn rc_test5(a: Rc<Box<bool>>) {}
    = help: consider using just `Rc<bool>` or `Box<bool>`
 
 error: usage of `Rc<Arc<bool>>`
-  --> $DIR/redundant_allocation.rs:48:24
+  --> $DIR/redundant_allocation.rs:39:24
    |
 LL |     pub fn rc_test7(a: Rc<Arc<bool>>) {}
    |                        ^^^^^^^^^^^^^
@@ -63,7 +63,7 @@ LL |     pub fn rc_test7(a: Rc<Arc<bool>>) {}
    = help: consider using just `Rc<bool>` or `Arc<bool>`
 
 error: usage of `Rc<Box<SubT<usize>>>`
-  --> $DIR/redundant_allocation.rs:50:26
+  --> $DIR/redundant_allocation.rs:41:26
    |
 LL |     pub fn rc_test8() -> Rc<Box<SubT<usize>>> {
    |                          ^^^^^^^^^^^^^^^^^^^^
@@ -72,7 +72,7 @@ LL |     pub fn rc_test8() -> Rc<Box<SubT<usize>>> {
    = help: consider using just `Rc<SubT<usize>>` or `Box<SubT<usize>>`
 
 error: usage of `Rc<Arc<T>>`
-  --> $DIR/redundant_allocation.rs:54:29
+  --> $DIR/redundant_allocation.rs:45:29
    |
 LL |     pub fn rc_test9<T>(foo: Rc<Arc<T>>) -> Rc<Arc<SubT<T>>> {
    |                             ^^^^^^^^^^
@@ -81,7 +81,7 @@ LL |     pub fn rc_test9<T>(foo: Rc<Arc<T>>) -> Rc<Arc<SubT<T>>> {
    = help: consider using just `Rc<T>` or `Arc<T>`
 
 error: usage of `Rc<Arc<SubT<T>>>`
-  --> $DIR/redundant_allocation.rs:54:44
+  --> $DIR/redundant_allocation.rs:45:44
    |
 LL |     pub fn rc_test9<T>(foo: Rc<Arc<T>>) -> Rc<Arc<SubT<T>>> {
    |                                            ^^^^^^^^^^^^^^^^
@@ -90,7 +90,7 @@ LL |     pub fn rc_test9<T>(foo: Rc<Arc<T>>) -> Rc<Arc<SubT<T>>> {
    = help: consider using just `Rc<SubT<T>>` or `Arc<SubT<T>>`
 
 error: usage of `Arc<Box<bool>>`
-  --> $DIR/redundant_allocation.rs:67:25
+  --> $DIR/redundant_allocation.rs:57:25
    |
 LL |     pub fn arc_test5(a: Arc<Box<bool>>) {}
    |                         ^^^^^^^^^^^^^^
@@ -99,7 +99,7 @@ LL |     pub fn arc_test5(a: Arc<Box<bool>>) {}
    = help: consider using just `Arc<bool>` or `Box<bool>`
 
 error: usage of `Arc<Rc<bool>>`
-  --> $DIR/redundant_allocation.rs:69:25
+  --> $DIR/redundant_allocation.rs:59:25
    |
 LL |     pub fn arc_test6(a: Arc<Rc<bool>>) {}
    |                         ^^^^^^^^^^^^^
@@ -108,7 +108,7 @@ LL |     pub fn arc_test6(a: Arc<Rc<bool>>) {}
    = help: consider using just `Arc<bool>` or `Rc<bool>`
 
 error: usage of `Arc<Box<SubT<usize>>>`
-  --> $DIR/redundant_allocation.rs:71:27
+  --> $DIR/redundant_allocation.rs:61:27
    |
 LL |     pub fn arc_test8() -> Arc<Box<SubT<usize>>> {
    |                           ^^^^^^^^^^^^^^^^^^^^^
@@ -117,7 +117,7 @@ LL |     pub fn arc_test8() -> Arc<Box<SubT<usize>>> {
    = help: consider using just `Arc<SubT<usize>>` or `Box<SubT<usize>>`
 
 error: usage of `Arc<Rc<T>>`
-  --> $DIR/redundant_allocation.rs:75:30
+  --> $DIR/redundant_allocation.rs:65:30
    |
 LL |     pub fn arc_test9<T>(foo: Arc<Rc<T>>) -> Arc<Rc<SubT<T>>> {
    |                              ^^^^^^^^^^
@@ -126,7 +126,7 @@ LL |     pub fn arc_test9<T>(foo: Arc<Rc<T>>) -> Arc<Rc<SubT<T>>> {
    = help: consider using just `Arc<T>` or `Rc<T>`
 
 error: usage of `Arc<Rc<SubT<T>>>`
-  --> $DIR/redundant_allocation.rs:75:45
+  --> $DIR/redundant_allocation.rs:65:45
    |
 LL |     pub fn arc_test9<T>(foo: Arc<Rc<T>>) -> Arc<Rc<SubT<T>>> {
    |                                             ^^^^^^^^^^^^^^^^
@@ -135,7 +135,7 @@ LL |     pub fn arc_test9<T>(foo: Arc<Rc<T>>) -> Arc<Rc<SubT<T>>> {
    = help: consider using just `Arc<SubT<T>>` or `Rc<SubT<T>>`
 
 error: usage of `Rc<Box<Box<dyn T>>>`
-  --> $DIR/redundant_allocation.rs:97:27
+  --> $DIR/redundant_allocation.rs:87:27
    |
 LL |     pub fn test_rc_box(_: Rc<Box<Box<dyn T>>>) {}
    |                           ^^^^^^^^^^^^^^^^^^^
@@ -144,7 +144,7 @@ LL |     pub fn test_rc_box(_: Rc<Box<Box<dyn T>>>) {}
    = help: consider using just `Rc<Box<dyn T>>` or `Box<Box<dyn T>>`
 
 error: usage of `Rc<Box<Box<str>>>`
-  --> $DIR/redundant_allocation.rs:129:31
+  --> $DIR/redundant_allocation.rs:119:31
    |
 LL |     pub fn test_rc_box_str(_: Rc<Box<Box<str>>>) {}
    |                               ^^^^^^^^^^^^^^^^^
@@ -153,7 +153,7 @@ LL |     pub fn test_rc_box_str(_: Rc<Box<Box<str>>>) {}
    = help: consider using just `Rc<Box<str>>` or `Box<Box<str>>`
 
 error: usage of `Rc<Box<Box<[usize]>>>`
-  --> $DIR/redundant_allocation.rs:130:33
+  --> $DIR/redundant_allocation.rs:120:33
    |
 LL |     pub fn test_rc_box_slice(_: Rc<Box<Box<[usize]>>>) {}
    |                                 ^^^^^^^^^^^^^^^^^^^^^
@@ -162,7 +162,7 @@ LL |     pub fn test_rc_box_slice(_: Rc<Box<Box<[usize]>>>) {}
    = help: consider using just `Rc<Box<[usize]>>` or `Box<Box<[usize]>>`
 
 error: usage of `Rc<Box<Box<Path>>>`
-  --> $DIR/redundant_allocation.rs:131:32
+  --> $DIR/redundant_allocation.rs:121:32
    |
 LL |     pub fn test_rc_box_path(_: Rc<Box<Box<Path>>>) {}
    |                                ^^^^^^^^^^^^^^^^^^
@@ -171,7 +171,7 @@ LL |     pub fn test_rc_box_path(_: Rc<Box<Box<Path>>>) {}
    = help: consider using just `Rc<Box<Path>>` or `Box<Box<Path>>`
 
 error: usage of `Rc<Box<Box<DynSized>>>`
-  --> $DIR/redundant_allocation.rs:132:34
+  --> $DIR/redundant_allocation.rs:122:34
    |
 LL |     pub fn test_rc_box_custom(_: Rc<Box<Box<DynSized>>>) {}
    |                                  ^^^^^^^^^^^^^^^^^^^^^^
index e7ed84731c02e4d64ec6e45cd5782d0e632b2416..6db02718c70bbe8eb54e349f10394d6a816b2f53 100644 (file)
@@ -1,7 +1,7 @@
 // run-rustfix
 #![warn(clippy::all)]
 #![allow(clippy::boxed_local, clippy::needless_pass_by_value)]
-#![allow(clippy::blacklisted_name, unused_variables, dead_code)]
+#![allow(clippy::disallowed_names, unused_variables, dead_code)]
 #![allow(unused_imports)]
 
 pub struct MyStruct;
index de763f98b5c89fb55d344bff8b836fde26f2f916..c15806f30c049c4c0715dfc897759c141edb3477 100644 (file)
@@ -1,7 +1,7 @@
 // run-rustfix
 #![warn(clippy::all)]
 #![allow(clippy::boxed_local, clippy::needless_pass_by_value)]
-#![allow(clippy::blacklisted_name, unused_variables, dead_code)]
+#![allow(clippy::disallowed_names, unused_variables, dead_code)]
 #![allow(unused_imports)]
 
 pub struct MyStruct;
index 0abca6fca0613b4469c74af12206f25c7a0a1b41..7cd687c95a003f14c770fed009c8c4062359156b 100644 (file)
@@ -1,8 +1,28 @@
 // run-rustfix
 
+#![feature(async_closure)]
 #![warn(clippy::redundant_closure_call)]
 #![allow(unused)]
 
+async fn something() -> u32 {
+    21
+}
+
+async fn something_else() -> u32 {
+    2
+}
+
 fn main() {
     let a = 42;
+    let b = async {
+        let x = something().await;
+        let y = something_else().await;
+        x * y
+    };
+    let c = {
+        let x = 21;
+        let y = 2;
+        x * y
+    };
+    let d = async { something().await };
 }
index f8b9d37a5cc4e757efe2960f1a1a804a62e839cd..37e4d2238641576fbff1184315d1264d2741f205 100644 (file)
@@ -1,8 +1,28 @@
 // run-rustfix
 
+#![feature(async_closure)]
 #![warn(clippy::redundant_closure_call)]
 #![allow(unused)]
 
+async fn something() -> u32 {
+    21
+}
+
+async fn something_else() -> u32 {
+    2
+}
+
 fn main() {
     let a = (|| 42)();
+    let b = (async || {
+        let x = something().await;
+        let y = something_else().await;
+        x * y
+    })();
+    let c = (|| {
+        let x = 21;
+        let y = 2;
+        x * y
+    })();
+    let d = (async || something().await)();
 }
index afd704ef12a934f913454334a42bd68c5a95a954..56a8e57c0c362097b74fb1b000b1438a1c62b097 100644 (file)
@@ -1,10 +1,56 @@
 error: try not to call a closure in the expression where it is declared
-  --> $DIR/redundant_closure_call_fixable.rs:7:13
+  --> $DIR/redundant_closure_call_fixable.rs:16:13
    |
 LL |     let a = (|| 42)();
    |             ^^^^^^^^^ help: try doing something like: `42`
    |
    = note: `-D clippy::redundant-closure-call` implied by `-D warnings`
 
-error: aborting due to previous error
+error: try not to call a closure in the expression where it is declared
+  --> $DIR/redundant_closure_call_fixable.rs:17:13
+   |
+LL |       let b = (async || {
+   |  _____________^
+LL | |         let x = something().await;
+LL | |         let y = something_else().await;
+LL | |         x * y
+LL | |     })();
+   | |________^
+   |
+help: try doing something like
+   |
+LL ~     let b = async {
+LL +         let x = something().await;
+LL +         let y = something_else().await;
+LL +         x * y
+LL ~     };
+   |
+
+error: try not to call a closure in the expression where it is declared
+  --> $DIR/redundant_closure_call_fixable.rs:22:13
+   |
+LL |       let c = (|| {
+   |  _____________^
+LL | |         let x = 21;
+LL | |         let y = 2;
+LL | |         x * y
+LL | |     })();
+   | |________^
+   |
+help: try doing something like
+   |
+LL ~     let c = {
+LL +         let x = 21;
+LL +         let y = 2;
+LL +         x * y
+LL ~     };
+   |
+
+error: try not to call a closure in the expression where it is declared
+  --> $DIR/redundant_closure_call_fixable.rs:27:13
+   |
+LL |     let d = (async || something().await)();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `async { something().await }`
+
+error: aborting due to 4 previous errors
 
index 53288be9404c2d03fbb9007abcfaa38067a930a9..9cbad2269a099c5b71756222744dabb78f9115a6 100644 (file)
@@ -4,6 +4,7 @@
 
 // run-rustfix
 
+#![allow(clippy::disallowed_names)]
 #![allow(clippy::blocks_in_if_conditions)]
 #![allow(clippy::box_collection)]
 #![allow(clippy::redundant_static_lifetimes)]
@@ -14,6 +15,7 @@
 #![allow(clippy::for_loops_over_fallibles)]
 #![allow(clippy::useless_conversion)]
 #![allow(clippy::match_result_ok)]
+#![allow(clippy::overly_complex_bool_expr)]
 #![allow(clippy::new_without_default)]
 #![allow(clippy::bind_instead_of_map)]
 #![allow(clippy::expect_used)]
@@ -33,6 +35,7 @@
 #![allow(temporary_cstring_as_ptr)]
 #![allow(unknown_lints)]
 #![allow(unused_labels)]
+#![warn(clippy::disallowed_names)]
 #![warn(clippy::blocks_in_if_conditions)]
 #![warn(clippy::blocks_in_if_conditions)]
 #![warn(clippy::box_collection)]
@@ -45,6 +48,7 @@
 #![warn(clippy::for_loops_over_fallibles)]
 #![warn(clippy::useless_conversion)]
 #![warn(clippy::match_result_ok)]
+#![warn(clippy::overly_complex_bool_expr)]
 #![warn(clippy::new_without_default)]
 #![warn(clippy::bind_instead_of_map)]
 #![warn(clippy::expect_used)]
index 539f34f847acdf580420d739e13fff8a09c51af4..9153c0dab0290aa213307bdc47827e1f5af4ca1e 100644 (file)
@@ -4,6 +4,7 @@
 
 // run-rustfix
 
+#![allow(clippy::disallowed_names)]
 #![allow(clippy::blocks_in_if_conditions)]
 #![allow(clippy::box_collection)]
 #![allow(clippy::redundant_static_lifetimes)]
@@ -14,6 +15,7 @@
 #![allow(clippy::for_loops_over_fallibles)]
 #![allow(clippy::useless_conversion)]
 #![allow(clippy::match_result_ok)]
+#![allow(clippy::overly_complex_bool_expr)]
 #![allow(clippy::new_without_default)]
 #![allow(clippy::bind_instead_of_map)]
 #![allow(clippy::expect_used)]
@@ -33,6 +35,7 @@
 #![allow(temporary_cstring_as_ptr)]
 #![allow(unknown_lints)]
 #![allow(unused_labels)]
+#![warn(clippy::blacklisted_name)]
 #![warn(clippy::block_in_if_condition_expr)]
 #![warn(clippy::block_in_if_condition_stmt)]
 #![warn(clippy::box_vec)]
@@ -45,6 +48,7 @@
 #![warn(clippy::for_loop_over_result)]
 #![warn(clippy::identity_conversion)]
 #![warn(clippy::if_let_some_result)]
+#![warn(clippy::logic_bug)]
 #![warn(clippy::new_without_default_derive)]
 #![warn(clippy::option_and_then_some)]
 #![warn(clippy::option_expect_used)]
index 8ea46b580a8c9df81e02b29ab21285e3b570d9a3..9c03ea914bb65fef6c94b919523a36ab24d9e833 100644 (file)
+error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names`
+  --> $DIR/rename.rs:38:9
+   |
+LL | #![warn(clippy::blacklisted_name)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names`
+   |
+   = note: `-D renamed-and-removed-lints` implied by `-D warnings`
+
 error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions`
-  --> $DIR/rename.rs:36:9
+  --> $DIR/rename.rs:39:9
    |
 LL | #![warn(clippy::block_in_if_condition_expr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
-   |
-   = note: `-D renamed-and-removed-lints` implied by `-D warnings`
 
 error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions`
-  --> $DIR/rename.rs:37:9
+  --> $DIR/rename.rs:40:9
    |
 LL | #![warn(clippy::block_in_if_condition_stmt)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
 
 error: lint `clippy::box_vec` has been renamed to `clippy::box_collection`
-  --> $DIR/rename.rs:38:9
+  --> $DIR/rename.rs:41:9
    |
 LL | #![warn(clippy::box_vec)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection`
 
 error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
-  --> $DIR/rename.rs:39:9
+  --> $DIR/rename.rs:42:9
    |
 LL | #![warn(clippy::const_static_lifetime)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
 
 error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity`
-  --> $DIR/rename.rs:40:9
+  --> $DIR/rename.rs:43:9
    |
 LL | #![warn(clippy::cyclomatic_complexity)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
 
 error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods`
-  --> $DIR/rename.rs:41:9
+  --> $DIR/rename.rs:44:9
    |
 LL | #![warn(clippy::disallowed_method)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods`
 
 error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types`
-  --> $DIR/rename.rs:42:9
+  --> $DIR/rename.rs:45:9
    |
 LL | #![warn(clippy::disallowed_type)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types`
 
 error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression`
-  --> $DIR/rename.rs:43:9
+  --> $DIR/rename.rs:46:9
    |
 LL | #![warn(clippy::eval_order_dependence)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
 
 error: lint `clippy::for_loop_over_option` has been renamed to `clippy::for_loops_over_fallibles`
-  --> $DIR/rename.rs:44:9
+  --> $DIR/rename.rs:47:9
    |
 LL | #![warn(clippy::for_loop_over_option)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles`
 
 error: lint `clippy::for_loop_over_result` has been renamed to `clippy::for_loops_over_fallibles`
-  --> $DIR/rename.rs:45:9
+  --> $DIR/rename.rs:48:9
    |
 LL | #![warn(clippy::for_loop_over_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles`
 
 error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
-  --> $DIR/rename.rs:46:9
+  --> $DIR/rename.rs:49:9
    |
 LL | #![warn(clippy::identity_conversion)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
 
 error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
-  --> $DIR/rename.rs:47:9
+  --> $DIR/rename.rs:50:9
    |
 LL | #![warn(clippy::if_let_some_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
 
+error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr`
+  --> $DIR/rename.rs:51:9
+   |
+LL | #![warn(clippy::logic_bug)]
+   |         ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr`
+
 error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
-  --> $DIR/rename.rs:48:9
+  --> $DIR/rename.rs:52:9
    |
 LL | #![warn(clippy::new_without_default_derive)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
 
 error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
-  --> $DIR/rename.rs:49:9
+  --> $DIR/rename.rs:53:9
    |
 LL | #![warn(clippy::option_and_then_some)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
 
 error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
-  --> $DIR/rename.rs:50:9
+  --> $DIR/rename.rs:54:9
    |
 LL | #![warn(clippy::option_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:51:9
+  --> $DIR/rename.rs:55:9
    |
 LL | #![warn(clippy::option_map_unwrap_or)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:52:9
+  --> $DIR/rename.rs:56:9
    |
 LL | #![warn(clippy::option_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> $DIR/rename.rs:53:9
+  --> $DIR/rename.rs:57:9
    |
 LL | #![warn(clippy::option_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow`
-  --> $DIR/rename.rs:54:9
+  --> $DIR/rename.rs:58:9
    |
 LL | #![warn(clippy::ref_in_deref)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
 
 error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
-  --> $DIR/rename.rs:55:9
+  --> $DIR/rename.rs:59:9
    |
 LL | #![warn(clippy::result_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:56:9
+  --> $DIR/rename.rs:60:9
    |
 LL | #![warn(clippy::result_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> $DIR/rename.rs:57:9
+  --> $DIR/rename.rs:61:9
    |
 LL | #![warn(clippy::result_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
-  --> $DIR/rename.rs:58:9
+  --> $DIR/rename.rs:62:9
    |
 LL | #![warn(clippy::single_char_push_str)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
 
 error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
-  --> $DIR/rename.rs:59:9
+  --> $DIR/rename.rs:63:9
    |
 LL | #![warn(clippy::stutter)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
 
 error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl`
-  --> $DIR/rename.rs:60:9
+  --> $DIR/rename.rs:64:9
    |
 LL | #![warn(clippy::to_string_in_display)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl`
 
 error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
-  --> $DIR/rename.rs:61:9
+  --> $DIR/rename.rs:65:9
    |
 LL | #![warn(clippy::zero_width_space)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
 
 error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
-  --> $DIR/rename.rs:62:9
+  --> $DIR/rename.rs:66:9
    |
 LL | #![warn(clippy::drop_bounds)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
 
 error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
-  --> $DIR/rename.rs:63:9
+  --> $DIR/rename.rs:67:9
    |
 LL | #![warn(clippy::into_iter_on_array)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
 
 error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
-  --> $DIR/rename.rs:64:9
+  --> $DIR/rename.rs:68:9
    |
 LL | #![warn(clippy::invalid_atomic_ordering)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
 
 error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
-  --> $DIR/rename.rs:65:9
+  --> $DIR/rename.rs:69:9
    |
 LL | #![warn(clippy::invalid_ref)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
 
 error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
-  --> $DIR/rename.rs:66:9
+  --> $DIR/rename.rs:70:9
    |
 LL | #![warn(clippy::mem_discriminant_non_enum)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
 
 error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
-  --> $DIR/rename.rs:67:9
+  --> $DIR/rename.rs:71:9
    |
 LL | #![warn(clippy::panic_params)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
 
 error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
-  --> $DIR/rename.rs:68:9
+  --> $DIR/rename.rs:72:9
    |
 LL | #![warn(clippy::temporary_cstring_as_ptr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
 
 error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
-  --> $DIR/rename.rs:69:9
+  --> $DIR/rename.rs:73:9
    |
 LL | #![warn(clippy::unknown_clippy_lints)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
 
 error: lint `clippy::unused_label` has been renamed to `unused_labels`
-  --> $DIR/rename.rs:70:9
+  --> $DIR/rename.rs:74:9
    |
 LL | #![warn(clippy::unused_label)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
 
-error: aborting due to 35 previous errors
+error: aborting due to 37 previous errors
 
index 3d2295912c9fd08827596a2cef226b76f58e17b0..a48829caac019249bab85a83552340e117574e82 100644 (file)
@@ -48,9 +48,9 @@ fn ifs_same_cond_fn() {
     }
 
     let mut v = vec![1];
-    if v.pop() == None {
+    if v.pop().is_none() {
         //~ ERROR ifs same condition
-    } else if v.pop() == None {
+    } else if v.pop().is_none() {
     }
 
     if v.len() == 42 {
index 71e82910ef7529e6cbef6c67426b334301941ba0..cd438b830401d746587e10d51b646be076b6de58 100644 (file)
@@ -50,14 +50,14 @@ LL |     if obj.method_arg(a) {
 error: this `if` has the same function call as a previous `if`
   --> $DIR/same_functions_in_if_condition.rs:53:15
    |
-LL |     } else if v.pop() == None {
-   |               ^^^^^^^^^^^^^^^
+LL |     } else if v.pop().is_none() {
+   |               ^^^^^^^^^^^^^^^^^
    |
 note: same as this
   --> $DIR/same_functions_in_if_condition.rs:51:8
    |
-LL |     if v.pop() == None {
-   |        ^^^^^^^^^^^^^^^
+LL |     if v.pop().is_none() {
+   |        ^^^^^^^^^^^^^^^^^
 
 error: this `if` has the same function call as a previous `if`
   --> $DIR/same_functions_in_if_condition.rs:58:15
index a522c0f08b207a5abd7cf037c304b39357c4a4b3..a551c19d98bcddda9bfae895033c143aecde5a50 100644 (file)
@@ -1,7 +1,7 @@
 // aux-build:option_helpers.rs
 
 #![warn(clippy::skip_while_next)]
-#![allow(clippy::blacklisted_name)]
+#![allow(clippy::disallowed_names)]
 
 extern crate option_helpers;
 use option_helpers::IteratorFalsePositives;
index 3329efbd4ff429f1daabef797cf9793513b010c0..24b229235d33a476f5d7ba5e45d7112a188658be 100644 (file)
@@ -2,7 +2,7 @@
 
 #![warn(clippy::all)]
 #![allow(
-    clippy::blacklisted_name,
+    clippy::disallowed_names,
     clippy::no_effect,
     clippy::redundant_clone,
     redundant_semicolons,
index 8179ac1f2ab028a7a5d5eb26a0adcb6a24c811c7..a318c27919c8a4fbdb972f59d48496c695f9e590 100644 (file)
@@ -2,7 +2,7 @@
 
 #![warn(clippy::all)]
 #![allow(
-    clippy::blacklisted_name,
+    clippy::disallowed_names,
     clippy::no_effect,
     clippy::redundant_clone,
     redundant_semicolons,
index 8f78f16a0a1a65939cd427b4a23fc64bf897a706..c0c64ebcabfbb66f979f9d6b4a81d0ee1189dd3b 100644 (file)
@@ -2,7 +2,7 @@
 // normalize-stderr-test "\(limit: \d+ byte\)" -> "(limit: N byte)"
 
 #![deny(clippy::trivially_copy_pass_by_ref)]
-#![allow(clippy::blacklisted_name, clippy::redundant_field_names)]
+#![allow(clippy::disallowed_names, clippy::redundant_field_names)]
 
 #[derive(Copy, Clone)]
 struct Foo(u32);
index 38be87bddf19845de6797e70384317bdbfb91162..7bf3adc07ac5645dcecf0abbc88a5743cf416103 100644 (file)
@@ -1,3 +1,5 @@
+// aux-build: proc_macro_with_span.rs
+
 #![warn(clippy::unit_arg)]
 #![allow(
     clippy::no_effect,
@@ -8,9 +10,13 @@
     clippy::or_fun_call,
     clippy::needless_question_mark,
     clippy::self_named_constructors,
-    clippy::let_unit_value
+    clippy::let_unit_value,
+    clippy::never_loop
 )]
 
+extern crate proc_macro_with_span;
+
+use proc_macro_with_span::with_span;
 use std::fmt::Debug;
 
 fn foo<T: Debug>(t: T) {
@@ -127,6 +133,10 @@ fn returning_expr() -> Option<()> {
 
 fn taking_multiple_units(a: (), b: ()) {}
 
+fn proc_macro() {
+    with_span!(span taking_multiple_units(unsafe { (); }, 'x: loop { break 'x (); }));
+}
+
 fn main() {
     bad();
     ok();
index 11cfe66a30e850975c859a3822d2f8c34efa7ad3..1de9d44bb0d6ea80251502616e5843d835d8264a 100644 (file)
@@ -1,5 +1,5 @@
 error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:57:5
+  --> $DIR/unit_arg.rs:63:5
    |
 LL | /     foo({
 LL | |         1;
@@ -20,7 +20,7 @@ LL ~     foo(());
    |
 
 error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:60:5
+  --> $DIR/unit_arg.rs:66:5
    |
 LL |     foo(foo(1));
    |     ^^^^^^^^^^^
@@ -32,7 +32,7 @@ LL ~     foo(());
    |
 
 error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:61:5
+  --> $DIR/unit_arg.rs:67:5
    |
 LL | /     foo({
 LL | |         foo(1);
@@ -54,7 +54,7 @@ LL ~     foo(());
    |
 
 error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:66:5
+  --> $DIR/unit_arg.rs:72:5
    |
 LL | /     b.bar({
 LL | |         1;
@@ -74,7 +74,7 @@ LL ~     b.bar(());
    |
 
 error: passing unit values to a function
-  --> $DIR/unit_arg.rs:69:5
+  --> $DIR/unit_arg.rs:75:5
    |
 LL |     taking_multiple_units(foo(0), foo(1));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -87,7 +87,7 @@ LL ~     taking_multiple_units((), ());
    |
 
 error: passing unit values to a function
-  --> $DIR/unit_arg.rs:70:5
+  --> $DIR/unit_arg.rs:76:5
    |
 LL | /     taking_multiple_units(foo(0), {
 LL | |         foo(1);
@@ -110,7 +110,7 @@ LL ~     taking_multiple_units((), ());
    |
 
 error: passing unit values to a function
-  --> $DIR/unit_arg.rs:74:5
+  --> $DIR/unit_arg.rs:80:5
    |
 LL | /     taking_multiple_units(
 LL | |         {
@@ -146,7 +146,7 @@ LL ~     );
    |
 
 error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:85:13
+  --> $DIR/unit_arg.rs:91:13
    |
 LL |     None.or(Some(foo(2)));
    |             ^^^^^^^^^^^^
@@ -160,7 +160,7 @@ LL ~     });
    |
 
 error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:88:5
+  --> $DIR/unit_arg.rs:94:5
    |
 LL |     foo(foo(()));
    |     ^^^^^^^^^^^^
@@ -172,7 +172,7 @@ LL ~     foo(());
    |
 
 error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:125:5
+  --> $DIR/unit_arg.rs:131:5
    |
 LL |     Some(foo(1))
    |     ^^^^^^^^^^^^
index e726b652ef1ed7a18ba4b950137770e271ab57f7..a67363b09ea5ac7e675d053ed791a05466435fb2 100644 (file)
@@ -1,6 +1,7 @@
 // run-rustfix
 
 #![warn(clippy::unreadable_literal)]
+#![allow(unused_tuple_struct_fields)]
 
 struct Foo(u64);
 
index 5bbb2fc9dc137c28339316a5d5c7dc3a85792d64..82f04e7ced5279f95e8959ca7e4a8848ad6e6721 100644 (file)
@@ -1,6 +1,7 @@
 // run-rustfix
 
 #![warn(clippy::unreadable_literal)]
+#![allow(unused_tuple_struct_fields)]
 
 struct Foo(u64);
 
index ee5466fd517fd6e00dd79b2cd4324f1df819a8c3..b51130c6a6abae11e2ba30908ab8a34ec94a9c7b 100644 (file)
@@ -1,5 +1,5 @@
 error: digits of hex or binary literal not grouped by four
-  --> $DIR/unreadable_literal.rs:25:9
+  --> $DIR/unreadable_literal.rs:26:9
    |
 LL |         0x1_234_567,
    |         ^^^^^^^^^^^ help: consider: `0x0123_4567`
@@ -7,7 +7,7 @@ LL |         0x1_234_567,
    = note: `-D clippy::unusual-byte-groupings` implied by `-D warnings`
 
 error: long literal lacking separators
-  --> $DIR/unreadable_literal.rs:33:17
+  --> $DIR/unreadable_literal.rs:34:17
    |
 LL |     let _bad = (0b110110_i64, 0x12345678_usize, 123456_f32, 1.234567_f32);
    |                 ^^^^^^^^^^^^ help: consider: `0b11_0110_i64`
@@ -15,55 +15,55 @@ LL |     let _bad = (0b110110_i64, 0x12345678_usize, 123456_f32, 1.234567_f32);
    = note: `-D clippy::unreadable-literal` implied by `-D warnings`
 
 error: long literal lacking separators
-  --> $DIR/unreadable_literal.rs:33:31
+  --> $DIR/unreadable_literal.rs:34:31
    |
 LL |     let _bad = (0b110110_i64, 0x12345678_usize, 123456_f32, 1.234567_f32);
    |                               ^^^^^^^^^^^^^^^^ help: consider: `0x1234_5678_usize`
 
 error: long literal lacking separators
-  --> $DIR/unreadable_literal.rs:33:49
+  --> $DIR/unreadable_literal.rs:34:49
    |
 LL |     let _bad = (0b110110_i64, 0x12345678_usize, 123456_f32, 1.234567_f32);
    |                                                 ^^^^^^^^^^ help: consider: `123_456_f32`
 
 error: long literal lacking separators
-  --> $DIR/unreadable_literal.rs:33:61
+  --> $DIR/unreadable_literal.rs:34:61
    |
 LL |     let _bad = (0b110110_i64, 0x12345678_usize, 123456_f32, 1.234567_f32);
    |                                                             ^^^^^^^^^^^^ help: consider: `1.234_567_f32`
 
 error: long literal lacking separators
-  --> $DIR/unreadable_literal.rs:35:20
+  --> $DIR/unreadable_literal.rs:36:20
    |
 LL |     let _bad_sci = 1.123456e1;
    |                    ^^^^^^^^^^ help: consider: `1.123_456e1`
 
 error: long literal lacking separators
-  --> $DIR/unreadable_literal.rs:37:18
+  --> $DIR/unreadable_literal.rs:38:18
    |
 LL |     let _fail1 = 0xabcdef;
    |                  ^^^^^^^^ help: consider: `0x00ab_cdef`
 
 error: long literal lacking separators
-  --> $DIR/unreadable_literal.rs:38:23
+  --> $DIR/unreadable_literal.rs:39:23
    |
 LL |     let _fail2: u32 = 0xBAFEBAFE;
    |                       ^^^^^^^^^^ help: consider: `0xBAFE_BAFE`
 
 error: long literal lacking separators
-  --> $DIR/unreadable_literal.rs:39:18
+  --> $DIR/unreadable_literal.rs:40:18
    |
 LL |     let _fail3 = 0xabcdeff;
    |                  ^^^^^^^^^ help: consider: `0x0abc_deff`
 
 error: long literal lacking separators
-  --> $DIR/unreadable_literal.rs:40:24
+  --> $DIR/unreadable_literal.rs:41:24
    |
 LL |     let _fail4: i128 = 0xabcabcabcabcabcabc;
    |                        ^^^^^^^^^^^^^^^^^^^^ help: consider: `0x00ab_cabc_abca_bcab_cabc`
 
 error: long literal lacking separators
-  --> $DIR/unreadable_literal.rs:41:18
+  --> $DIR/unreadable_literal.rs:42:18
    |
 LL |     let _fail5 = 1.100300400;
    |                  ^^^^^^^^^^^ help: consider: `1.100_300_400`
diff --git a/src/tools/clippy/tests/ui/unwrap_expect_used.rs b/src/tools/clippy/tests/ui/unwrap_expect_used.rs
new file mode 100644 (file)
index 0000000..0d4a050
--- /dev/null
@@ -0,0 +1,10 @@
+#![warn(clippy::unwrap_used, clippy::expect_used)]
+
+fn main() {
+    Some(3).unwrap();
+    Some(3).expect("Hello world!");
+
+    let a: Result<i32, i32> = Ok(3);
+    a.unwrap();
+    a.expect("Hello world!");
+}
diff --git a/src/tools/clippy/tests/ui/unwrap_expect_used.stderr b/src/tools/clippy/tests/ui/unwrap_expect_used.stderr
new file mode 100644 (file)
index 0000000..f54bfd6
--- /dev/null
@@ -0,0 +1,36 @@
+error: used `unwrap()` on `an Option` value
+  --> $DIR/unwrap_expect_used.rs:4:5
+   |
+LL |     Some(3).unwrap();
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::unwrap-used` implied by `-D warnings`
+   = help: if this value is `None`, it will panic
+
+error: used `expect()` on `an Option` value
+  --> $DIR/unwrap_expect_used.rs:5:5
+   |
+LL |     Some(3).expect("Hello world!");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::expect-used` implied by `-D warnings`
+   = help: if this value is `None`, it will panic
+
+error: used `unwrap()` on `a Result` value
+  --> $DIR/unwrap_expect_used.rs:8:5
+   |
+LL |     a.unwrap();
+   |     ^^^^^^^^^^
+   |
+   = help: if this value is an `Err`, it will panic
+
+error: used `expect()` on `a Result` value
+  --> $DIR/unwrap_expect_used.rs:9:5
+   |
+LL |     a.expect("Hello world!");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: if this value is an `Err`, it will panic
+
+error: aborting due to 4 previous errors
+
index d20977d55d29de60b79fe9202716b827c917c21b..322083511ac1808c61d2fed4df0ccc58bba97735 100644 (file)
@@ -2,7 +2,7 @@
 
 #![feature(rustc_private)]
 #![warn(clippy::all)]
-#![allow(clippy::blacklisted_name, clippy::eq_op)]
+#![allow(clippy::disallowed_names, clippy::eq_op)]
 #![warn(clippy::used_underscore_binding)]
 
 #[macro_use]
index 23e49539969a04633b24a24172cb5f99a1fb8a10..41f97e4326a901b37ff80f00c6f700205ee61700 100644 (file)
@@ -17,6 +17,7 @@ rustfix = "0.6.0"
 lazy_static = "1.0"
 walkdir = "2"
 glob = "0.3.0"
+lazycell = "1.3.0"
 
 [target.'cfg(unix)'.dependencies]
 libc = "0.2"
index be81ff881f3a897f4e827ab93ebae7711ef44c97..6f17b9e1be9a3d04556bdf7082c9d3e138e3b332 100644 (file)
@@ -3,9 +3,11 @@
 use std::ffi::OsString;
 use std::fmt;
 use std::path::{Path, PathBuf};
+use std::process::Command;
 use std::str::FromStr;
 
 use crate::util::PathBufExt;
+use lazycell::LazyCell;
 use test::ColorConfig;
 
 #[derive(Clone, Copy, PartialEq, Debug)]
@@ -371,6 +373,8 @@ pub struct Config {
 
     /// Whether to rerun tests even if the inputs are unchanged.
     pub force_rerun: bool,
+
+    pub target_cfg: LazyCell<TargetCfg>,
 }
 
 impl Config {
@@ -380,6 +384,131 @@ pub fn run_enabled(&self) -> bool {
             !self.target.ends_with("-fuchsia")
         })
     }
+
+    fn target_cfg(&self) -> &TargetCfg {
+        self.target_cfg.borrow_with(|| TargetCfg::new(&self.rustc_path, &self.target))
+    }
+
+    pub fn matches_arch(&self, arch: &str) -> bool {
+        self.target_cfg().arch == arch ||
+        // Shorthand for convenience. The arch for
+        // asmjs-unknown-emscripten is actually wasm32.
+        (arch == "asmjs" && self.target.starts_with("asmjs")) ||
+        // Matching all the thumb variants as one can be convenient.
+        // (thumbv6m, thumbv7em, thumbv7m, etc.)
+        (arch == "thumb" && self.target.starts_with("thumb"))
+    }
+
+    pub fn matches_os(&self, os: &str) -> bool {
+        self.target_cfg().os == os
+    }
+
+    pub fn matches_env(&self, env: &str) -> bool {
+        self.target_cfg().env == env
+    }
+
+    pub fn matches_abi(&self, abi: &str) -> bool {
+        self.target_cfg().abi == abi
+    }
+
+    pub fn matches_family(&self, family: &str) -> bool {
+        self.target_cfg().families.iter().any(|f| f == family)
+    }
+
+    pub fn is_big_endian(&self) -> bool {
+        self.target_cfg().endian == Endian::Big
+    }
+
+    pub fn get_pointer_width(&self) -> u32 {
+        *&self.target_cfg().pointer_width
+    }
+
+    pub fn has_asm_support(&self) -> bool {
+        static ASM_SUPPORTED_ARCHS: &[&str] = &[
+            "x86", "x86_64", "arm", "aarch64", "riscv32",
+            "riscv64",
+            // These targets require an additional asm_experimental_arch feature.
+            // "nvptx64", "hexagon", "mips", "mips64", "spirv", "wasm32",
+        ];
+        ASM_SUPPORTED_ARCHS.contains(&self.target_cfg().arch.as_str())
+    }
+}
+
+#[derive(Clone, Debug)]
+pub struct TargetCfg {
+    arch: String,
+    os: String,
+    env: String,
+    abi: String,
+    families: Vec<String>,
+    pointer_width: u32,
+    endian: Endian,
+}
+
+#[derive(Eq, PartialEq, Clone, Debug)]
+pub enum Endian {
+    Little,
+    Big,
+}
+
+impl TargetCfg {
+    fn new(rustc_path: &Path, target: &str) -> TargetCfg {
+        let output = match Command::new(rustc_path)
+            .arg("--print=cfg")
+            .arg("--target")
+            .arg(target)
+            .output()
+        {
+            Ok(output) => output,
+            Err(e) => panic!("error: failed to get cfg info from {:?}: {e}", rustc_path),
+        };
+        if !output.status.success() {
+            panic!(
+                "error: failed to get cfg info from {:?}\n--- stdout\n{}\n--- stderr\n{}",
+                rustc_path,
+                String::from_utf8(output.stdout).unwrap(),
+                String::from_utf8(output.stderr).unwrap(),
+            );
+        }
+        let print_cfg = String::from_utf8(output.stdout).unwrap();
+        let mut arch = None;
+        let mut os = None;
+        let mut env = None;
+        let mut abi = None;
+        let mut families = Vec::new();
+        let mut pointer_width = None;
+        let mut endian = None;
+        for line in print_cfg.lines() {
+            if let Some((name, value)) = line.split_once('=') {
+                let value = value.trim_matches('"');
+                match name {
+                    "target_arch" => arch = Some(value),
+                    "target_os" => os = Some(value),
+                    "target_env" => env = Some(value),
+                    "target_abi" => abi = Some(value),
+                    "target_family" => families.push(value.to_string()),
+                    "target_pointer_width" => pointer_width = Some(value.parse().unwrap()),
+                    "target_endian" => {
+                        endian = Some(match value {
+                            "little" => Endian::Little,
+                            "big" => Endian::Big,
+                            s => panic!("unexpected {s}"),
+                        })
+                    }
+                    _ => {}
+                }
+            }
+        }
+        TargetCfg {
+            arch: arch.unwrap().to_string(),
+            os: os.unwrap().to_string(),
+            env: env.unwrap().to_string(),
+            abi: abi.unwrap().to_string(),
+            families,
+            pointer_width: pointer_width.unwrap(),
+            endian: endian.unwrap(),
+        }
+    }
 }
 
 #[derive(Debug, Clone)]
index f8f193ddf83fb470e91ee4172fac36188b570288..8f097f47b451aae68113a00274340398adf109c0 100644 (file)
@@ -661,17 +661,36 @@ fn parse_cfg_name_directive(&self, line: &str, prefix: &str) -> ParsedNameDirect
 
         let name = line[prefix.len() + 1..].split(&[':', ' '][..]).next().unwrap();
 
+        let matches_pointer_width = || {
+            name.strip_suffix("bit")
+                .and_then(|width| width.parse::<u32>().ok())
+                .map(|width| self.get_pointer_width() == width)
+                .unwrap_or(false)
+        };
+
+        // If something is ignored for emscripten, it likely also needs to be
+        // ignored for wasm32-unknown-unknown.
+        // `wasm32-bare` is an alias to refer to just wasm32-unknown-unknown
+        // (in contrast to `wasm32` which also matches non-bare targets like
+        // asmjs-unknown-emscripten).
+        let matches_wasm32_alias = || {
+            self.target == "wasm32-unknown-unknown" && matches!(name, "emscripten" | "wasm32-bare")
+        };
+
         let is_match = name == "test" ||
             self.target == name ||                              // triple
-            util::matches_os(&self.target, name) ||             // target
-            util::matches_env(&self.target, name) ||            // env
+            self.matches_os(name) ||
+            self.matches_env(name) ||
+            self.matches_abi(name) ||
+            self.matches_family(name) ||
             self.target.ends_with(name) ||                      // target and env
-            name == util::get_arch(&self.target) ||             // architecture
-            name == util::get_pointer_width(&self.target) ||    // pointer width
+            self.matches_arch(name) ||
+            matches_wasm32_alias() ||
+            matches_pointer_width() ||
             name == self.stage_id.split('-').next().unwrap() || // stage
             name == self.channel ||                             // channel
             (self.target != self.host && name == "cross-compile") ||
-            (name == "endian-big" && util::is_big_endian(&self.target)) ||
+            (name == "endian-big" && self.is_big_endian()) ||
             (self.remote_test_client.is_some() && name == "remote") ||
             match self.compare_mode {
                 Some(CompareMode::Polonius) => name == "compare-mode-polonius",
@@ -869,7 +888,7 @@ pub fn make_test_description<R: Read>(
 
     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_asm_support = util::has_asm_support(&config.target);
+    let has_asm_support = config.has_asm_support();
     let has_asan = util::ASAN_SUPPORTED_TARGETS.contains(&&*config.target);
     let has_cfi = util::CFI_SUPPORTED_TARGETS.contains(&&*config.target);
     let has_lsan = util::LSAN_SUPPORTED_TARGETS.contains(&&*config.target);
index a8fd4880f078250191547ae4c743c12e35f6630f..bcd222b5a93220f8dd010b11cd829fbdb179be83 100644 (file)
@@ -42,7 +42,6 @@ fn config() -> Config {
         "--suite=ui",
         "--compile-lib-path=",
         "--run-lib-path=",
-        "--rustc-path=",
         "--python=",
         "--jsondocck-path=",
         "--src-base=",
@@ -57,7 +56,24 @@ fn config() -> Config {
         "--target=x86_64-unknown-linux-gnu",
         "--channel=nightly",
     ];
-    let args = args.iter().map(ToString::to_string).collect();
+    let mut args: Vec<String> = args.iter().map(ToString::to_string).collect();
+    args.push("--rustc-path".to_string());
+    // This is a subtle/fragile thing. On rust-lang CI, there is no global
+    // `rustc`, and Cargo doesn't offer a convenient way to get the path to
+    // `rustc`. Fortunately bootstrap sets `RUSTC` for us, which is pointing
+    // to the stage0 compiler.
+    //
+    // Otherwise, if you are running compiletests's tests manually, you
+    // probably don't have `RUSTC` set, in which case this falls back to the
+    // global rustc. If your global rustc is too far out of sync with stage0,
+    // then this may cause confusing errors. Or if for some reason you don't
+    // have rustc in PATH, that would also fail.
+    args.push(std::env::var("RUSTC").unwrap_or_else(|_| {
+        eprintln!(
+            "warning: RUSTC not set, using global rustc (are you not running via bootstrap?)"
+        );
+        "rustc".to_string()
+    }));
     crate::parse_config(args)
 }
 
@@ -237,13 +253,20 @@ fn sanitizers() {
 
 #[test]
 fn asm_support() {
-    let mut config = config();
-
-    config.target = "avr-unknown-gnu-atmega328".to_owned();
-    assert!(check_ignore(&config, "// needs-asm-support"));
-
-    config.target = "i686-unknown-netbsd".to_owned();
-    assert!(!check_ignore(&config, "// needs-asm-support"));
+    let asms = [
+        ("avr-unknown-gnu-atmega328", false),
+        ("i686-unknown-netbsd", true),
+        ("riscv32gc-unknown-linux-gnu", true),
+        ("riscv64imac-unknown-none-elf", true),
+        ("x86_64-unknown-linux-gnu", true),
+        ("i686-unknown-netbsd", true),
+    ];
+    for (target, has_asm) in asms {
+        let mut config = config();
+        config.target = target.to_string();
+        assert_eq!(config.has_asm_support(), has_asm);
+        assert_eq!(check_ignore(&config, "// needs-asm-support"), !has_asm)
+    }
 }
 
 #[test]
@@ -281,3 +304,155 @@ fn test_duplicate_revisions() {
     let config = config();
     parse_rs(&config, "// revisions: rpass1 rpass1");
 }
+
+#[test]
+fn ignore_arch() {
+    let archs = [
+        ("x86_64-unknown-linux-gnu", "x86_64"),
+        ("i686-unknown-linux-gnu", "x86"),
+        ("nvptx64-nvidia-cuda", "nvptx64"),
+        ("asmjs-unknown-emscripten", "wasm32"),
+        ("asmjs-unknown-emscripten", "asmjs"),
+        ("thumbv7m-none-eabi", "thumb"),
+    ];
+    for (target, arch) in archs {
+        let mut config = config();
+        config.target = target.to_string();
+        assert!(config.matches_arch(arch), "{target} {arch}");
+        assert!(check_ignore(&config, &format!("// ignore-{arch}")));
+    }
+}
+
+#[test]
+fn matches_os() {
+    let oss = [
+        ("x86_64-unknown-linux-gnu", "linux"),
+        ("x86_64-fortanix-unknown-sgx", "unknown"),
+        ("wasm32-unknown-unknown", "unknown"),
+        ("x86_64-unknown-none", "none"),
+    ];
+    for (target, os) in oss {
+        let mut config = config();
+        config.target = target.to_string();
+        assert!(config.matches_os(os), "{target} {os}");
+        assert!(check_ignore(&config, &format!("// ignore-{os}")));
+    }
+}
+
+#[test]
+fn matches_env() {
+    let envs = [
+        ("x86_64-unknown-linux-gnu", "gnu"),
+        ("x86_64-fortanix-unknown-sgx", "sgx"),
+        ("arm-unknown-linux-musleabi", "musl"),
+    ];
+    for (target, env) in envs {
+        let mut config = config();
+        config.target = target.to_string();
+        assert!(config.matches_env(env), "{target} {env}");
+        assert!(check_ignore(&config, &format!("// ignore-{env}")));
+    }
+}
+
+#[test]
+fn matches_abi() {
+    let abis = [
+        ("aarch64-apple-ios-macabi", "macabi"),
+        ("x86_64-unknown-linux-gnux32", "x32"),
+        ("arm-unknown-linux-gnueabi", "eabi"),
+    ];
+    for (target, abi) in abis {
+        let mut config = config();
+        config.target = target.to_string();
+        assert!(config.matches_abi(abi), "{target} {abi}");
+        assert!(check_ignore(&config, &format!("// ignore-{abi}")));
+    }
+}
+
+#[test]
+fn is_big_endian() {
+    let endians = [
+        ("x86_64-unknown-linux-gnu", false),
+        ("bpfeb-unknown-none", true),
+        ("m68k-unknown-linux-gnu", true),
+        ("aarch64_be-unknown-linux-gnu", true),
+        ("powerpc64-unknown-linux-gnu", true),
+    ];
+    for (target, is_big) in endians {
+        let mut config = config();
+        config.target = target.to_string();
+        assert_eq!(config.is_big_endian(), is_big, "{target} {is_big}");
+        assert_eq!(check_ignore(&config, "// ignore-endian-big"), is_big);
+    }
+}
+
+#[test]
+fn pointer_width() {
+    let widths = [
+        ("x86_64-unknown-linux-gnu", 64),
+        ("i686-unknown-linux-gnu", 32),
+        ("arm64_32-apple-watchos", 32),
+        ("msp430-none-elf", 16),
+    ];
+    for (target, width) in widths {
+        let mut config = config();
+        config.target = target.to_string();
+        assert_eq!(config.get_pointer_width(), width, "{target} {width}");
+        assert_eq!(check_ignore(&config, "// ignore-16bit"), width == 16);
+        assert_eq!(check_ignore(&config, "// ignore-32bit"), width == 32);
+        assert_eq!(check_ignore(&config, "// ignore-64bit"), width == 64);
+    }
+}
+
+#[test]
+fn wasm_special() {
+    let ignores = [
+        ("wasm32-unknown-unknown", "emscripten", true),
+        ("wasm32-unknown-unknown", "wasm32", true),
+        ("wasm32-unknown-unknown", "wasm32-bare", true),
+        ("wasm32-unknown-unknown", "wasm64", false),
+        ("asmjs-unknown-emscripten", "emscripten", true),
+        ("asmjs-unknown-emscripten", "wasm32", true),
+        ("asmjs-unknown-emscripten", "wasm32-bare", false),
+        ("wasm32-unknown-emscripten", "emscripten", true),
+        ("wasm32-unknown-emscripten", "wasm32", true),
+        ("wasm32-unknown-emscripten", "wasm32-bare", false),
+        ("wasm32-wasi", "emscripten", false),
+        ("wasm32-wasi", "wasm32", true),
+        ("wasm32-wasi", "wasm32-bare", false),
+        ("wasm32-wasi", "wasi", true),
+        ("wasm64-unknown-unknown", "emscripten", false),
+        ("wasm64-unknown-unknown", "wasm32", false),
+        ("wasm64-unknown-unknown", "wasm32-bare", false),
+        ("wasm64-unknown-unknown", "wasm64", true),
+    ];
+    for (target, pattern, ignore) in ignores {
+        let mut config = config();
+        config.target = target.to_string();
+        assert_eq!(
+            check_ignore(&config, &format!("// ignore-{pattern}")),
+            ignore,
+            "{target} {pattern}"
+        );
+    }
+}
+
+#[test]
+fn families() {
+    let families = [
+        ("x86_64-unknown-linux-gnu", "unix"),
+        ("x86_64-pc-windows-gnu", "windows"),
+        ("wasm32-unknown-unknown", "wasm"),
+        ("wasm32-unknown-emscripten", "wasm"),
+        ("wasm32-unknown-emscripten", "unix"),
+    ];
+    for (target, family) in families {
+        let mut config = config();
+        config.target = target.to_string();
+        assert!(config.matches_family(family));
+        let other = if family == "windows" { "unix" } else { "windows" };
+        assert!(!config.matches_family(other));
+        assert!(check_ignore(&config, &format!("// ignore-{family}")));
+        assert!(!check_ignore(&config, &format!("// ignore-{other}")));
+    }
+}
index a8a151ca114d2aa82960e2458312d5cccf843468..ac6d80bb439b3b99e5931639ca9f9e110eaca689 100644 (file)
@@ -11,6 +11,7 @@
 use crate::common::{CompareMode, Config, Debugger, Mode, PassMode, TestPaths};
 use crate::util::logv;
 use getopts::Options;
+use lazycell::LazyCell;
 use std::env;
 use std::ffi::OsString;
 use std::fs;
@@ -299,6 +300,8 @@ fn make_absolute(path: PathBuf) -> PathBuf {
         npm: matches.opt_str("npm"),
 
         force_rerun: matches.opt_present("force-rerun"),
+
+        target_cfg: LazyCell::new(),
     }
 }
 
@@ -441,7 +444,7 @@ fn configure_cdb(config: &Config) -> Option<Config> {
 fn configure_gdb(config: &Config) -> Option<Config> {
     config.gdb_version?;
 
-    if util::matches_env(&config.target, "msvc") {
+    if config.matches_env("msvc") {
         return None;
     }
 
index d3e5a2dd644af31eb6f18036a9e01a46af0d1573..47f2a2d34821c737a6a2daab7baecc9241e09e96 100644 (file)
@@ -13,7 +13,6 @@
 use crate::header::TestProps;
 use crate::json;
 use crate::read2::read2_abbreviated;
-use crate::util::get_pointer_width;
 use crate::util::{logv, PathBufExt};
 use crate::ColorConfig;
 use regex::{Captures, Regex};
@@ -3127,7 +3126,7 @@ fn load_compare_outputs(
         output_kind: TestOutput,
         explicit_format: bool,
     ) -> usize {
-        let stderr_bits = format!("{}.stderr", get_pointer_width(&self.config.target));
+        let stderr_bits = format!("{}bit.stderr", self.config.get_pointer_width());
         let (stderr_kind, stdout_kind) = match output_kind {
             TestOutput::Compile => (
                 {
@@ -3402,7 +3401,7 @@ fn check_mir_dump(&self) {
 
         let mut bit_width = String::new();
         if test_file_contents.lines().any(|l| l == "// EMIT_MIR_FOR_EACH_BIT_WIDTH") {
-            bit_width = format!(".{}", get_pointer_width(&self.config.target));
+            bit_width = format!(".{}bit", self.config.get_pointer_width());
         }
 
         if self.config.bless {
index 22df18ee9fbb8aca934c1e656e9e18f4e4c52326..9d047b63c859397d8ffb7d9b4ed317b1c697045f 100644 (file)
@@ -8,84 +8,6 @@
 #[cfg(test)]
 mod tests;
 
-/// Conversion table from triple OS name to Rust SYSNAME
-const OS_TABLE: &[(&str, &str)] = &[
-    ("android", "android"),
-    ("androideabi", "android"),
-    ("cuda", "cuda"),
-    ("darwin", "macos"),
-    ("dragonfly", "dragonfly"),
-    ("emscripten", "emscripten"),
-    ("freebsd", "freebsd"),
-    ("fuchsia", "fuchsia"),
-    ("haiku", "haiku"),
-    ("hermit", "hermit"),
-    ("illumos", "illumos"),
-    ("ios", "ios"),
-    ("l4re", "l4re"),
-    ("linux", "linux"),
-    ("mingw32", "windows"),
-    ("none", "none"),
-    ("netbsd", "netbsd"),
-    ("openbsd", "openbsd"),
-    ("redox", "redox"),
-    ("sgx", "sgx"),
-    ("solaris", "solaris"),
-    ("watchos", "watchos"),
-    ("win32", "windows"),
-    ("windows", "windows"),
-    ("vxworks", "vxworks"),
-];
-
-const ARCH_TABLE: &[(&str, &str)] = &[
-    ("aarch64", "aarch64"),
-    ("aarch64_be", "aarch64"),
-    ("amd64", "x86_64"),
-    ("arm", "arm"),
-    ("arm64", "aarch64"),
-    ("armv4t", "arm"),
-    ("armv5te", "arm"),
-    ("armv7", "arm"),
-    ("armv7s", "arm"),
-    ("asmjs", "asmjs"),
-    ("avr", "avr"),
-    ("bpfeb", "bpf"),
-    ("bpfel", "bpf"),
-    ("hexagon", "hexagon"),
-    ("i386", "x86"),
-    ("i586", "x86"),
-    ("i686", "x86"),
-    ("m68k", "m68k"),
-    ("mips", "mips"),
-    ("mips64", "mips64"),
-    ("mips64el", "mips64"),
-    ("mipsisa32r6", "mips"),
-    ("mipsisa32r6el", "mips"),
-    ("mipsisa64r6", "mips64"),
-    ("mipsisa64r6el", "mips64"),
-    ("mipsel", "mips"),
-    ("mipsisa32r6", "mips"),
-    ("mipsisa32r6el", "mips"),
-    ("mipsisa64r6", "mips64"),
-    ("mipsisa64r6el", "mips64"),
-    ("msp430", "msp430"),
-    ("nvptx64", "nvptx64"),
-    ("powerpc", "powerpc"),
-    ("powerpc64", "powerpc64"),
-    ("powerpc64le", "powerpc64"),
-    ("riscv64gc", "riscv64"),
-    ("s390x", "s390x"),
-    ("sparc", "sparc"),
-    ("sparc64", "sparc64"),
-    ("sparcv9", "sparc64"),
-    ("thumbv6m", "thumb"),
-    ("thumbv7em", "thumb"),
-    ("thumbv7m", "thumb"),
-    ("wasm32", "wasm32"),
-    ("x86_64", "x86_64"),
-    ("xcore", "xcore"),
-];
-
 pub const ASAN_SUPPORTED_TARGETS: &[&str] = &[
     "aarch64-apple-darwin",
     "aarch64-fuchsia",
 
 pub const SHADOWCALLSTACK_SUPPORTED_TARGETS: &[&str] = &["aarch64-linux-android"];
 
-const BIG_ENDIAN: &[&str] = &[
-    "aarch64_be",
-    "armebv7r",
-    "mips",
-    "mips64",
-    "mipsisa32r6",
-    "mipsisa64r6",
-    "powerpc",
-    "powerpc64",
-    "s390x",
-    "sparc",
-    "sparc64",
-    "sparcv9",
-];
-
-static ASM_SUPPORTED_ARCHS: &[&str] = &[
-    "x86", "x86_64", "arm", "aarch64", "riscv32",
-    "riscv64",
-    // These targets require an additional asm_experimental_arch feature.
-    // "nvptx64", "hexagon", "mips", "mips64", "spirv", "wasm32",
-];
-
-pub fn has_asm_support(triple: &str) -> bool {
-    ASM_SUPPORTED_ARCHS.contains(&get_arch(triple))
-}
-
-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
-    if triple == "wasm32-unknown-unknown" {
-        return name == "emscripten" || name == "wasm32-bare";
-    }
-    let triple: Vec<_> = triple.split('-').collect();
-    for &(triple_os, os) in OS_TABLE {
-        if triple.contains(&triple_os) {
-            return os == name;
-        }
-    }
-    panic!("Cannot determine OS from triple");
-}
-
-/// Determine the architecture from `triple`
-pub fn get_arch(triple: &str) -> &'static str {
-    let triple: Vec<_> = triple.split('-').collect();
-    for &(triple_arch, arch) in ARCH_TABLE {
-        if triple.contains(&triple_arch) {
-            return arch;
-        }
-    }
-    panic!("Cannot determine Architecture from triple");
-}
-
-/// Determine the endianness from `triple`
-pub fn is_big_endian(triple: &str) -> bool {
-    let triple_arch = triple.split('-').next().unwrap();
-    BIG_ENDIAN.contains(&triple_arch)
-}
-
-pub fn matches_env(triple: &str, name: &str) -> bool {
-    if let Some(env) = triple.split('-').nth(3) { env.starts_with(name) } else { false }
-}
-
-pub fn get_pointer_width(triple: &str) -> &'static str {
-    if (triple.contains("64") && !triple.ends_with("gnux32") && !triple.ends_with("gnu_ilp32"))
-        || triple.starts_with("s390x")
-    {
-        "64bit"
-    } else if triple.starts_with("avr") {
-        "16bit"
-    } else {
-        "32bit"
-    }
-}
-
 pub fn make_new_path(path: &str) -> String {
     assert!(cfg!(windows));
     // Windows just uses PATH as the library search path, so we have to
index 663027173ff9d442857f96f92c5189ab03eb299c..b09a183b14e6a263ca93ca6ae389279c0ef5602e 100644 (file)
@@ -1,42 +1,5 @@
 use super::*;
 
-#[test]
-#[should_panic(expected = "Cannot determine Architecture from triple")]
-fn test_get_arch_failure() {
-    get_arch("abc");
-}
-
-#[test]
-fn test_get_arch() {
-    assert_eq!("x86_64", get_arch("x86_64-unknown-linux-gnu"));
-    assert_eq!("x86_64", get_arch("amd64"));
-    assert_eq!("nvptx64", get_arch("nvptx64-nvidia-cuda"));
-}
-
-#[test]
-#[should_panic(expected = "Cannot determine OS from triple")]
-fn test_matches_os_failure() {
-    matches_os("abc", "abc");
-}
-
-#[test]
-fn test_matches_os() {
-    assert!(matches_os("x86_64-unknown-linux-gnu", "linux"));
-    assert!(matches_os("wasm32-unknown-unknown", "emscripten"));
-    assert!(matches_os("wasm32-unknown-unknown", "wasm32-bare"));
-    assert!(!matches_os("wasm32-unknown-unknown", "windows"));
-    assert!(matches_os("thumbv6m0-none-eabi", "none"));
-    assert!(matches_os("riscv32imc-unknown-none-elf", "none"));
-    assert!(matches_os("nvptx64-nvidia-cuda", "cuda"));
-    assert!(matches_os("x86_64-fortanix-unknown-sgx", "sgx"));
-}
-
-#[test]
-fn is_big_endian_test() {
-    assert!(!is_big_endian("no"));
-    assert!(is_big_endian("sparc-unknown-unknown"));
-}
-
 #[test]
 fn path_buf_with_extra_extension_test() {
     assert_eq!(
index 34d3954db28dc6b5b1836889db6a35cc30c1fd16..72d61d9bd2638048050344c787a97d84d11c6a63 100644 (file)
@@ -9,3 +9,4 @@ path = "main.rs"
 
 [dependencies]
 walkdir = "2"
+rayon = "1.5"
index f52fbdfe2d7dc5949b5195985598a0c3bc335747..9b4d2c52598068892f8277f1b7bff44a6b23a6f4 100644 (file)
@@ -1,3 +1,4 @@
+use rayon::iter::{ParallelBridge, ParallelIterator};
 use std::env;
 use std::path::Path;
 use std::process::{Command, Output};
@@ -56,27 +57,30 @@ fn check_html_file(file: &Path) -> usize {
 
 // Returns the number of files read and the number of errors.
 fn find_all_html_files(dir: &Path) -> (usize, usize) {
-    let mut files_read = 0;
-    let mut errors = 0;
-
-    for entry in walkdir::WalkDir::new(dir).into_iter().filter_entry(|e| {
-        e.depth() != 1
-            || e.file_name()
-                .to_str()
-                .map(|s| DOCS_TO_CHECK.into_iter().any(|d| *d == s))
-                .unwrap_or(false)
-    }) {
-        let entry = entry.expect("failed to read file");
-        if !entry.file_type().is_file() {
-            continue;
-        }
-        let entry = entry.path();
-        if entry.extension().and_then(|s| s.to_str()) == Some("html") {
-            errors += check_html_file(&entry);
-            files_read += 1;
-        }
-    }
-    (files_read, errors)
+    walkdir::WalkDir::new(dir)
+        .into_iter()
+        .filter_entry(|e| {
+            e.depth() != 1
+                || e.file_name()
+                    .to_str()
+                    .map(|s| DOCS_TO_CHECK.into_iter().any(|d| *d == s))
+                    .unwrap_or(false)
+        })
+        .par_bridge()
+        .map(|entry| {
+            let entry = entry.expect("failed to read file");
+            if !entry.file_type().is_file() {
+                return (0, 0);
+            }
+            let entry = entry.path();
+            // (Number of files processed, number of errors)
+            if entry.extension().and_then(|s| s.to_str()) == Some("html") {
+                (1, check_html_file(&entry))
+            } else {
+                (0, 0)
+            }
+        })
+        .reduce(|| (0, 0), |a, b| (a.0 + b.0, a.1 + b.1))
 }
 
 /// Default `tidy` command for macOS is too old that it does not have `mute-id` and `mute` options.
index b938529fb8ed8f7b5b374282ffc3ffa74c313111..39ee5747153bf13324870c4a912acbf1f9bfde3f 160000 (submodule)
@@ -1 +1 @@
-Subproject commit b938529fb8ed8f7b5b374282ffc3ffa74c313111
+Subproject commit 39ee5747153bf13324870c4a912acbf1f9bfde3f
index fcf1f94c9ab2acc18cfd4368a4aeb38e77da9649..4d8b0a19986a4daab37287a5b5fe2da0775d1873 160000 (submodule)
@@ -1 +1 @@
-Subproject commit fcf1f94c9ab2acc18cfd4368a4aeb38e77da9649
+Subproject commit 4d8b0a19986a4daab37287a5b5fe2da0775d1873
index 7ba06356a37ceaed48e84b0e7a40d749ecf9c8e3..a038dce3248aa41fb5ede1be651a3cf7fce1c078 100644 (file)
@@ -19,7 +19,7 @@ Before submitting, please make sure that you're not running into one of these kn
 Otherwise please try to provide information which will help us to fix the issue faster. Minimal reproducible examples with few dependencies are especially lovely <3.
 -->
 
-**rust-analyzer version**: (eg. output of "Rust Analyzer: Show RA Version" command)
+**rust-analyzer version**: (eg. output of "rust-analyzer: Show RA Version" command, accessible in VSCode via <kbd>Ctrl/⌘</kbd>+<kbd>Shift</kbd>+<kbd>P</kbd>)
 
 **rustc version**: (eg. output of `rustc -V`)
 
index 927996c1bef21d7f8a5c631a13577c3ee6fcaeb7..a4497f49e3c2f8c5193aea300b044251ec262463 100644 (file)
@@ -34,8 +34,21 @@ jobs:
           git config --global user.email "runner@gha.local"
           git config --global user.name "Github Action"
           rm Cargo.lock
+          # Fix names for crates that were published before switch to kebab-case.
+          cargo workspaces rename --from base-db base_db
+          cargo workspaces rename --from hir-def hir_def
+          cargo workspaces rename --from hir-expand hir_expand
+          cargo workspaces rename --from hir-ty hir_ty
+          cargo workspaces rename --from ide-assists ide_assists
+          cargo workspaces rename --from ide-completion ide_completion
+          cargo workspaces rename --from ide-db ide_db
+          cargo workspaces rename --from ide-diagnostics ide_diagnostics
+          cargo workspaces rename --from ide-ssr ide_ssr
+          cargo workspaces rename --from proc-macro-api proc_macro_api
+          cargo workspaces rename --from proc-macro-srv proc_macro_srv
+          cargo workspaces rename --from project-model project_model
+          cargo workspaces rename --from test-utils test_utils
+          cargo workspaces rename --from text-edit text_edit
           cargo workspaces rename ra_ap_%n
           find crates/rust-analyzer -type f -name '*.rs' -exec sed -i 's/rust_analyzer/ra_ap_rust_analyzer/g' {} +
-          # Fix names for crates that were published before switch to kebab-case.
-          find crates -name 'Cargo.toml' -exec sed -i "s/ra_ap_base-db/ra_ap_base_db/g; s/ra_ap_hir-def/ra_ap_hir_def/g; s/ra_ap_hir-expand/ra_ap_hir_expand/g; s/ra_ap_hir-ty/ra_ap_hir_ty/g; s/ra_ap_ide-assists/ra_ap_ide_assists/g; s/ra_ap_ide-completion/ra_ap_ide_completion/g; s/ra_ap_ide-db/ra_ap_ide_db/g; s/ra_ap_ide-diagnostics/ra_ap_ide_diagnostics/g; s/ra_ap_ide-ssr/ra_ap_ide_ssr/g; s/ra_ap_proc-macro-api/ra_ap_proc_macro_api/g; s/ra_ap_proc-macro-srv/ra_ap_proc_macro_srv/g; s/ra_ap_project-model/ra_ap_project_model/g; s/ra_ap_test-utils/ra_ap_test_utils/g; s/ra_ap_text-edit/ra_ap_text_edit/g" {} +
           cargo workspaces publish --yes --force '*' --exact --no-git-commit --allow-dirty --skip-published custom 0.0.$PATCH
index 4e62f2cde279905ec463421f2b1127a29c8c2d7c..ca8eb1309de3dce3d92aa96a3e03a14ded9c781a 100644 (file)
@@ -18,6 +18,7 @@ env:
   FETCH_DEPTH: 0 # pull in the tags for the version string
   MACOSX_DEPLOYMENT_TARGET: 10.15
   CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
+  CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER: arm-linux-gnueabihf-gcc
 
 jobs:
   dist:
@@ -36,6 +37,9 @@ jobs:
           - os: ubuntu-18.04
             target: aarch64-unknown-linux-gnu
             code-target: linux-arm64
+          - os: ubuntu-18.04
+            target: arm-unknown-linux-gnueabihf
+            code-target: linux-armhf
           - os: macos-11
             target: x86_64-apple-darwin
             code-target: darwin-x64
@@ -67,13 +71,17 @@ jobs:
           node-version: 14.x
 
       - name: Update apt repositories
-        if: matrix.target == 'aarch64-unknown-linux-gnu'
+        if: matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'arm-unknown-linux-gnueabihf'
         run: sudo apt-get update
 
-      - name: Install target toolchain
+      - name: Install AArch64 target toolchain
         if: matrix.target == 'aarch64-unknown-linux-gnu'
         run: sudo apt-get install gcc-aarch64-linux-gnu
 
+      - name: Install ARM target toolchain
+        if: matrix.target == 'arm-unknown-linux-gnueabihf'
+        run: sudo apt-get install gcc-arm-linux-gnueabihf
+
       - name: Dist
         run: cargo xtask dist --client-patch-version ${{ github.run_number }}
 
@@ -204,6 +212,10 @@ jobs:
         with:
           name: dist-aarch64-unknown-linux-gnu
           path: dist
+      - uses: actions/download-artifact@v1
+        with:
+          name: dist-arm-unknown-linux-gnueabihf
+          path: dist
       - uses: actions/download-artifact@v1
         with:
           name: dist-x86_64-pc-windows-msvc
index 8bb0517ed5abbe1518ea4b510d586da047c07b54..8c3f6f8468bf6f64a1872b1c637fd774c844cbdc 100644 (file)
@@ -43,7 +43,7 @@ https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frust-analyzer
 
 ## License
 
-Rust analyzer is primarily distributed under the terms of both the MIT
+rust-analyzer is primarily distributed under the terms of both the MIT
 license and the Apache License (Version 2.0).
 
 See LICENSE-APACHE and LICENSE-MIT for details.
index 4e8bc881ae7383f8caf04e0627ff244979becd92..3347940ec6d639015304407bdd708dcff184c2bb 100644 (file)
@@ -57,6 +57,7 @@ pub struct FlycheckHandle {
     // XXX: drop order is significant
     sender: Sender<Restart>,
     _thread: jod_thread::JoinHandle,
+    id: usize,
 }
 
 impl FlycheckHandle {
@@ -72,18 +73,22 @@ pub fn spawn(
             .name("Flycheck".to_owned())
             .spawn(move || actor.run(receiver))
             .expect("failed to spawn thread");
-        FlycheckHandle { sender, _thread: thread }
+        FlycheckHandle { id, sender, _thread: thread }
     }
 
     /// Schedule a re-start of the cargo check worker.
     pub fn update(&self) {
         self.sender.send(Restart).unwrap();
     }
+
+    pub fn id(&self) -> usize {
+        self.id
+    }
 }
 
 pub enum Message {
     /// Request adding a diagnostic with fixes included to a file
-    AddDiagnostic { workspace_root: AbsPathBuf, diagnostic: Diagnostic },
+    AddDiagnostic { id: usize, workspace_root: AbsPathBuf, diagnostic: Diagnostic },
 
     /// Request check progress notification to client
     Progress {
@@ -96,8 +101,9 @@ pub enum Message {
 impl fmt::Debug for Message {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
-            Message::AddDiagnostic { workspace_root, diagnostic } => f
+            Message::AddDiagnostic { id, workspace_root, diagnostic } => f
                 .debug_struct("AddDiagnostic")
+                .field("id", id)
                 .field("workspace_root", workspace_root)
                 .field("diagnostic_code", &diagnostic.code.as_ref().map(|it| &it.code))
                 .finish(),
@@ -183,7 +189,7 @@ fn run(mut self, inbox: Receiver<Restart>) {
                     }
                 }
                 Event::CheckEvent(None) => {
-                    tracing::debug!("flycheck finished");
+                    tracing::debug!(flycheck_id = self.id, "flycheck finished");
 
                     // Watcher finished
                     let cargo_handle = self.cargo_handle.take().unwrap();
@@ -203,6 +209,7 @@ fn run(mut self, inbox: Receiver<Restart>) {
 
                     CargoMessage::Diagnostic(msg) => {
                         self.send(Message::AddDiagnostic {
+                            id: self.id,
                             workspace_root: self.workspace_root.clone(),
                             diagnostic: msg,
                         });
index 8a6b6f3effd2ed33e6f121a79f8bf816688b8125..2b39c6f8da86bee737371f8fd86547d5ed281d11 100644 (file)
@@ -124,13 +124,24 @@ fn from_attrs_owner(db: &dyn DefDatabase, owner: InFile<&dyn ast::HasAttrs>) ->
 
     pub(crate) fn merge(&self, other: Self) -> Self {
         // FIXME: This needs to fixup `AttrId`s
-        match (&self.entries, &other.entries) {
+        match (&self.entries, other.entries) {
             (None, None) => Self::EMPTY,
-            (Some(entries), None) | (None, Some(entries)) => {
-                Self { entries: Some(entries.clone()) }
-            }
+            (None, entries @ Some(_)) => Self { entries },
+            (Some(entries), None) => Self { entries: Some(entries.clone()) },
             (Some(a), Some(b)) => {
-                Self { entries: Some(a.iter().chain(b.iter()).cloned().collect()) }
+                let last_ast_index = a.last().map_or(0, |it| it.id.ast_index + 1);
+                Self {
+                    entries: Some(
+                        a.iter()
+                            .cloned()
+                            .chain(b.iter().map(|it| {
+                                let mut it = it.clone();
+                                it.id.ast_index += last_ast_index;
+                                it
+                            }))
+                            .collect(),
+                    ),
+                }
             }
         }
     }
index 2397cf5015848038b2b2401d8b600b89534aaeaa..469b28c2d9ede6a8edc9904792215579df6285af 100644 (file)
@@ -451,7 +451,7 @@ fn child_source(
         if let GenericDefId::TraitId(id) = *self {
             let trait_ref = id.lookup(db).source(db).value;
             let idx = idx_iter.next().unwrap();
-            params.insert(idx, Either::Right(trait_ref))
+            params.insert(idx, Either::Right(trait_ref));
         }
 
         if let Some(generic_params_list) = generic_params_list {
index 579f803ea193ac94b3f4f998955e9cbf5a44ccc2..a11a92204c15c29c788a4d134e71e681595e466c 100644 (file)
@@ -5,6 +5,7 @@
 
 use base_db::CrateId;
 use hir_expand::{name::Name, AstId, MacroCallId};
+use itertools::Itertools;
 use once_cell::sync::Lazy;
 use profile::Count;
 use rustc_hash::{FxHashMap, FxHashSet};
@@ -97,15 +98,14 @@ pub(crate) enum BuiltinShadowMode {
 impl ItemScope {
     pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a {
         // FIXME: shadowing
-        let keys: FxHashSet<_> = self
-            .types
+        self.types
             .keys()
             .chain(self.values.keys())
             .chain(self.macros.keys())
             .chain(self.unresolved.iter())
-            .collect();
-
-        keys.into_iter().map(move |name| (name, self.get(name)))
+            .sorted()
+            .unique()
+            .map(move |name| (name, self.get(name)))
     }
 
     pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ {
index 375587ee935bf65425fad8254ad12c60703c18a4..3342d4db4aa64812d88c5c40e1cbd4a53a644165 100644 (file)
@@ -14,7 +14,7 @@
 //! unaffected, so we don't have to recompute name resolution results or item data (see `data.rs`).
 //!
 //! The `ItemTree` for the currently open file can be displayed by using the VS Code command
-//! "Rust Analyzer: Debug ItemTree".
+//! "rust-analyzer: Debug ItemTree".
 //!
 //! Compared to rustc's architecture, `ItemTree` has properties from both rustc's AST and HIR: many
 //! syntax-level Rust features are already desugared to simpler forms in the `ItemTree`, but name
index f394c541719f323a42f20bc7765b6a300de8b900..8a6bb929c3df7bd660e2fcd5995b8e38b61bcfc0 100644 (file)
@@ -1055,7 +1055,7 @@ fn resolve_macros(&mut self) -> ReachedFixedPoint {
         };
         let mut res = ReachedFixedPoint::Yes;
         macros.retain(|directive| {
-            let resolver2 = |path| {
+            let resolver = |path| {
                 let resolved_res = self.def_map.resolve_path_fp_with_macro(
                     self.db,
                     ResolveMode::Other,
@@ -1068,7 +1068,7 @@ fn resolve_macros(&mut self) -> ReachedFixedPoint {
                     .take_macros()
                     .map(|it| (it, macro_id_to_def_id(self.db, it)))
             };
-            let resolver = |path| resolver2(path).map(|(_, it)| it);
+            let resolver_def_id = |path| resolver(path).map(|(_, it)| it);
 
             match &directive.kind {
                 MacroDirectiveKind::FnLike { ast_id, expand_to } => {
@@ -1077,7 +1077,7 @@ fn resolve_macros(&mut self) -> ReachedFixedPoint {
                         ast_id,
                         *expand_to,
                         self.def_map.krate,
-                        &resolver,
+                        &resolver_def_id,
                         &mut |_err| (),
                     );
                     if let Ok(Ok(call_id)) = call_id {
@@ -1093,7 +1093,7 @@ fn resolve_macros(&mut self) -> ReachedFixedPoint {
                         *derive_attr,
                         *derive_pos as u32,
                         self.def_map.krate,
-                        &resolver2,
+                        &resolver,
                     );
 
                     if let Ok((macro_id, def_id, call_id)) = id {
@@ -1158,7 +1158,7 @@ fn resolve_macros(&mut self) -> ReachedFixedPoint {
                         }
                     }
 
-                    let def = match resolver(path.clone()) {
+                    let def = match resolver_def_id(path.clone()) {
                         Some(def) if def.is_attribute() => def,
                         _ => return true,
                     };
@@ -1292,7 +1292,8 @@ fn resolve_macros(&mut self) -> ReachedFixedPoint {
             true
         });
         // Attribute resolution can add unresolved macro invocations, so concatenate the lists.
-        self.unresolved_macros.extend(macros);
+        macros.extend(mem::take(&mut self.unresolved_macros));
+        self.unresolved_macros = macros;
 
         for (module_id, depth, container, macro_call_id) in resolved {
             self.collect_macro_expansion(module_id, macro_call_id, depth, container);
index 6e22a877a9fa7980921f19be2af230e6eec56a3b..087268a9ecee4f2c3cac07835bb92b13277d7b0e 100644 (file)
@@ -224,7 +224,7 @@ pub(crate) fn field_visibilities_query(
     let resolver = variant_id.module(db).resolver(db);
     let mut res = ArenaMap::default();
     for (field_id, field_data) in var_data.fields().iter() {
-        res.insert(field_id, field_data.visibility.resolve(db, &resolver))
+        res.insert(field_id, field_data.visibility.resolve(db, &resolver));
     }
     Arc::new(res)
 }
index 9999790fae727631460c91ff3c7120b9ed1171df..e46f43a878fe13c7597b2d0a23e456d35a537587 100644 (file)
@@ -5,7 +5,7 @@
 use mbe::{SyntheticToken, SyntheticTokenId, TokenMap};
 use rustc_hash::FxHashMap;
 use syntax::{
-    ast::{self, AstNode},
+    ast::{self, AstNode, HasLoopBody},
     match_ast, SyntaxElement, SyntaxKind, SyntaxNode, TextRange,
 };
 use tt::Subtree;
@@ -142,8 +142,59 @@ pub(crate) fn fixup_syntax(node: &SyntaxNode) -> SyntaxFixups {
                         ]);
                     }
                 },
+                ast::WhileExpr(it) => {
+                    if it.condition().is_none() {
+                        // insert placeholder token after the while token
+                        let while_token = match it.while_token() {
+                            Some(t) => t,
+                            None => continue,
+                        };
+                        append.insert(while_token.into(), vec![
+                            SyntheticToken {
+                                kind: SyntaxKind::IDENT,
+                                text: "__ra_fixup".into(),
+                                range: end_range,
+                                id: EMPTY_ID,
+                            },
+                        ]);
+                    }
+                    if it.loop_body().is_none() {
+                        append.insert(node.clone().into(), vec![
+                            SyntheticToken {
+                                kind: SyntaxKind::L_CURLY,
+                                text: "{".into(),
+                                range: end_range,
+                                id: EMPTY_ID,
+                            },
+                            SyntheticToken {
+                                kind: SyntaxKind::R_CURLY,
+                                text: "}".into(),
+                                range: end_range,
+                                id: EMPTY_ID,
+                            },
+                        ]);
+                    }
+                },
+                ast::LoopExpr(it) => {
+                    if it.loop_body().is_none() {
+                        append.insert(node.clone().into(), vec![
+                            SyntheticToken {
+                                kind: SyntaxKind::L_CURLY,
+                                text: "{".into(),
+                                range: end_range,
+                                id: EMPTY_ID,
+                            },
+                            SyntheticToken {
+                                kind: SyntaxKind::R_CURLY,
+                                text: "}".into(),
+                                range: end_range,
+                                id: EMPTY_ID,
+                            },
+                        ]);
+                    }
+                },
                 // FIXME: foo::
-                // FIXME: for, loop, match etc.
+                // FIXME: for, match etc.
                 _ => (),
             }
         }
@@ -376,6 +427,61 @@ fn foo() {
             // the {} gets parsed as the condition, I think?
             expect![[r#"
 fn foo () {if {} {}}
+"#]],
+        )
+    }
+
+    #[test]
+    fn fixup_while_1() {
+        check(
+            r#"
+fn foo() {
+    while
+}
+"#,
+            expect![[r#"
+fn foo () {while __ra_fixup {}}
+"#]],
+        )
+    }
+
+    #[test]
+    fn fixup_while_2() {
+        check(
+            r#"
+fn foo() {
+    while foo
+}
+"#,
+            expect![[r#"
+fn foo () {while foo {}}
+"#]],
+        )
+    }
+    #[test]
+    fn fixup_while_3() {
+        check(
+            r#"
+fn foo() {
+    while {}
+}
+"#,
+            expect![[r#"
+fn foo () {while __ra_fixup {}}
+"#]],
+        )
+    }
+
+    #[test]
+    fn fixup_loop() {
+        check(
+            r#"
+fn foo() {
+    loop
+}
+"#,
+            expect![[r#"
+fn foo () {loop {}}
 "#]],
         )
     }
index 85b0a7735fe94e9fc4255b89c414b36f2865eabc..47d191822d841af60e5ae81977cabc7b45747e56 100644 (file)
@@ -381,6 +381,7 @@ macro_rules! known_names {
         bitor,
         bitxor_assign,
         bitxor,
+        branch,
         deref_mut,
         deref,
         div_assign,
@@ -396,6 +397,7 @@ macro_rules! known_names {
         not,
         owned_box,
         partial_ord,
+        poll,
         r#fn,
         rem_assign,
         rem,
index b0885ab003f71317db3669607aaf5515673a81f1..a9c124b42dc2c112b3a04718f4c0d161fcb00afc 100644 (file)
@@ -34,6 +34,7 @@ pub trait TyExt {
     fn callable_sig(&self, db: &dyn HirDatabase) -> Option<CallableSig>;
 
     fn strip_references(&self) -> &Ty;
+    fn strip_reference(&self) -> &Ty;
 
     /// If this is a `dyn Trait`, returns that trait.
     fn dyn_trait(&self) -> Option<TraitId>;
@@ -182,6 +183,10 @@ fn strip_references(&self) -> &Ty {
         t
     }
 
+    fn strip_reference(&self) -> &Ty {
+        self.as_reference().map_or(self, |(ty, _, _)| ty)
+    }
+
     fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<QuantifiedWhereClause>> {
         match self.kind(Interner) {
             TyKind::OpaqueType(opaque_ty_id, subst) => {
index d164e64a8be0780a0d9b5d54008b648e46b89c18..2a13106390d9f7f90773d1377bdc8b24351ca393 100644 (file)
     cast::Cast, fold::Shift, DebruijnIndex, GenericArgData, Mutability, TyVariableKind,
 };
 use hir_def::{
-    expr::{ArithOp, Array, BinaryOp, CmpOp, Expr, ExprId, Literal, Ordering, Statement, UnaryOp},
+    expr::{ArithOp, Array, BinaryOp, CmpOp, Expr, ExprId, Literal, Statement, UnaryOp},
     generics::TypeOrConstParamData,
     path::{GenericArg, GenericArgs},
     resolver::resolver_for_expr,
-    ConstParamId, FieldId, FunctionId, ItemContainerId, Lookup,
+    ConstParamId, FieldId, ItemContainerId, Lookup,
 };
-use hir_expand::name::{name, Name};
+use hir_expand::name::Name;
 use stdx::always;
 use syntax::ast::RangeOp;
 
@@ -28,7 +28,7 @@
         const_or_path_to_chalk, generic_arg_to_chalk, lower_to_chalk_mutability, ParamLoweringMode,
     },
     mapping::{from_chalk, ToChalk},
-    method_resolution::{self, VisibleFromModule},
+    method_resolution::{self, lang_names_for_bin_op, VisibleFromModule},
     primitive::{self, UintTy},
     static_lifetime, to_chalk_trait_id,
     utils::{generics, Generics},
@@ -947,7 +947,9 @@ fn infer_overloadable_binop(
         let lhs_ty = self.infer_expr(lhs, &lhs_expectation);
         let rhs_ty = self.table.new_type_var();
 
-        let func = self.resolve_binop_method(op);
+        let func = lang_names_for_bin_op(op).and_then(|(name, lang_item)| {
+            self.db.trait_data(self.resolve_lang_item(lang_item)?.as_trait()?).method_by_name(&name)
+        });
         let func = match func {
             Some(func) => func,
             None => {
@@ -1473,55 +1475,4 @@ fn builtin_binary_op_rhs_expectation(&mut self, op: BinaryOp, lhs_ty: Ty) -> Opt
             },
         })
     }
-
-    fn resolve_binop_method(&self, op: BinaryOp) -> Option<FunctionId> {
-        let (name, lang_item) = match op {
-            BinaryOp::LogicOp(_) => return None,
-            BinaryOp::ArithOp(aop) => match aop {
-                ArithOp::Add => (name!(add), name!(add)),
-                ArithOp::Mul => (name!(mul), name!(mul)),
-                ArithOp::Sub => (name!(sub), name!(sub)),
-                ArithOp::Div => (name!(div), name!(div)),
-                ArithOp::Rem => (name!(rem), name!(rem)),
-                ArithOp::Shl => (name!(shl), name!(shl)),
-                ArithOp::Shr => (name!(shr), name!(shr)),
-                ArithOp::BitXor => (name!(bitxor), name!(bitxor)),
-                ArithOp::BitOr => (name!(bitor), name!(bitor)),
-                ArithOp::BitAnd => (name!(bitand), name!(bitand)),
-            },
-            BinaryOp::Assignment { op: Some(aop) } => match aop {
-                ArithOp::Add => (name!(add_assign), name!(add_assign)),
-                ArithOp::Mul => (name!(mul_assign), name!(mul_assign)),
-                ArithOp::Sub => (name!(sub_assign), name!(sub_assign)),
-                ArithOp::Div => (name!(div_assign), name!(div_assign)),
-                ArithOp::Rem => (name!(rem_assign), name!(rem_assign)),
-                ArithOp::Shl => (name!(shl_assign), name!(shl_assign)),
-                ArithOp::Shr => (name!(shr_assign), name!(shr_assign)),
-                ArithOp::BitXor => (name!(bitxor_assign), name!(bitxor_assign)),
-                ArithOp::BitOr => (name!(bitor_assign), name!(bitor_assign)),
-                ArithOp::BitAnd => (name!(bitand_assign), name!(bitand_assign)),
-            },
-            BinaryOp::CmpOp(cop) => match cop {
-                CmpOp::Eq { negated: false } => (name!(eq), name!(eq)),
-                CmpOp::Eq { negated: true } => (name!(ne), name!(eq)),
-                CmpOp::Ord { ordering: Ordering::Less, strict: false } => {
-                    (name!(le), name!(partial_ord))
-                }
-                CmpOp::Ord { ordering: Ordering::Less, strict: true } => {
-                    (name!(lt), name!(partial_ord))
-                }
-                CmpOp::Ord { ordering: Ordering::Greater, strict: false } => {
-                    (name!(ge), name!(partial_ord))
-                }
-                CmpOp::Ord { ordering: Ordering::Greater, strict: true } => {
-                    (name!(gt), name!(partial_ord))
-                }
-            },
-            BinaryOp::Assignment { op: None } => return None,
-        };
-
-        let trait_ = self.resolve_lang_item(lang_item)?.as_trait()?;
-
-        self.db.trait_data(trait_).method_by_name(&name)
-    }
 }
index 3ed9c941f4790dc2dd07b949a89fee5cb1b50518..239f66bcb7e798f813a0e2d9206f78897a1d0c95 100644 (file)
@@ -1126,7 +1126,7 @@ pub(crate) fn field_types_query(
     let ctx =
         TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
     for (field_id, field_data) in var_data.fields().iter() {
-        res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(&field_data.type_ref)))
+        res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(&field_data.type_ref)));
     }
     Arc::new(res)
 }
index 15df7b3dd2b9b4b658ea0490cf5f36ca3c3541cf..64622545f8408b190cec4f87e906a0627d515a6a 100644 (file)
@@ -336,7 +336,7 @@ pub fn all_impls(&self) -> impl Iterator<Item = ImplId> + '_ {
     }
 }
 
-pub fn inherent_impl_crates_query(
+pub(crate) fn inherent_impl_crates_query(
     db: &dyn HirDatabase,
     krate: CrateId,
     fp: TyFingerprint,
@@ -419,6 +419,55 @@ pub fn def_crates(
     }
 }
 
+pub fn lang_names_for_bin_op(op: syntax::ast::BinaryOp) -> Option<(Name, Name)> {
+    use hir_expand::name;
+    use syntax::ast::{ArithOp, BinaryOp, CmpOp, Ordering};
+    Some(match op {
+        BinaryOp::LogicOp(_) => return None,
+        BinaryOp::ArithOp(aop) => match aop {
+            ArithOp::Add => (name!(add), name!(add)),
+            ArithOp::Mul => (name!(mul), name!(mul)),
+            ArithOp::Sub => (name!(sub), name!(sub)),
+            ArithOp::Div => (name!(div), name!(div)),
+            ArithOp::Rem => (name!(rem), name!(rem)),
+            ArithOp::Shl => (name!(shl), name!(shl)),
+            ArithOp::Shr => (name!(shr), name!(shr)),
+            ArithOp::BitXor => (name!(bitxor), name!(bitxor)),
+            ArithOp::BitOr => (name!(bitor), name!(bitor)),
+            ArithOp::BitAnd => (name!(bitand), name!(bitand)),
+        },
+        BinaryOp::Assignment { op: Some(aop) } => match aop {
+            ArithOp::Add => (name!(add_assign), name!(add_assign)),
+            ArithOp::Mul => (name!(mul_assign), name!(mul_assign)),
+            ArithOp::Sub => (name!(sub_assign), name!(sub_assign)),
+            ArithOp::Div => (name!(div_assign), name!(div_assign)),
+            ArithOp::Rem => (name!(rem_assign), name!(rem_assign)),
+            ArithOp::Shl => (name!(shl_assign), name!(shl_assign)),
+            ArithOp::Shr => (name!(shr_assign), name!(shr_assign)),
+            ArithOp::BitXor => (name!(bitxor_assign), name!(bitxor_assign)),
+            ArithOp::BitOr => (name!(bitor_assign), name!(bitor_assign)),
+            ArithOp::BitAnd => (name!(bitand_assign), name!(bitand_assign)),
+        },
+        BinaryOp::CmpOp(cop) => match cop {
+            CmpOp::Eq { negated: false } => (name!(eq), name!(eq)),
+            CmpOp::Eq { negated: true } => (name!(ne), name!(eq)),
+            CmpOp::Ord { ordering: Ordering::Less, strict: false } => {
+                (name!(le), name!(partial_ord))
+            }
+            CmpOp::Ord { ordering: Ordering::Less, strict: true } => {
+                (name!(lt), name!(partial_ord))
+            }
+            CmpOp::Ord { ordering: Ordering::Greater, strict: false } => {
+                (name!(ge), name!(partial_ord))
+            }
+            CmpOp::Ord { ordering: Ordering::Greater, strict: true } => {
+                (name!(gt), name!(partial_ord))
+            }
+        },
+        BinaryOp::Assignment { op: None } => return None,
+    })
+}
+
 /// Look up the method with the given name.
 pub(crate) fn lookup_method(
     ty: &Canonical<Ty>,
index d4925455d7bd2dcf4c7d90df5a0d2d6bfb41e9bc..8f984210e1176702c1ce23c865ed8aca631a4c82 100644 (file)
@@ -2769,6 +2769,10 @@ pub fn strip_references(&self) -> Type {
         self.derived(self.ty.strip_references().clone())
     }
 
+    pub fn strip_reference(&self) -> Type {
+        self.derived(self.ty.strip_reference().clone())
+    }
+
     pub fn is_unknown(&self) -> bool {
         self.ty.is_unknown()
     }
index fc8f23f19ab9112839303e2f33c022e056567891..416b6f58061da344580f4d9b672c6006e4749852 100644 (file)
@@ -324,6 +324,10 @@ pub fn resolve_type(&self, ty: &ast::Type) -> Option<Type> {
         self.imp.resolve_type(ty)
     }
 
+    pub fn resolve_trait(&self, trait_: &ast::Path) -> Option<Trait> {
+        self.imp.resolve_trait(trait_)
+    }
+
     // FIXME: Figure out a nice interface to inspect adjustments
     pub fn is_implicit_reborrow(&self, expr: &ast::Expr) -> Option<Mutability> {
         self.imp.is_implicit_reborrow(expr)
@@ -353,6 +357,26 @@ pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function
         self.imp.resolve_method_call(call).map(Function::from)
     }
 
+    pub fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option<Function> {
+        self.imp.resolve_await_to_poll(await_expr).map(Function::from)
+    }
+
+    pub fn resolve_prefix_expr(&self, prefix_expr: &ast::PrefixExpr) -> Option<Function> {
+        self.imp.resolve_prefix_expr(prefix_expr).map(Function::from)
+    }
+
+    pub fn resolve_index_expr(&self, index_expr: &ast::IndexExpr) -> Option<Function> {
+        self.imp.resolve_index_expr(index_expr).map(Function::from)
+    }
+
+    pub fn resolve_bin_expr(&self, bin_expr: &ast::BinExpr) -> Option<Function> {
+        self.imp.resolve_bin_expr(bin_expr).map(Function::from)
+    }
+
+    pub fn resolve_try_expr(&self, try_expr: &ast::TryExpr) -> Option<Function> {
+        self.imp.resolve_try_expr(try_expr).map(Function::from)
+    }
+
     pub fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> {
         self.imp.resolve_method_call_as_callable(call)
     }
@@ -924,7 +948,12 @@ fn original_range_opt(&self, node: &SyntaxNode) -> Option<FileRange> {
     }
 
     fn original_ast_node<N: AstNode>(&self, node: N) -> Option<N> {
-        self.wrap_node_infile(node).original_ast_node(self.db.upcast()).map(|it| it.value)
+        self.wrap_node_infile(node).original_ast_node(self.db.upcast()).map(
+            |InFile { file_id, value }| {
+                self.cache(find_root(value.syntax()), file_id);
+                value
+            },
+        )
     }
 
     fn diagnostics_display_range(&self, src: InFile<SyntaxNodePtr>) -> FileRange {
@@ -1009,6 +1038,20 @@ fn resolve_type(&self, ty: &ast::Type) -> Option<Type> {
         Some(Type::new_with_resolver(self.db, &analyze.resolver, ty))
     }
 
+    fn resolve_trait(&self, path: &ast::Path) -> Option<Trait> {
+        let analyze = self.analyze(path.syntax())?;
+        let hygiene = hir_expand::hygiene::Hygiene::new(self.db.upcast(), analyze.file_id);
+        let ctx = body::LowerCtx::with_hygiene(self.db.upcast(), &hygiene);
+        let hir_path = Path::from_src(path.clone(), &ctx)?;
+        match analyze
+            .resolver
+            .resolve_path_in_type_ns_fully(self.db.upcast(), hir_path.mod_path())?
+        {
+            TypeNs::TraitId(id) => Some(Trait { id }),
+            _ => None,
+        }
+    }
+
     fn is_implicit_reborrow(&self, expr: &ast::Expr) -> Option<Mutability> {
         self.analyze(expr.syntax())?.is_implicit_reborrow(self.db, expr)
     }
@@ -1043,6 +1086,26 @@ fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<FunctionId>
         self.analyze(call.syntax())?.resolve_method_call(self.db, call)
     }
 
+    fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option<FunctionId> {
+        self.analyze(await_expr.syntax())?.resolve_await_to_poll(self.db, await_expr)
+    }
+
+    fn resolve_prefix_expr(&self, prefix_expr: &ast::PrefixExpr) -> Option<FunctionId> {
+        self.analyze(prefix_expr.syntax())?.resolve_prefix_expr(self.db, prefix_expr)
+    }
+
+    fn resolve_index_expr(&self, index_expr: &ast::IndexExpr) -> Option<FunctionId> {
+        self.analyze(index_expr.syntax())?.resolve_index_expr(self.db, index_expr)
+    }
+
+    fn resolve_bin_expr(&self, bin_expr: &ast::BinExpr) -> Option<FunctionId> {
+        self.analyze(bin_expr.syntax())?.resolve_bin_expr(self.db, bin_expr)
+    }
+
+    fn resolve_try_expr(&self, try_expr: &ast::TryExpr) -> Option<FunctionId> {
+        self.analyze(try_expr.syntax())?.resolve_try_expr(self.db, try_expr)
+    }
+
     fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> {
         self.analyze(call.syntax())?.resolve_method_call_as_callable(self.db, call)
     }
index 1eb51b20c356b602efa8057b9b09a4447a2f9e93..f5e2e44307090151c24908cd5cf11a5896b0e709 100644 (file)
     Lookup, ModuleDefId, VariantId,
 };
 use hir_expand::{
-    builtin_fn_macro::BuiltinFnLikeExpander, hygiene::Hygiene, name::AsName, HirFileId, InFile,
+    builtin_fn_macro::BuiltinFnLikeExpander,
+    hygiene::Hygiene,
+    name,
+    name::{AsName, Name},
+    HirFileId, InFile,
 };
 use hir_ty::{
     diagnostics::{
         record_literal_missing_fields, record_pattern_missing_fields, unsafe_expressions,
         UnsafeExpr,
     },
-    method_resolution, Adjust, Adjustment, AutoBorrow, InferenceResult, Interner, Substitution,
-    TyExt, TyKind, TyLoweringContext,
+    method_resolution::{self, lang_names_for_bin_op},
+    Adjust, Adjustment, AutoBorrow, InferenceResult, Interner, Substitution, Ty, TyExt, TyKind,
+    TyLoweringContext,
 };
 use itertools::Itertools;
 use smallvec::SmallVec;
@@ -255,8 +260,90 @@ pub(crate) fn resolve_method_call(
     ) -> Option<FunctionId> {
         let expr_id = self.expr_id(db, &call.clone().into())?;
         let (f_in_trait, substs) = self.infer.as_ref()?.method_resolution(expr_id)?;
-        let f_in_impl = self.resolve_impl_method(db, f_in_trait, &substs);
-        f_in_impl.or(Some(f_in_trait))
+
+        Some(self.resolve_impl_method_or_trait_def(db, f_in_trait, &substs))
+    }
+
+    pub(crate) fn resolve_await_to_poll(
+        &self,
+        db: &dyn HirDatabase,
+        await_expr: &ast::AwaitExpr,
+    ) -> Option<FunctionId> {
+        let ty = self.ty_of_expr(db, &await_expr.expr()?.into())?;
+
+        let op_fn = db
+            .lang_item(self.resolver.krate(), hir_expand::name![poll].to_smol_str())?
+            .as_function()?;
+        let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(ty.clone()).build();
+
+        Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
+    }
+
+    pub(crate) fn resolve_prefix_expr(
+        &self,
+        db: &dyn HirDatabase,
+        prefix_expr: &ast::PrefixExpr,
+    ) -> Option<FunctionId> {
+        let lang_item_name = match prefix_expr.op_kind()? {
+            ast::UnaryOp::Deref => name![deref],
+            ast::UnaryOp::Not => name![not],
+            ast::UnaryOp::Neg => name![neg],
+        };
+        let ty = self.ty_of_expr(db, &prefix_expr.expr()?.into())?;
+
+        let op_fn = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
+        let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(ty.clone()).build();
+
+        Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
+    }
+
+    pub(crate) fn resolve_index_expr(
+        &self,
+        db: &dyn HirDatabase,
+        index_expr: &ast::IndexExpr,
+    ) -> Option<FunctionId> {
+        let base_ty = self.ty_of_expr(db, &index_expr.base()?.into())?;
+        let index_ty = self.ty_of_expr(db, &index_expr.index()?.into())?;
+
+        let lang_item_name = name![index];
+
+        let op_fn = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
+        let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn)
+            .push(base_ty.clone())
+            .push(index_ty.clone())
+            .build();
+        Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
+    }
+
+    pub(crate) fn resolve_bin_expr(
+        &self,
+        db: &dyn HirDatabase,
+        binop_expr: &ast::BinExpr,
+    ) -> Option<FunctionId> {
+        let op = binop_expr.op_kind()?;
+        let lhs = self.ty_of_expr(db, &binop_expr.lhs()?.into())?;
+        let rhs = self.ty_of_expr(db, &binop_expr.rhs()?.into())?;
+
+        let op_fn = lang_names_for_bin_op(op)
+            .and_then(|(name, lang_item)| self.lang_trait_fn(db, &lang_item, &name))?;
+        let substs =
+            hir_ty::TyBuilder::subst_for_def(db, op_fn).push(lhs.clone()).push(rhs.clone()).build();
+
+        Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
+    }
+
+    pub(crate) fn resolve_try_expr(
+        &self,
+        db: &dyn HirDatabase,
+        try_expr: &ast::TryExpr,
+    ) -> Option<FunctionId> {
+        let ty = self.ty_of_expr(db, &try_expr.expr()?.into())?;
+
+        let op_fn =
+            db.lang_item(self.resolver.krate(), name![branch].to_smol_str())?.as_function()?;
+        let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(ty.clone()).build();
+
+        Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
     }
 
     pub(crate) fn resolve_field(
@@ -666,6 +753,29 @@ fn resolve_impl_method(
         let fun_data = db.function_data(func);
         method_resolution::lookup_impl_method(self_ty, db, trait_env, impled_trait, &fun_data.name)
     }
+
+    fn resolve_impl_method_or_trait_def(
+        &self,
+        db: &dyn HirDatabase,
+        func: FunctionId,
+        substs: &Substitution,
+    ) -> FunctionId {
+        self.resolve_impl_method(db, func, substs).unwrap_or(func)
+    }
+
+    fn lang_trait_fn(
+        &self,
+        db: &dyn HirDatabase,
+        lang_trait: &Name,
+        method_name: &Name,
+    ) -> Option<FunctionId> {
+        db.trait_data(db.lang_item(self.resolver.krate(), lang_trait.to_smol_str())?.as_trait()?)
+            .method_by_name(method_name)
+    }
+
+    fn ty_of_expr(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<&Ty> {
+        self.infer.as_ref()?.type_of_expr.get(self.expr_id(db, &expr)?)
+    }
 }
 
 fn scope_for(
index 943c1d90e63659830d017e9ab4b102a594de62f1..87f5018fb69586f44e6307cb8f2561d558d85e03 100644 (file)
@@ -36,7 +36,7 @@
 //     pub struct Baz;
 // }
 //
-// use foo::{Baz, Bar};
+// use foo::{Bar, Baz};
 //
 // fn qux(bar: Bar, baz: Baz) {}
 // ```
@@ -281,7 +281,7 @@ mod foo {
     pub fn f() {}
 }
 
-use foo::{Baz, Bar, f};
+use foo::{Bar, Baz, f};
 
 fn qux(bar: Bar, baz: Baz) {
     f();
@@ -351,7 +351,7 @@ mod foo {
     pub fn f() {}
 }
 
-use foo::{Baz, Bar, f};
+use foo::{Bar, Baz, f};
 
 fn qux(bar: Bar, baz: Baz) {
     f();
@@ -440,7 +440,7 @@ pub fn g() {}
     }
 }
 
-use foo::{bar::{Baz, Bar, f}, baz::*};
+use foo::{bar::{Bar, Baz, f}, baz::*};
 
 fn qux(bar: Bar, baz: Baz) {
     f();
@@ -561,7 +561,7 @@ pub fn j() {}
 
 use foo::{
     bar::{*, f},
-    baz::{g, qux::{q, h}}
+    baz::{g, qux::{h, q}}
 };
 
 fn qux(bar: Bar, baz: Baz) {
index 4461fbd5ac82709eeb7a6f0b6ff904c88c250028..35cd42908af2c0d225d3fa5d0fb3336fb3629d96 100644 (file)
@@ -1,8 +1,8 @@
-use hir::{HasSource, InFile};
+use hir::{HasSource, HirDisplay, InFile};
 use ide_db::assists::{AssistId, AssistKind};
 use syntax::{
-    ast::{self, edit::IndentLevel},
-    AstNode, TextSize,
+    ast::{self, make, HasArgList},
+    match_ast, AstNode, SyntaxNode,
 };
 
 use crate::assist_context::{AssistContext, Assists};
@@ -32,8 +32,8 @@
 // }
 // ```
 pub(crate) fn generate_enum_variant(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
-    let path_expr: ast::PathExpr = ctx.find_node_at_offset()?;
-    let path = path_expr.path()?;
+    let path: ast::Path = ctx.find_node_at_offset()?;
+    let parent = path_parent(&path)?;
 
     if ctx.sema.resolve_path(&path).is_some() {
         // No need to generate anything if the path resolves
@@ -50,26 +50,71 @@ pub(crate) fn generate_enum_variant(acc: &mut Assists, ctx: &AssistContext<'_>)
         ctx.sema.resolve_path(&path.qualifier()?)
     {
         let target = path.syntax().text_range();
-        return add_variant_to_accumulator(acc, ctx, target, e, &name_ref);
+        return add_variant_to_accumulator(acc, ctx, target, e, &name_ref, parent);
     }
 
     None
 }
 
+#[derive(Debug)]
+enum PathParent {
+    PathExpr(ast::PathExpr),
+    RecordExpr(ast::RecordExpr),
+    PathPat(ast::PathPat),
+    UseTree(ast::UseTree),
+}
+
+impl PathParent {
+    fn syntax(&self) -> &SyntaxNode {
+        match self {
+            PathParent::PathExpr(it) => it.syntax(),
+            PathParent::RecordExpr(it) => it.syntax(),
+            PathParent::PathPat(it) => it.syntax(),
+            PathParent::UseTree(it) => it.syntax(),
+        }
+    }
+
+    fn make_field_list(&self, ctx: &AssistContext<'_>) -> Option<ast::FieldList> {
+        let scope = ctx.sema.scope(self.syntax())?;
+
+        match self {
+            PathParent::PathExpr(it) => {
+                if let Some(call_expr) = it.syntax().parent().and_then(ast::CallExpr::cast) {
+                    make_tuple_field_list(call_expr, ctx, &scope)
+                } else {
+                    None
+                }
+            }
+            PathParent::RecordExpr(it) => make_record_field_list(it, ctx, &scope),
+            PathParent::UseTree(_) | PathParent::PathPat(_) => None,
+        }
+    }
+}
+
+fn path_parent(path: &ast::Path) -> Option<PathParent> {
+    let parent = path.syntax().parent()?;
+
+    match_ast! {
+        match parent {
+            ast::PathExpr(it) => Some(PathParent::PathExpr(it)),
+            ast::RecordExpr(it) => Some(PathParent::RecordExpr(it)),
+            ast::PathPat(it) => Some(PathParent::PathPat(it)),
+            ast::UseTree(it) => Some(PathParent::UseTree(it)),
+            _ => None
+        }
+    }
+}
+
 fn add_variant_to_accumulator(
     acc: &mut Assists,
     ctx: &AssistContext<'_>,
     target: syntax::TextRange,
     adt: hir::Enum,
     name_ref: &ast::NameRef,
+    parent: PathParent,
 ) -> Option<()> {
     let db = ctx.db();
     let InFile { file_id, value: enum_node } = adt.source(db)?.original_ast_node(db)?;
-    let enum_indent = IndentLevel::from_node(&enum_node.syntax());
-
-    let variant_list = enum_node.variant_list()?;
-    let offset = variant_list.syntax().text_range().end() - TextSize::of('}');
-    let empty_enum = variant_list.variants().next().is_none();
 
     acc.add(
         AssistId("generate_enum_variant", AssistKind::Generate),
@@ -77,18 +122,80 @@ fn add_variant_to_accumulator(
         target,
         |builder| {
             builder.edit_file(file_id.original_file(db));
-            let text = format!(
-                "{maybe_newline}{indent_1}{name},\n{enum_indent}",
-                maybe_newline = if empty_enum { "\n" } else { "" },
-                indent_1 = IndentLevel(1),
-                name = name_ref,
-                enum_indent = enum_indent
-            );
-            builder.insert(offset, text)
+            let node = builder.make_mut(enum_node);
+            let variant = make_variant(ctx, name_ref, parent);
+            node.variant_list().map(|it| it.add_variant(variant.clone_for_update()));
         },
     )
 }
 
+fn make_variant(
+    ctx: &AssistContext<'_>,
+    name_ref: &ast::NameRef,
+    parent: PathParent,
+) -> ast::Variant {
+    let field_list = parent.make_field_list(ctx);
+    make::variant(make::name(&name_ref.text()), field_list)
+}
+
+fn make_record_field_list(
+    record: &ast::RecordExpr,
+    ctx: &AssistContext<'_>,
+    scope: &hir::SemanticsScope<'_>,
+) -> Option<ast::FieldList> {
+    let fields = record.record_expr_field_list()?.fields();
+    let record_fields = fields.map(|field| {
+        let name = name_from_field(&field);
+
+        let ty = field
+            .expr()
+            .and_then(|it| expr_ty(ctx, it, scope))
+            .unwrap_or_else(make::ty_placeholder);
+
+        make::record_field(None, name, ty)
+    });
+    Some(make::record_field_list(record_fields).into())
+}
+
+fn name_from_field(field: &ast::RecordExprField) -> ast::Name {
+    let text = match field.name_ref() {
+        Some(it) => it.to_string(),
+        None => name_from_field_shorthand(field).unwrap_or("unknown".to_string()),
+    };
+    make::name(&text)
+}
+
+fn name_from_field_shorthand(field: &ast::RecordExprField) -> Option<String> {
+    let path = match field.expr()? {
+        ast::Expr::PathExpr(path_expr) => path_expr.path(),
+        _ => None,
+    }?;
+    Some(path.as_single_name_ref()?.to_string())
+}
+
+fn make_tuple_field_list(
+    call_expr: ast::CallExpr,
+    ctx: &AssistContext<'_>,
+    scope: &hir::SemanticsScope<'_>,
+) -> Option<ast::FieldList> {
+    let args = call_expr.arg_list()?.args();
+    let tuple_fields = args.map(|arg| {
+        let ty = expr_ty(ctx, arg, &scope).unwrap_or_else(make::ty_placeholder);
+        make::tuple_field(None, ty)
+    });
+    Some(make::tuple_field_list(tuple_fields).into())
+}
+
+fn expr_ty(
+    ctx: &AssistContext<'_>,
+    arg: ast::Expr,
+    scope: &hir::SemanticsScope<'_>,
+) -> Option<ast::Type> {
+    let ty = ctx.sema.type_of_expr(&arg).map(|it| it.adjusted())?;
+    let text = ty.display_source_code(ctx.db(), scope.module().into()).ok()?;
+    Some(make::ty(&text))
+}
+
 #[cfg(test)]
 mod tests {
     use crate::tests::{check_assist, check_assist_not_applicable};
@@ -221,6 +328,236 @@ enum Foo {
 fn main() {
     m::Foo::Baz
 }
+",
+        )
+    }
+
+    #[test]
+    fn associated_single_element_tuple() {
+        check_assist(
+            generate_enum_variant,
+            r"
+enum Foo {}
+fn main() {
+    Foo::Bar$0(true)
+}
+",
+            r"
+enum Foo {
+    Bar(bool),
+}
+fn main() {
+    Foo::Bar(true)
+}
+",
+        )
+    }
+
+    #[test]
+    fn associated_single_element_tuple_unknown_type() {
+        check_assist(
+            generate_enum_variant,
+            r"
+enum Foo {}
+fn main() {
+    Foo::Bar$0(x)
+}
+",
+            r"
+enum Foo {
+    Bar(_),
+}
+fn main() {
+    Foo::Bar(x)
+}
+",
+        )
+    }
+
+    #[test]
+    fn associated_multi_element_tuple() {
+        check_assist(
+            generate_enum_variant,
+            r"
+struct Struct {}
+enum Foo {}
+fn main() {
+    Foo::Bar$0(true, x, Struct {})
+}
+",
+            r"
+struct Struct {}
+enum Foo {
+    Bar(bool, _, Struct),
+}
+fn main() {
+    Foo::Bar(true, x, Struct {})
+}
+",
+        )
+    }
+
+    #[test]
+    fn associated_record() {
+        check_assist(
+            generate_enum_variant,
+            r"
+enum Foo {}
+fn main() {
+    Foo::$0Bar { x: true }
+}
+",
+            r"
+enum Foo {
+    Bar { x: bool },
+}
+fn main() {
+    Foo::Bar { x: true }
+}
+",
+        )
+    }
+
+    #[test]
+    fn associated_record_unknown_type() {
+        check_assist(
+            generate_enum_variant,
+            r"
+enum Foo {}
+fn main() {
+    Foo::$0Bar { x: y }
+}
+",
+            r"
+enum Foo {
+    Bar { x: _ },
+}
+fn main() {
+    Foo::Bar { x: y }
+}
+",
+        )
+    }
+
+    #[test]
+    fn associated_record_field_shorthand() {
+        check_assist(
+            generate_enum_variant,
+            r"
+enum Foo {}
+fn main() {
+    let x = true;
+    Foo::$0Bar { x }
+}
+",
+            r"
+enum Foo {
+    Bar { x: bool },
+}
+fn main() {
+    let x = true;
+    Foo::Bar { x }
+}
+",
+        )
+    }
+
+    #[test]
+    fn associated_record_field_shorthand_unknown_type() {
+        check_assist(
+            generate_enum_variant,
+            r"
+enum Foo {}
+fn main() {
+    Foo::$0Bar { x }
+}
+",
+            r"
+enum Foo {
+    Bar { x: _ },
+}
+fn main() {
+    Foo::Bar { x }
+}
+",
+        )
+    }
+
+    #[test]
+    fn associated_record_field_multiple_fields() {
+        check_assist(
+            generate_enum_variant,
+            r"
+struct Struct {}
+enum Foo {}
+fn main() {
+    Foo::$0Bar { x, y: x, s: Struct {} }
+}
+",
+            r"
+struct Struct {}
+enum Foo {
+    Bar { x: _, y: _, s: Struct },
+}
+fn main() {
+    Foo::Bar { x, y: x, s: Struct {} }
+}
+",
+        )
+    }
+
+    #[test]
+    fn use_tree() {
+        check_assist(
+            generate_enum_variant,
+            r"
+//- /main.rs
+mod foo;
+use foo::Foo::Bar$0;
+
+//- /foo.rs
+enum Foo {}
+",
+            r"
+enum Foo {
+    Bar,
+}
+",
+        )
+    }
+
+    #[test]
+    fn not_applicable_for_path_type() {
+        check_assist_not_applicable(
+            generate_enum_variant,
+            r"
+enum Foo {}
+impl Foo::Bar$0 {}
+",
+        )
+    }
+
+    #[test]
+    fn path_pat() {
+        check_assist(
+            generate_enum_variant,
+            r"
+enum Foo {}
+fn foo(x: Foo) {
+    match x {
+        Foo::Bar$0 =>
+    }
+}
+",
+            r"
+enum Foo {
+    Bar,
+}
+fn foo(x: Foo) {
+    match x {
+        Foo::Bar =>
+    }
+}
 ",
         )
     }
index 658a1aadf53ecf9e0549f27af1671d3d0b9bd127..80d3b925593674266776a705fadd0c4ea59f9b65 100644 (file)
@@ -7,7 +7,7 @@
     imports::insert_use::remove_path_if_in_use_stmt,
     path_transform::PathTransform,
     search::{FileReference, SearchScope},
-    syntax_helpers::node_ext::expr_as_name_ref,
+    syntax_helpers::{insert_whitespace_into_node::insert_ws_into, node_ext::expr_as_name_ref},
     RootDatabase,
 };
 use itertools::{izip, Itertools};
@@ -301,7 +301,16 @@ fn inline(
     params: &[(ast::Pat, Option<ast::Type>, hir::Param)],
     CallInfo { node, arguments, generic_arg_list }: &CallInfo,
 ) -> ast::Expr {
-    let body = fn_body.clone_for_update();
+    let body = if sema.hir_file_for(fn_body.syntax()).is_macro() {
+        cov_mark::hit!(inline_call_defined_in_macro);
+        if let Some(body) = ast::BlockExpr::cast(insert_ws_into(fn_body.syntax().clone())) {
+            body
+        } else {
+            fn_body.clone_for_update()
+        }
+    } else {
+        fn_body.clone_for_update()
+    };
     let usages_for_locals = |local| {
         Definition::Local(local)
             .usages(sema)
@@ -1144,6 +1153,41 @@ fn bar() -> u32 {
         x
     }) + foo()
 }
+"#,
+        )
+    }
+
+    #[test]
+    fn inline_call_defined_in_macro() {
+        cov_mark::check!(inline_call_defined_in_macro);
+        check_assist(
+            inline_call,
+            r#"
+macro_rules! define_foo {
+    () => { fn foo() -> u32 {
+        let x = 0;
+        x
+    } };
+}
+define_foo!();
+fn bar() -> u32 {
+    foo$0()
+}
+"#,
+            r#"
+macro_rules! define_foo {
+    () => { fn foo() -> u32 {
+        let x = 0;
+        x
+    } };
+}
+define_foo!();
+fn bar() -> u32 {
+    {
+      let x = 0;
+      x
+    }
+}
 "#,
         )
     }
index e8d48607be0e9f938814bb94f5995ae6d84bad40..6eaab48a32ba54e567f0e958f9a52d8cebbe9bbe 100644 (file)
@@ -535,7 +535,7 @@ mod foo {
     pub struct Baz;
 }
 
-use foo::{Baz, Bar};
+use foo::{Bar, Baz};
 
 fn qux(bar: Bar, baz: Baz) {}
 "#####,
index 149afcac9d4786e5bc38bf93b4cfdefb72c04021..72579e6026aee736868f1ae64bbdc310b00b46cd 100644 (file)
@@ -400,7 +400,7 @@ pub(crate) fn add_enum_variant(
     ) {
         if let PathCompletionCtx { kind: PathKind::Pat { pat_ctx }, .. } = path_ctx {
             cov_mark::hit!(enum_variant_pattern_path);
-            self.add_variant_pat(ctx, pat_ctx, variant, local_name);
+            self.add_variant_pat(ctx, pat_ctx, Some(path_ctx), variant, local_name);
             return;
         }
 
@@ -484,12 +484,14 @@ pub(crate) fn add_variant_pat(
         &mut self,
         ctx: &CompletionContext<'_>,
         pattern_ctx: &PatternContext,
+        path_ctx: Option<&PathCompletionCtx>,
         variant: hir::Variant,
         local_name: Option<hir::Name>,
     ) {
         self.add_opt(render_variant_pat(
             RenderContext::new(ctx),
             pattern_ctx,
+            path_ctx,
             variant,
             local_name.clone(),
             None,
@@ -504,7 +506,14 @@ pub(crate) fn add_qualified_variant_pat(
         path: hir::ModPath,
     ) {
         let path = Some(&path);
-        self.add_opt(render_variant_pat(RenderContext::new(ctx), pattern_ctx, variant, None, path));
+        self.add_opt(render_variant_pat(
+            RenderContext::new(ctx),
+            pattern_ctx,
+            None,
+            variant,
+            None,
+            path,
+        ));
     }
 
     pub(crate) fn add_struct_pat(
index 1d8a8c5f20db35828438e90abaa8bd1b6dbbed27..d9fe94cb44ee1d3d5e3d4573d5d6e696f411c67b 100644 (file)
@@ -115,7 +115,7 @@ pub(crate) fn complete_attribute_path(
             });
             acc.add_nameref_keywords_with_colon(ctx);
         }
-        Qualified::Infer | Qualified::With { .. } => {}
+        Qualified::TypeAnchor { .. } | Qualified::With { .. } => {}
     }
 
     let attributes = annotated_item_kind.and_then(|kind| {
index 14538fef6072c8b8a481b182321ab6cb5a6d1b5c..793c22630bf8959039856f2ecd9ddd126565cc1a 100644 (file)
@@ -97,7 +97,7 @@ pub(crate) fn complete_derive_path(
             });
             acc.add_nameref_keywords_with_colon(ctx);
         }
-        Qualified::Infer | Qualified::With { .. } => {}
+        Qualified::TypeAnchor { .. } | Qualified::With { .. } => {}
     }
 }
 
index bdf6e64f09696d27660409743a8d42842e8f7751..5d0ddaaf2a22854e96f1029db1a14722afbe08a2 100644 (file)
@@ -11,7 +11,14 @@ pub(crate) fn complete_expr_path(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
     path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
-    &ExprCtx {
+    expr_ctx: &ExprCtx,
+) {
+    let _p = profile::span("complete_expr_path");
+    if !ctx.qualifier_ctx.none() {
+        return;
+    }
+
+    let &ExprCtx {
         in_block_expr,
         in_loop_body,
         after_if_expr,
@@ -23,12 +30,7 @@ pub(crate) fn complete_expr_path(
         ref impl_,
         in_match_guard,
         ..
-    }: &ExprCtx,
-) {
-    let _p = profile::span("complete_expr_path");
-    if !ctx.qualifier_ctx.none() {
-        return;
-    }
+    } = expr_ctx;
 
     let wants_mut_token =
         ref_expr_parent.as_ref().map(|it| it.mut_token().is_none()).unwrap_or(false);
@@ -46,11 +48,32 @@ pub(crate) fn complete_expr_path(
     };
 
     match qualified {
-        Qualified::Infer => ctx
+        Qualified::TypeAnchor { ty: None, trait_: None } => ctx
             .traits_in_scope()
             .iter()
             .flat_map(|&it| hir::Trait::from(it).items(ctx.sema.db))
             .for_each(|item| add_assoc_item(acc, item)),
+        Qualified::TypeAnchor { trait_: Some(trait_), .. } => {
+            trait_.items(ctx.sema.db).into_iter().for_each(|item| add_assoc_item(acc, item))
+        }
+        Qualified::TypeAnchor { ty: Some(ty), trait_: None } => {
+            if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
+                cov_mark::hit!(completes_variant_through_alias);
+                acc.add_enum_variants(ctx, path_ctx, e);
+            }
+
+            ctx.iterate_path_candidates(&ty, |item| {
+                add_assoc_item(acc, item);
+            });
+
+            // Iterate assoc types separately
+            ty.iterate_assoc_items(ctx.db, ctx.krate, |item| {
+                if let hir::AssocItem::TypeAlias(ty) = item {
+                    acc.add_type_alias(ctx, ty)
+                }
+                None::<()>
+            });
+        }
         Qualified::With { resolution: None, .. } => {}
         Qualified::With { resolution: Some(resolution), .. } => {
             // Add associated types on type parameters and `Self`.
@@ -179,10 +202,21 @@ pub(crate) fn complete_expr_path(
                     }
                 }
             }
-            ctx.process_all_names(&mut |name, def| {
-                if scope_def_applicable(def) {
-                    acc.add_path_resolution(ctx, path_ctx, name, def);
+            ctx.process_all_names(&mut |name, def| match def {
+                ScopeDef::ModuleDef(hir::ModuleDef::Trait(t)) => {
+                    let assocs = t.items_with_supertraits(ctx.db);
+                    match &*assocs {
+                        // traits with no assoc items are unusable as expressions since
+                        // there is no associated item path that can be constructed with them
+                        [] => (),
+                        // FIXME: Render the assoc item with the trait qualified
+                        &[_item] => acc.add_path_resolution(ctx, path_ctx, name, def),
+                        // FIXME: Append `::` to the thing here, since a trait on its own won't work
+                        [..] => acc.add_path_resolution(ctx, path_ctx, name, def),
+                    }
                 }
+                _ if scope_def_applicable(def) => acc.add_path_resolution(ctx, path_ctx, name, def),
+                _ => (),
             });
 
             if is_func_update.is_none() {
index 4e4c9fba6cc57250498a877f159967ca9051e538..60d05ae46b9168181d7823f660867a1b3ad36462 100644 (file)
@@ -66,7 +66,7 @@ pub(crate) fn complete_item_list(
             });
             acc.add_nameref_keywords_with_colon(ctx);
         }
-        Qualified::Infer | Qualified::No | Qualified::With { .. } => {}
+        Qualified::TypeAnchor { .. } | Qualified::No | Qualified::With { .. } => {}
     }
 }
 
index 17dfe432b3529e453e81a8fbaebf174c99d63046..71d2d9d434b449f915dbad29a58c756ae591b651 100644 (file)
@@ -74,7 +74,7 @@ pub(crate) fn complete_pattern(
                 hir::ModuleDef::Variant(variant)
                     if refutable || single_variant_enum(variant.parent_enum(ctx.db)) =>
                 {
-                    acc.add_variant_pat(ctx, pattern_ctx, variant, Some(name.clone()));
+                    acc.add_variant_pat(ctx, pattern_ctx, None, variant, Some(name.clone()));
                     true
                 }
                 hir::ModuleDef::Adt(hir::Adt::Enum(e)) => refutable || single_variant_enum(e),
@@ -180,6 +180,6 @@ pub(crate) fn complete_pattern_path(
 
             acc.add_nameref_keywords_with_colon(ctx);
         }
-        Qualified::Infer | Qualified::With { .. } => {}
+        Qualified::TypeAnchor { .. } | Qualified::With { .. } => {}
     }
 }
index 87a998dfcce6bfab229e85d6302330a2e7b891bc..8f9db2f94c204c5e78bd962c0de7e07b3a08e3f0 100644 (file)
@@ -49,11 +49,27 @@ pub(crate) fn complete_type_path(
     };
 
     match qualified {
-        Qualified::Infer => ctx
+        Qualified::TypeAnchor { ty: None, trait_: None } => ctx
             .traits_in_scope()
             .iter()
             .flat_map(|&it| hir::Trait::from(it).items(ctx.sema.db))
             .for_each(|item| add_assoc_item(acc, item)),
+        Qualified::TypeAnchor { trait_: Some(trait_), .. } => {
+            trait_.items(ctx.sema.db).into_iter().for_each(|item| add_assoc_item(acc, item))
+        }
+        Qualified::TypeAnchor { ty: Some(ty), trait_: None } => {
+            ctx.iterate_path_candidates(&ty, |item| {
+                add_assoc_item(acc, item);
+            });
+
+            // Iterate assoc types separately
+            ty.iterate_assoc_items(ctx.db, ctx.krate, |item| {
+                if let hir::AssocItem::TypeAlias(ty) = item {
+                    acc.add_type_alias(ctx, ty)
+                }
+                None::<()>
+            });
+        }
         Qualified::With { resolution: None, .. } => {}
         Qualified::With { resolution: Some(resolution), .. } => {
             // Add associated types on type parameters and `Self`.
index bb2ecc9fdde76b384464d22b9c5df5b1056b0a10..2555c34aa7477090bc7f588ae66a908990f9db34 100644 (file)
@@ -115,6 +115,6 @@ pub(crate) fn complete_use_path(
             });
             acc.add_nameref_keywords_with_colon(ctx);
         }
-        Qualified::Infer | Qualified::With { resolution: None, .. } => {}
+        Qualified::TypeAnchor { .. } | Qualified::With { resolution: None, .. } => {}
     }
 }
index ca8303906a800a82f425cdd716a9f442c8f8ef16..5e6cf4bf9a52142d572924a5f280d5625f88f2a1 100644 (file)
@@ -29,7 +29,7 @@ pub(crate) fn complete_vis_path(
 
             acc.add_super_keyword(ctx, *super_chain_len);
         }
-        Qualified::Absolute | Qualified::Infer | Qualified::With { .. } => {}
+        Qualified::Absolute | Qualified::TypeAnchor { .. } | Qualified::With { .. } => {}
         Qualified::No => {
             if !has_in_token {
                 cov_mark::hit!(kw_completion_in);
index 93b6ad5d145dff545f979c2aad0d9f06ad96179d..e35f79d2b6951e05a57c943af8eba44bb60e7f57 100644 (file)
@@ -193,7 +193,10 @@ pub(super) enum Qualified {
         super_chain_len: Option<usize>,
     },
     /// <_>::
-    Infer,
+    TypeAnchor {
+        ty: Option<hir::Type>,
+        trait_: Option<hir::Trait>,
+    },
     /// Whether the path is an absolute path
     Absolute,
 }
index c71ffa0ed86fd754c4d7a0ab6cd29041998d444b..22ec7cead4988cc54d33b9f8c49e6c4b34cd1d88 100644 (file)
@@ -162,11 +162,52 @@ pub(super) fn expand_and_analyze(
     }
 
     /// Calculate the expected type and name of the cursor position.
-    fn expected_type_and_name(&self) -> (Option<Type>, Option<NameOrNameRef>) {
+    fn expected_type_and_name(
+        &self,
+        name_like: &ast::NameLike,
+    ) -> (Option<Type>, Option<NameOrNameRef>) {
         let mut node = match self.token.parent() {
             Some(it) => it,
             None => return (None, None),
         };
+
+        let strip_refs = |mut ty: Type| match name_like {
+            ast::NameLike::NameRef(n) => {
+                let p = match n.syntax().parent() {
+                    Some(it) => it,
+                    None => return ty,
+                };
+                let top_syn = match_ast! {
+                    match p {
+                        ast::FieldExpr(e) => e
+                            .syntax()
+                            .ancestors()
+                            .map_while(ast::FieldExpr::cast)
+                            .last()
+                            .map(|it| it.syntax().clone()),
+                        ast::PathSegment(e) => e
+                            .syntax()
+                            .ancestors()
+                            .skip(1)
+                            .take_while(|it| ast::Path::can_cast(it.kind()) || ast::PathExpr::can_cast(it.kind()))
+                            .find_map(ast::PathExpr::cast)
+                            .map(|it| it.syntax().clone()),
+                        _ => None
+                    }
+                };
+                let top_syn = match top_syn {
+                    Some(it) => it,
+                    None => return ty,
+                };
+                for _ in top_syn.ancestors().skip(1).map_while(ast::RefExpr::cast) {
+                    cov_mark::hit!(expected_type_fn_param_ref);
+                    ty = ty.strip_reference();
+                }
+                ty
+            }
+            _ => ty,
+        };
+
         loop {
             break match_ast! {
                 match node {
@@ -199,13 +240,9 @@ fn expected_type_and_name(&self) -> (Option<Type>, Option<NameOrNameRef>) {
                             self.token.clone(),
                         ).map(|ap| {
                             let name = ap.ident().map(NameOrNameRef::Name);
-                            let ty = if has_ref(&self.token) {
-                                cov_mark::hit!(expected_type_fn_param_ref);
-                                ap.ty.remove_ref()
-                            } else {
-                                Some(ap.ty)
-                            };
-                            (ty, name)
+
+                            let ty = strip_refs(ap.ty);
+                            (Some(ty), name)
                         })
                         .unwrap_or((None, None))
                     },
@@ -330,8 +367,6 @@ fn analyze(
             return None;
         }
 
-        (self.expected_type, self.expected_name) = self.expected_type_and_name();
-
         // Overwrite the path kind for derives
         if let Some((original_file, file_with_fake_ident, offset, origin_attr)) = derive_ctx {
             if let Some(ast::NameLike::NameRef(name_ref)) =
@@ -389,6 +424,7 @@ fn analyze(
                 return Some(analysis);
             }
         };
+        (self.expected_type, self.expected_name) = self.expected_type_and_name(&name_like);
         let analysis = match name_like {
             ast::NameLike::Lifetime(lifetime) => CompletionAnalysis::Lifetime(
                 Self::classify_lifetime(&self.sema, original_file, lifetime)?,
@@ -556,7 +592,7 @@ fn classify_name_ref(
             has_call_parens: false,
             has_macro_bang: false,
             qualified: Qualified::No,
-            parent: path.parent_path(),
+            parent: None,
             path: path.clone(),
             kind: PathKind::Item { kind: ItemListKind::SourceFile },
             has_type_args: false,
@@ -791,92 +827,125 @@ fn classify_name_ref(
             PathKind::Type { location: location.unwrap_or(TypeLocation::Other) }
         };
 
+        let mut kind_macro_call = |it: ast::MacroCall| {
+            path_ctx.has_macro_bang = it.excl_token().is_some();
+            let parent = it.syntax().parent()?;
+            // Any path in an item list will be treated as a macro call by the parser
+            let kind = match_ast! {
+                match parent {
+                    ast::MacroExpr(expr) => make_path_kind_expr(expr.into()),
+                    ast::MacroPat(it) => PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())},
+                    ast::MacroType(ty) => make_path_kind_type(ty.into()),
+                    ast::ItemList(_) => PathKind::Item { kind: ItemListKind::Module },
+                    ast::AssocItemList(_) => PathKind::Item { kind: match parent.parent() {
+                        Some(it) => match_ast! {
+                            match it {
+                                ast::Trait(_) => ItemListKind::Trait,
+                                ast::Impl(it) => if it.trait_().is_some() {
+                                    ItemListKind::TraitImpl(find_node_in_file_compensated(sema, original_file, &it))
+                                } else {
+                                    ItemListKind::Impl
+                                },
+                                _ => return None
+                            }
+                        },
+                        None => return None,
+                    } },
+                    ast::ExternItemList(_) => PathKind::Item { kind: ItemListKind::ExternBlock },
+                    ast::SourceFile(_) => PathKind::Item { kind: ItemListKind::SourceFile },
+                    _ => return None,
+                }
+            };
+            Some(kind)
+        };
+        let make_path_kind_attr = |meta: ast::Meta| {
+            let attr = meta.parent_attr()?;
+            let kind = attr.kind();
+            let attached = attr.syntax().parent()?;
+            let is_trailing_outer_attr = kind != AttrKind::Inner
+                && non_trivia_sibling(attr.syntax().clone().into(), syntax::Direction::Next)
+                    .is_none();
+            let annotated_item_kind =
+                if is_trailing_outer_attr { None } else { Some(attached.kind()) };
+            Some(PathKind::Attr { attr_ctx: AttrCtx { kind, annotated_item_kind } })
+        };
+
         // Infer the path kind
         let parent = path.syntax().parent()?;
         let kind = match_ast! {
-                match parent {
-                    ast::PathType(it) => make_path_kind_type(it.into()),
-                    ast::PathExpr(it) => {
-                        if let Some(p) = it.syntax().parent() {
-                            if ast::ExprStmt::can_cast(p.kind()) {
-                                if let Some(kind) = inbetween_body_and_decl_check(p) {
-                                    return Some(make_res(NameRefKind::Keyword(kind)));
-                                }
+            match parent {
+                ast::PathType(it) => make_path_kind_type(it.into()),
+                ast::PathExpr(it) => {
+                    if let Some(p) = it.syntax().parent() {
+                        if ast::ExprStmt::can_cast(p.kind()) {
+                            if let Some(kind) = inbetween_body_and_decl_check(p) {
+                                return Some(make_res(NameRefKind::Keyword(kind)));
                             }
                         }
+                    }
 
-                        path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind()));
+                    path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind()));
 
-                        make_path_kind_expr(it.into())
-                    },
-                    ast::TupleStructPat(it) => {
-                        path_ctx.has_call_parens = true;
-                        PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
-                    },
-                    ast::RecordPat(it) => {
-                        path_ctx.has_call_parens = true;
-                        PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
-                    },
-                    ast::PathPat(it) => {
-                        PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
-                    },
-                    ast::MacroCall(it) => {
-                        // A macro call in this position is usually a result of parsing recovery, so check that
-                        if let Some(kind) = inbetween_body_and_decl_check(it.syntax().clone()) {
-                            return Some(make_res(NameRefKind::Keyword(kind)));
-                        }
+                    make_path_kind_expr(it.into())
+                },
+                ast::TupleStructPat(it) => {
+                    path_ctx.has_call_parens = true;
+                    PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
+                },
+                ast::RecordPat(it) => {
+                    path_ctx.has_call_parens = true;
+                    PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
+                },
+                ast::PathPat(it) => {
+                    PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
+                },
+                ast::MacroCall(it) => {
+                    // A macro call in this position is usually a result of parsing recovery, so check that
+                    if let Some(kind) = inbetween_body_and_decl_check(it.syntax().clone()) {
+                        return Some(make_res(NameRefKind::Keyword(kind)));
+                    }
 
-                        path_ctx.has_macro_bang = it.excl_token().is_some();
-                        let parent = it.syntax().parent()?;
-                        // Any path in an item list will be treated as a macro call by the parser
-                        match_ast! {
-                            match parent {
-                                ast::MacroExpr(expr) => make_path_kind_expr(expr.into()),
-                                ast::MacroPat(it) => PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())},
-                                ast::MacroType(ty) => make_path_kind_type(ty.into()),
-                                ast::ItemList(_) => PathKind::Item { kind: ItemListKind::Module },
-                                ast::AssocItemList(_) => PathKind::Item { kind: match parent.parent() {
-                                    Some(it) => match_ast! {
-                                        match it {
-                                            ast::Trait(_) => ItemListKind::Trait,
-                                            ast::Impl(it) => if it.trait_().is_some() {
-                                                ItemListKind::TraitImpl(find_node_in_file_compensated(sema, original_file, &it))
-                                            } else {
-                                                ItemListKind::Impl
-                                            },
-                                            _ => return None
-                                        }
-                                    },
-                                    None => return None,
-                                } },
-                                ast::ExternItemList(_) => PathKind::Item { kind: ItemListKind::ExternBlock },
-                                ast::SourceFile(_) => PathKind::Item { kind: ItemListKind::SourceFile },
-                                _ => return None,
-                            }
-                        }
-                    },
-                    ast::Meta(meta) => {
-                        let attr = meta.parent_attr()?;
-                        let kind = attr.kind();
-                        let attached = attr.syntax().parent()?;
-                        let is_trailing_outer_attr = kind != AttrKind::Inner
-                            && non_trivia_sibling(attr.syntax().clone().into(), syntax::Direction::Next).is_none();
-                        let annotated_item_kind = if is_trailing_outer_attr {
-                            None
-                        } else {
-                            Some(attached.kind())
-                        };
-                        PathKind::Attr {
-                            attr_ctx: AttrCtx {
-                                kind,
-                                annotated_item_kind,
-                            }
+                    kind_macro_call(it)?
+                },
+                ast::Meta(meta) => make_path_kind_attr(meta)?,
+                ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() },
+                ast::UseTree(_) => PathKind::Use,
+                // completing inside a qualifier
+                ast::Path(parent) => {
+                    path_ctx.parent = Some(parent.clone());
+                    let parent = iter::successors(Some(parent), |it| it.parent_path()).last()?.syntax().parent()?;
+                    match_ast! {
+                        match parent {
+                            ast::PathType(it) => make_path_kind_type(it.into()),
+                            ast::PathExpr(it) => {
+                                path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind()));
+
+                                make_path_kind_expr(it.into())
+                            },
+                            ast::TupleStructPat(it) => {
+                                path_ctx.has_call_parens = true;
+                                PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
+                            },
+                            ast::RecordPat(it) => {
+                                path_ctx.has_call_parens = true;
+                                PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
+                            },
+                            ast::PathPat(it) => {
+                                PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
+                            },
+                            ast::MacroCall(it) => {
+                                kind_macro_call(it)?
+                            },
+                            ast::Meta(meta) => make_path_kind_attr(meta)?,
+                            ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() },
+                            ast::UseTree(_) => PathKind::Use,
+                            ast::RecordExpr(it) => make_path_kind_expr(it.into()),
+                            _ => return None,
                         }
-                    },
-                    ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() },
-                    ast::UseTree(_) => PathKind::Use,
-                    _ => return None,
-
+                    }
+                },
+                ast::RecordExpr(it) => make_path_kind_expr(it.into()),
+                _ => return None,
             }
         };
 
@@ -884,49 +953,53 @@ fn classify_name_ref(
         path_ctx.has_type_args = segment.generic_arg_list().is_some();
 
         // calculate the qualifier context
-        if let Some((path, use_tree_parent)) = path_or_use_tree_qualifier(&path) {
+        if let Some((qualifier, use_tree_parent)) = path_or_use_tree_qualifier(&path) {
             path_ctx.use_tree_parent = use_tree_parent;
             if !use_tree_parent && segment.coloncolon_token().is_some() {
                 path_ctx.qualified = Qualified::Absolute;
             } else {
-                let path = path
+                let qualifier = qualifier
                     .segment()
                     .and_then(|it| find_node_in_file(original_file, &it))
                     .map(|it| it.parent_path());
-                if let Some(path) = path {
-                    // `<_>::$0`
-                    let is_infer_qualifier = path.qualifier().is_none()
-                        && matches!(
-                            path.segment().and_then(|it| it.kind()),
-                            Some(ast::PathSegmentKind::Type {
-                                type_ref: Some(ast::Type::InferType(_)),
-                                trait_ref: None,
-                            })
-                        );
+                if let Some(qualifier) = qualifier {
+                    let type_anchor = match qualifier.segment().and_then(|it| it.kind()) {
+                        Some(ast::PathSegmentKind::Type {
+                            type_ref: Some(type_ref),
+                            trait_ref,
+                        }) if qualifier.qualifier().is_none() => Some((type_ref, trait_ref)),
+                        _ => None,
+                    };
 
-                    path_ctx.qualified = if is_infer_qualifier {
-                        Qualified::Infer
+                    path_ctx.qualified = if let Some((ty, trait_ref)) = type_anchor {
+                        let ty = match ty {
+                            ast::Type::InferType(_) => None,
+                            ty => sema.resolve_type(&ty),
+                        };
+                        let trait_ = trait_ref.and_then(|it| sema.resolve_trait(&it.path()?));
+                        Qualified::TypeAnchor { ty, trait_ }
                     } else {
-                        let res = sema.resolve_path(&path);
+                        let res = sema.resolve_path(&qualifier);
 
                         // For understanding how and why super_chain_len is calculated the way it
                         // is check the documentation at it's definition
                         let mut segment_count = 0;
-                        let super_count = iter::successors(Some(path.clone()), |p| p.qualifier())
-                            .take_while(|p| {
-                                p.segment()
-                                    .and_then(|s| {
-                                        segment_count += 1;
-                                        s.super_token()
-                                    })
-                                    .is_some()
-                            })
-                            .count();
+                        let super_count =
+                            iter::successors(Some(qualifier.clone()), |p| p.qualifier())
+                                .take_while(|p| {
+                                    p.segment()
+                                        .and_then(|s| {
+                                            segment_count += 1;
+                                            s.super_token()
+                                        })
+                                        .is_some()
+                                })
+                                .count();
 
                         let super_chain_len =
                             if segment_count > super_count { None } else { Some(super_count) };
 
-                        Qualified::With { path, resolution: res, super_chain_len }
+                        Qualified::With { path: qualifier, resolution: res, super_chain_len }
                     }
                 };
             }
@@ -1141,19 +1214,6 @@ fn path_or_use_tree_qualifier(path: &ast::Path) -> Option<(ast::Path, bool)> {
     Some((use_tree.path()?, true))
 }
 
-fn has_ref(token: &SyntaxToken) -> bool {
-    let mut token = token.clone();
-    for skip in [SyntaxKind::IDENT, SyntaxKind::WHITESPACE, T![mut]] {
-        if token.kind() == skip {
-            token = match token.prev_token() {
-                Some(it) => it,
-                None => return false,
-            }
-        }
-    }
-    token.kind() == T![&]
-}
-
 pub(crate) fn is_in_token_of_for_loop(element: SyntaxElement) -> bool {
     // oh my ...
     (|| {
index c5557bdafb339e1abc1e08a2705d2d6ec2f4b17b..50845b3881f433953014dfa47d3ec00261806bf7 100644 (file)
@@ -391,3 +391,23 @@ fn foo($0: Foo) {}
         expect![[r#"ty: ?, name: ?"#]],
     );
 }
+
+#[test]
+fn expected_type_ref_prefix_on_field() {
+    check_expected_type_and_name(
+        r#"
+fn foo(_: &mut i32) {}
+struct S {
+    field: i32,
+}
+
+fn main() {
+    let s = S {
+        field: 100,
+    };
+    foo(&mut s.f$0);
+}
+"#,
+        expect!["ty: i32, name: ?"],
+    );
+}
index 9b25964a6086e704e0c4ca5ef5676cf1f985127c..946134b0ff95db78cb4682f847c6e4131dbf3fd4 100644 (file)
@@ -1271,8 +1271,8 @@ fn main() {
                 st S []
                 st &mut S [type]
                 st S []
-                fn main() []
                 fn foo(…) []
+                fn main() []
             "#]],
         );
         check_relevance(
@@ -1288,8 +1288,8 @@ fn main() {
                 lc s [type+name+local]
                 st S [type]
                 st S []
-                fn main() []
                 fn foo(…) []
+                fn main() []
             "#]],
         );
         check_relevance(
@@ -1305,8 +1305,8 @@ fn main() {
                 lc ssss [type+local]
                 st S [type]
                 st S []
-                fn main() []
                 fn foo(…) []
+                fn main() []
             "#]],
         );
     }
@@ -1342,12 +1342,11 @@ fn main() {
                 lc &t [type+local]
                 st S []
                 st &S [type]
-                st T []
                 st S []
-                fn main() []
+                st T []
                 fn foo(…) []
+                fn main() []
                 md core []
-                tt Sized []
             "#]],
         )
     }
@@ -1389,12 +1388,11 @@ fn main() {
                 lc &mut t [type+local]
                 st S []
                 st &mut S [type]
-                st T []
                 st S []
-                fn main() []
+                st T []
                 fn foo(…) []
+                fn main() []
                 md core []
-                tt Sized []
             "#]],
         )
     }
@@ -1485,14 +1483,13 @@ fn main() {
             expect![[r#"
                 st S []
                 st &S [type]
-                st T []
                 st S []
-                fn main() []
+                st T []
                 fn bar() []
                 fn &bar() [type]
                 fn foo(…) []
+                fn main() []
                 md core []
-                tt Sized []
             "#]],
         )
     }
@@ -1636,8 +1633,8 @@ fn foo() {
                 ev Foo::B [type_could_unify]
                 fn foo() []
                 en Foo []
-                fn baz() []
                 fn bar() []
+                fn baz() []
             "#]],
         );
     }
@@ -1727,9 +1724,9 @@ fn f() {
 }
 "#,
             expect![[r#"
-                md std []
                 st Buffer []
                 fn f() []
+                md std []
                 tt BufRead (use std::io::BufRead) [requires_import]
                 st BufReader (use std::io::BufReader) [requires_import]
                 st BufWriter (use std::io::BufWriter) [requires_import]
index 241de0a1834a0c1759fd4cd280df61ce94475fe3..4b5535718c5dfd4027df9e1d8132db83dad9ec54 100644 (file)
@@ -85,7 +85,9 @@ fn render(
                 item.ref_match(ref_match, path_ctx.path.syntax().text_range().start());
             }
             FuncKind::Method(DotAccess { receiver: Some(receiver), .. }, _) => {
-                item.ref_match(ref_match, receiver.syntax().text_range().start());
+                if let Some(original_expr) = completion.sema.original_ast_node(receiver.clone()) {
+                    item.ref_match(ref_match, original_expr.syntax().text_range().start());
+                }
             }
             _ => (),
         }
index 03db08a911e92afc8c7abd89603fb3bde9257ff9..34a384f2f7ae8cabdffbdc986101c5f71bed1936 100644 (file)
@@ -6,7 +6,7 @@
 use syntax::SmolStr;
 
 use crate::{
-    context::{ParamContext, ParamKind, PatternContext},
+    context::{ParamContext, ParamKind, PathCompletionCtx, PatternContext},
     render::{
         variant::{format_literal_label, visible_fields},
         RenderContext,
@@ -42,6 +42,7 @@ pub(crate) fn render_struct_pat(
 pub(crate) fn render_variant_pat(
     ctx: RenderContext<'_>,
     pattern_ctx: &PatternContext,
+    path_ctx: Option<&PathCompletionCtx>,
     variant: hir::Variant,
     local_name: Option<Name>,
     path: Option<&hir::ModPath>,
@@ -58,9 +59,23 @@ pub(crate) fn render_variant_pat(
             (name.to_smol_str(), name.escaped().to_smol_str())
         }
     };
-    let kind = variant.kind(ctx.db());
-    let label = format_literal_label(name.as_str(), kind);
-    let pat = render_pat(&ctx, pattern_ctx, &escaped_name, kind, &visible_fields, fields_omitted)?;
+
+    let (label, pat) = match path_ctx {
+        Some(PathCompletionCtx { has_call_parens: true, .. }) => (name, escaped_name.to_string()),
+        _ => {
+            let kind = variant.kind(ctx.db());
+            let label = format_literal_label(name.as_str(), kind);
+            let pat = render_pat(
+                &ctx,
+                pattern_ctx,
+                &escaped_name,
+                kind,
+                &visible_fields,
+                fields_omitted,
+            )?;
+            (label, pat)
+        }
+    };
 
     Some(build_completion(ctx, label, pat, variant))
 }
index 4be6acbe8461eef57bb1ca6686ac4459ec4346fe..cf826648dcf7b92426d162055248a2f7248a91c3 100644 (file)
@@ -23,8 +23,6 @@
 mod use_tree;
 mod visibility;
 
-use std::mem;
-
 use hir::{db::DefDatabase, PrefixKind, Semantics};
 use ide_db::{
     base_db::{fixture::ChangeFixture, FileLoader, FilePosition},
@@ -107,12 +105,9 @@ fn completion_list_with_config(
 ) -> String {
     // filter out all but one builtintype completion for smaller test outputs
     let items = get_all_items(config, ra_fixture, trigger_character);
-    let mut bt_seen = false;
     let items = items
         .into_iter()
-        .filter(|it| {
-            it.kind() != CompletionItemKind::BuiltinType || !mem::replace(&mut bt_seen, true)
-        })
+        .filter(|it| it.kind() != CompletionItemKind::BuiltinType || it.label() == "u32")
         .filter(|it| include_keywords || it.kind() != CompletionItemKind::Keyword)
         .filter(|it| include_keywords || it.kind() != CompletionItemKind::Snippet)
         .sorted_by_key(|it| (it.kind(), it.label().to_owned(), it.detail().map(ToOwned::to_owned)))
index ce9d01d337bae55378f75eb02bd2b2ddaf7a7ee1..925081ebf66025552c5a5a1e03bbbf0c2e058176 100644 (file)
@@ -44,7 +44,6 @@ fn function()    fn()
             st Record
             st Tuple
             st Unit
-            tt Trait
             un Union
             ev TupleV(…)     TupleV(u32)
             bt u32
@@ -137,7 +136,6 @@ fn local_func() fn()
             st Record
             st Tuple
             st Unit
-            tt Trait
             tp TypeParam
             un Union
             ev TupleV(…)    TupleV(u32)
@@ -653,3 +651,22 @@ fn bar(…) fn(impl Trait<U>)
         "]],
     );
 }
+
+#[test]
+fn complete_record_expr_path() {
+    check(
+        r#"
+struct Zulu;
+impl Zulu {
+    fn test() -> Self { }
+}
+fn boi(val: Zulu) { }
+fn main() {
+    boi(Zulu:: $0 {});
+}
+"#,
+        expect![[r#"
+            fn test() fn() -> Zulu
+        "#]],
+    );
+}
index 877b5f216433171995b578ba6ae316a4075e831a..30ddbe2dc6f6010caca0c48d70e718a3178c1c90 100644 (file)
@@ -443,7 +443,7 @@ fn foo() {
 }
 "#,
         expect![[r#"
-            bn TupleVariant(…) TupleVariant($1)$0
+            bn TupleVariant TupleVariant
         "#]],
     );
     check_empty(
@@ -458,7 +458,7 @@ fn foo() {
 }
 "#,
         expect![[r#"
-            bn RecordVariant {…} RecordVariant { field$1 }$0
+            bn RecordVariant RecordVariant
         "#]],
     );
 }
index ec32602fa3c2f83f95ab6f8db5b193b966068ac7..f6accc68e5e80cec252e9c5c970ad819662ab81e 100644 (file)
@@ -167,7 +167,6 @@ fn main()               fn()
             st Foo
             st Foo {…}              Foo { foo1: u32, foo2: u32 }
             tt Default
-            tt Sized
             bt u32
             kw crate::
             kw self::
index ca779c2fc713e98f6022b85d1a35467579ba779e..033dc99c26cf0c09acfdb2efb52a073b95b2a2f2 100644 (file)
@@ -674,7 +674,60 @@ fn bar() -> Bar {
         expect![[r#"
                 fn foo() (as Foo) fn() -> Self
             "#]],
-    )
+    );
+}
+
+#[test]
+fn type_anchor_type() {
+    check(
+        r#"
+trait Foo {
+    fn foo() -> Self;
+}
+struct Bar;
+impl Bar {
+    fn bar() {}
+}
+impl Foo for Bar {
+    fn foo() -> {
+        Bar
+    }
+}
+fn bar() -> Bar {
+    <Bar>::$0
+}
+"#,
+        expect![[r#"
+            fn bar()          fn()
+            fn foo() (as Foo) fn() -> Self
+        "#]],
+    );
+}
+
+#[test]
+fn type_anchor_type_trait() {
+    check(
+        r#"
+trait Foo {
+    fn foo() -> Self;
+}
+struct Bar;
+impl Bar {
+    fn bar() {}
+}
+impl Foo for Bar {
+    fn foo() -> {
+        Bar
+    }
+}
+fn bar() -> Bar {
+    <Bar as Foo>::$0
+}
+"#,
+        expect![[r#"
+            fn foo() (as Foo) fn() -> Self
+        "#]],
+    );
 }
 
 #[test]
index 98b0e9c947a742c4fdc963fabc0d1c21665c646d..f8134c552f7563295d264cc0681bbc8af49e47f7 100644 (file)
@@ -45,7 +45,7 @@ pub fn apply_change(&mut self, change: Change) {
     // |===
     // | Editor  | Action Name
     //
-    // | VS Code | **Rust Analyzer: Memory Usage (Clears Database)**
+    // | VS Code | **rust-analyzer: Memory Usage (Clears Database)**
     // |===
     // image::https://user-images.githubusercontent.com/48062697/113065592-08559f00-91b1-11eb-8c96-64b88068ec02.gif[]
     pub fn per_query_memory_usage(&mut self) -> Vec<(String, Bytes)> {
index aeaca00ec65cc3aeb053cf2731ddfd26e877fccf..6c13c039723b297a2a5b22645893b2c4c4e09590 100644 (file)
@@ -127,10 +127,12 @@ pub fn name(&self, db: &RootDatabase) -> Option<Name> {
     }
 }
 
+// FIXME: IdentClass as a name no longer fits
 #[derive(Debug)]
 pub enum IdentClass {
     NameClass(NameClass),
     NameRefClass(NameRefClass),
+    Operator(OperatorClass),
 }
 
 impl IdentClass {
@@ -147,6 +149,11 @@ pub fn classify_node(
                         .map(IdentClass::NameClass)
                         .or_else(|| NameRefClass::classify_lifetime(sema, &lifetime).map(IdentClass::NameRefClass))
                 },
+                ast::AwaitExpr(await_expr) => OperatorClass::classify_await(sema, &await_expr).map(IdentClass::Operator),
+                ast::BinExpr(bin_expr) => OperatorClass::classify_bin(sema, &bin_expr).map(IdentClass::Operator),
+                ast::IndexExpr(index_expr) => OperatorClass::classify_index(sema, &index_expr).map(IdentClass::Operator),
+                ast::PrefixExpr(prefix_expr) => OperatorClass::classify_prefix(sema,&prefix_expr).map(IdentClass::Operator),
+                ast::TryExpr(try_expr) => OperatorClass::classify_try(sema,&try_expr).map(IdentClass::Operator),
                 _ => None,
             }
         }
@@ -184,6 +191,33 @@ pub fn definitions(self) -> ArrayVec<Definition, 2> {
                 res.push(Definition::Local(local_ref));
                 res.push(Definition::Field(field_ref));
             }
+            IdentClass::Operator(
+                OperatorClass::Await(func)
+                | OperatorClass::Prefix(func)
+                | OperatorClass::Bin(func)
+                | OperatorClass::Index(func)
+                | OperatorClass::Try(func),
+            ) => res.push(Definition::Function(func)),
+        }
+        res
+    }
+
+    pub fn definitions_no_ops(self) -> ArrayVec<Definition, 2> {
+        let mut res = ArrayVec::new();
+        match self {
+            IdentClass::NameClass(NameClass::Definition(it) | NameClass::ConstReference(it)) => {
+                res.push(it)
+            }
+            IdentClass::NameClass(NameClass::PatFieldShorthand { local_def, field_ref }) => {
+                res.push(Definition::Local(local_def));
+                res.push(Definition::Field(field_ref));
+            }
+            IdentClass::NameRefClass(NameRefClass::Definition(it)) => res.push(it),
+            IdentClass::NameRefClass(NameRefClass::FieldShorthand { local_ref, field_ref }) => {
+                res.push(Definition::Local(local_ref));
+                res.push(Definition::Field(field_ref));
+            }
+            IdentClass::Operator(_) => (),
         }
         res
     }
@@ -332,6 +366,52 @@ pub fn classify_lifetime(
     }
 }
 
+#[derive(Debug)]
+pub enum OperatorClass {
+    Await(Function),
+    Prefix(Function),
+    Index(Function),
+    Try(Function),
+    Bin(Function),
+}
+
+impl OperatorClass {
+    pub fn classify_await(
+        sema: &Semantics<'_, RootDatabase>,
+        await_expr: &ast::AwaitExpr,
+    ) -> Option<OperatorClass> {
+        sema.resolve_await_to_poll(await_expr).map(OperatorClass::Await)
+    }
+
+    pub fn classify_prefix(
+        sema: &Semantics<'_, RootDatabase>,
+        prefix_expr: &ast::PrefixExpr,
+    ) -> Option<OperatorClass> {
+        sema.resolve_prefix_expr(prefix_expr).map(OperatorClass::Prefix)
+    }
+
+    pub fn classify_try(
+        sema: &Semantics<'_, RootDatabase>,
+        try_expr: &ast::TryExpr,
+    ) -> Option<OperatorClass> {
+        sema.resolve_try_expr(try_expr).map(OperatorClass::Try)
+    }
+
+    pub fn classify_index(
+        sema: &Semantics<'_, RootDatabase>,
+        index_expr: &ast::IndexExpr,
+    ) -> Option<OperatorClass> {
+        sema.resolve_index_expr(index_expr).map(OperatorClass::Index)
+    }
+
+    pub fn classify_bin(
+        sema: &Semantics<'_, RootDatabase>,
+        bin_expr: &ast::BinExpr,
+    ) -> Option<OperatorClass> {
+        sema.resolve_bin_expr(bin_expr).map(OperatorClass::Bin)
+    }
+}
+
 /// This is similar to [`NameClass`], but works for [`ast::NameRef`] rather than
 /// for [`ast::Name`]. Similarly, what looks like a reference in syntax is a
 /// reference most of the time, but there are a couple of annoying exceptions.
index a5e24daa9fa01019de7deb33a62584007d2ce3f4..739e0ccb436dbeebad6112430c610ca79a93688e 100644 (file)
@@ -57,7 +57,7 @@
 // |===
 // | Editor  | Action Name
 //
-// | VS Code | **Rust Analyzer: Structural Search Replace**
+// | VS Code | **rust-analyzer: Structural Search Replace**
 // |===
 //
 // Also available as an assist, by writing a comment containing the structural
index a18a6bea979881e517ceee1f13d065919995d108..5a8cda8fb3dda19e0c4ea6c5c0f4b0fbc72073f9 100644 (file)
@@ -7,7 +7,7 @@
     search::FileReference,
     FxIndexMap, RootDatabase,
 };
-use syntax::{ast, AstNode, SyntaxKind::NAME, TextRange};
+use syntax::{ast, AstNode, SyntaxKind::IDENT, TextRange};
 
 use crate::{goto_definition, FilePosition, NavigationTarget, RangeInfo, TryToNav};
 
@@ -79,7 +79,7 @@ pub(crate) fn outgoing_calls(db: &RootDatabase, position: FilePosition) -> Optio
     let file = sema.parse(file_id);
     let file = file.syntax();
     let token = pick_best_token(file.token_at_offset(position.offset), |kind| match kind {
-        NAME => 1,
+        IDENT => 1,
         _ => 0,
     })?;
     let mut calls = CallLocations::default();
index efa8551a00d5a858200e71cebac860176a761a8e..93252339cd4a83885f6b26a54b30b3f0ecf65cb4 100644 (file)
@@ -19,7 +19,7 @@ pub struct ExpandedMacro {
 // |===
 // | Editor  | Action Name
 //
-// | VS Code | **Rust Analyzer: Expand macro recursively**
+// | VS Code | **rust-analyzer: Expand macro recursively**
 // |===
 //
 // image::https://user-images.githubusercontent.com/48062697/113020648-b3973180-917a-11eb-84a9-ecb921293dc5.gif[]
@@ -32,7 +32,7 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
         _ => 0,
     })?;
 
-    // due to how Rust Analyzer works internally, we need to special case derive attributes,
+    // due to how rust-analyzer works internally, we need to special case derive attributes,
     // otherwise they might not get found, e.g. here with the cursor at $0 `#[attr]` would expand:
     // ```
     // #[attr]
index d9c97751c95c319ef136b0852a8b7cfebdd6f460..b2123b9a87938545f4e9609e4e586289b8634aa9 100644 (file)
@@ -39,7 +39,11 @@ pub(crate) fn goto_definition(
             | T![super]
             | T![crate]
             | T![Self]
-            | COMMENT => 2,
+            | COMMENT => 4,
+            // index and prefix ops
+            T!['['] | T![']'] | T![?] | T![*] | T![-] | T![!] => 3,
+            kind if kind.is_keyword() => 2,
+            T!['('] | T![')'] => 2,
             kind if kind.is_trivia() => 0,
             _ => 1,
         })?;
@@ -1628,6 +1632,122 @@ fn foo() {
 }
 
 foo!(bar$0);
+"#,
+        );
+    }
+
+    #[test]
+    fn goto_await_poll() {
+        check(
+            r#"
+//- minicore: future
+
+struct MyFut;
+
+impl core::future::Future for MyFut {
+    type Output = ();
+
+    fn poll(
+     //^^^^
+        self: std::pin::Pin<&mut Self>,
+        cx: &mut std::task::Context<'_>
+    ) -> std::task::Poll<Self::Output>
+    {
+        ()
+    }
+}
+
+fn f() {
+    MyFut.await$0;
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn goto_try_op() {
+        check(
+            r#"
+//- minicore: try
+
+struct Struct;
+
+impl core::ops::Try for Struct {
+    fn branch(
+     //^^^^^^
+        self
+    ) {}
+}
+
+fn f() {
+    Struct?$0;
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn goto_index_op() {
+        check(
+            r#"
+//- minicore: index
+
+struct Struct;
+
+impl core::ops::Index<usize> for Struct {
+    fn index(
+     //^^^^^
+        self
+    ) {}
+}
+
+fn f() {
+    Struct[0]$0;
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn goto_prefix_op() {
+        check(
+            r#"
+//- minicore: deref
+
+struct Struct;
+
+impl core::ops::Deref for Struct {
+    fn deref(
+     //^^^^^
+        self
+    ) {}
+}
+
+fn f() {
+    $0*Struct;
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn goto_bin_op() {
+        check(
+            r#"
+//- minicore: add
+
+struct Struct;
+
+impl core::ops::Add for Struct {
+    fn add(
+     //^^^
+        self
+    ) {}
+}
+
+fn f() {
+    Struct +$0 Struct;
+}
 "#,
         );
     }
index 04b51c839407b67a376e16efad230cf268f99448..b3f711b6b88c4edd0b97403d85fc99b0857317a9 100644 (file)
@@ -30,7 +30,7 @@ pub(crate) fn goto_implementation(
 
     let original_token =
         pick_best_token(syntax.token_at_offset(position.offset), |kind| match kind {
-            IDENT | T![self] => 1,
+            IDENT | T![self] | INT_NUMBER => 1,
             _ => 0,
         })?;
     let range = original_token.text_range();
index f2d7029eab19556b42059cef7e3abb8bf3633302..f190da326e455fd8a6563df8ad19fd73d1aff90d 100644 (file)
@@ -333,7 +333,8 @@ fn cover_range(r0: Option<TextRange>, r1: Option<TextRange>) -> Option<TextRange
 fn find_defs(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> FxHashSet<Definition> {
     sema.descend_into_macros(token)
         .into_iter()
-        .filter_map(|token| IdentClass::classify_token(sema, &token).map(IdentClass::definitions))
+        .filter_map(|token| IdentClass::classify_token(sema, &token))
+        .map(IdentClass::definitions_no_ops)
         .flatten()
         .collect()
 }
index 59c97f2dcf966bff485bdd32b5b14cfeba614d60..3ada181f1ed2ba63a3e69d775af8a9bc3c35ab25 100644 (file)
@@ -9,7 +9,7 @@
 use hir::{HasSource, Semantics};
 use ide_db::{
     base_db::FileRange,
-    defs::{Definition, IdentClass},
+    defs::{Definition, IdentClass, OperatorClass},
     famous_defs::FamousDefs,
     helpers::pick_best_token,
     FxIndexSet, RootDatabase,
@@ -101,7 +101,10 @@ pub(crate) fn hover(
     let offset = range.start();
 
     let original_token = pick_best_token(file.token_at_offset(offset), |kind| match kind {
-        IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] | T![Self] => 3,
+        IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] | T![Self] => 4,
+        // index and prefix ops
+        T!['['] | T![']'] | T![?] | T![*] | T![-] | T![!] => 3,
+        kind if kind.is_keyword() => 2,
         T!['('] | T![')'] => 2,
         kind if kind.is_trivia() => 0,
         _ => 1,
@@ -136,6 +139,11 @@ pub(crate) fn hover(
         .filter_map(|token| {
             let node = token.parent()?;
             let class = IdentClass::classify_token(sema, token)?;
+            if let IdentClass::Operator(OperatorClass::Await(_)) = class {
+                // It's better for us to fall back to the keyword hover here,
+                // rendering poll is very confusing
+                return None;
+            }
             Some(class.definitions().into_iter().zip(iter::once(node).cycle()))
         })
         .flatten()
@@ -232,10 +240,12 @@ fn hover_type_fallback(
     token: &SyntaxToken,
     original_token: &SyntaxToken,
 ) -> Option<RangeInfo<HoverResult>> {
-    let node = token
-        .parent_ancestors()
-        .take_while(|it| !ast::Item::can_cast(it.kind()))
-        .find(|n| ast::Expr::can_cast(n.kind()) || ast::Pat::can_cast(n.kind()))?;
+    let node =
+        token.parent_ancestors().take_while(|it| !ast::Item::can_cast(it.kind())).find(|n| {
+            ast::Expr::can_cast(n.kind())
+                || ast::Pat::can_cast(n.kind())
+                || ast::Type::can_cast(n.kind())
+        })?;
 
     let expr_or_pat = match_ast! {
         match node {
index 867d1f54d4feb99257042408277287163ff093cd..c6274264b8f1a55770cd1a478bc8559a5c7ff9c3 100644 (file)
@@ -5051,3 +5051,37 @@ fn f() {
             ```"#]],
     );
 }
+
+#[test]
+fn hover_deref() {
+    check(
+        r#"
+//- minicore: deref
+
+struct Struct(usize);
+
+impl core::ops::Deref for Struct {
+    type Target = usize;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+fn f() {
+    $0*Struct(0);
+}
+"#,
+        expect![[r#"
+            ***
+
+            ```rust
+            test::Struct
+            ```
+
+            ```rust
+            fn deref(&self) -> &Self::Target
+            ```
+        "#]],
+    );
+}
index 5aae669aa4d6d1db97ddf26acdf823c215e6f2dc..ed19784d1fa49d11355835d94be8b83983f75792 100644 (file)
@@ -100,7 +100,7 @@ pub enum InlayTooltip {
 // |===
 // | Editor  | Action Name
 //
-// | VS Code | **Rust Analyzer: Toggle inlay hints*
+// | VS Code | **rust-analyzer: Toggle inlay hints*
 // |===
 //
 // image::https://user-images.githubusercontent.com/48062697/113020660-b5f98b80-917a-11eb-8d70-3be3fd558cdd.png[]
index 08621addeef4d821f44a04eabbae7e406dd4bebd..edc48e84d72528f7ce14d6db2b8f5dc533c9b8ff 100644 (file)
@@ -28,7 +28,7 @@ pub struct JoinLinesConfig {
 // |===
 // | Editor  | Action Name
 //
-// | VS Code | **Rust Analyzer: Join lines**
+// | VS Code | **rust-analyzer: Join lines**
 // |===
 //
 // image::https://user-images.githubusercontent.com/48062697/113020661-b6922200-917a-11eb-87c4-b75acc028f11.gif[]
index da70cecdd8e11b437134cc42bb0235215d017bff..6e8a6d020cc7888db3ede65c8e2c5b91fc165b58 100644 (file)
@@ -12,7 +12,7 @@
 // |===
 // | Editor  | Action Name
 //
-// | VS Code | **Rust Analyzer: Find matching brace**
+// | VS Code | **rust-analyzer: Find matching brace**
 // |===
 //
 // image::https://user-images.githubusercontent.com/48062697/113065573-04298180-91b1-11eb-8dec-d4e2a202f304.gif[]
index 6bab9fa1ebbb89d24f027426b99997182462812b..4f758967b46194538d41c753da10372f997ba7de 100644 (file)
@@ -90,7 +90,7 @@ pub(crate) fn moniker(
         .descend_into_macros(original_token.clone())
         .into_iter()
         .filter_map(|token| {
-            IdentClass::classify_token(sema, &token).map(IdentClass::definitions).map(|it| {
+            IdentClass::classify_token(sema, &token).map(IdentClass::definitions_no_ops).map(|it| {
                 it.into_iter().flat_map(|def| def_to_moniker(sema.db, def, current_crate))
             })
         })
index 02e9fb8b5e28898c234ecc97791363188d691c2a..ffc4bdd7da33f9453e232518170c2000e06f7e0a 100644 (file)
@@ -19,8 +19,8 @@ pub enum Direction {
 // |===
 // | Editor  | Action Name
 //
-// | VS Code | **Rust Analyzer: Move item up**
-// | VS Code | **Rust Analyzer: Move item down**
+// | VS Code | **rust-analyzer: Move item up**
+// | VS Code | **rust-analyzer: Move item down**
 // |===
 //
 // image::https://user-images.githubusercontent.com/48062697/113065576-04298180-91b1-11eb-91ce-4505e99ed598.gif[]
index 9b1f480446aa95231e1971f2d3d7ff1580c11b32..8f3cc86873f5ed06d5325274079e69bfa22f4fca 100644 (file)
@@ -18,7 +18,7 @@
 // |===
 // | Editor  | Action Name
 //
-// | VS Code | **Rust Analyzer: Locate parent module**
+// | VS Code | **rust-analyzer: Locate parent module**
 // |===
 //
 // image::https://user-images.githubusercontent.com/48062697/113065580-04c21800-91b1-11eb-9a32-00086161c0bd.gif[]
index bec770ed99f1661b71c8a9ce4f7b24a1dd1218fc..b0853b10fde2f818d66f0c97d7c83e01ba2e906b 100644 (file)
@@ -116,7 +116,7 @@ fn test_kind(&self) -> RunnableTestKind {
 // |===
 // | Editor  | Action Name
 //
-// | VS Code | **Rust Analyzer: Run**
+// | VS Code | **rust-analyzer: Run**
 // |===
 // image::https://user-images.githubusercontent.com/48062697/113065583-055aae80-91b1-11eb-958f-d67efcaf6a2f.gif[]
 pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> {
@@ -202,7 +202,7 @@ pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> {
 // |===
 // | Editor  | Action Name
 //
-// | VS Code | **Rust Analyzer: Peek related tests**
+// | VS Code | **rust-analyzer: Peek related tests**
 // |===
 pub(crate) fn related_tests(
     db: &RootDatabase,
@@ -373,11 +373,13 @@ pub(crate) fn runnable_impl(
     let adt_name = ty.as_adt()?.name(sema.db);
     let mut ty_args = ty.type_arguments().peekable();
     let params = if ty_args.peek().is_some() {
-        format!("<{}>", ty_args.format_with(", ", |ty, cb| cb(&ty.display(sema.db))))
+        format!("<{}>", ty_args.format_with(",", |ty, cb| cb(&ty.display(sema.db))))
     } else {
         String::new()
     };
-    let test_id = TestId::Path(format!("{}{}", adt_name, params));
+    let mut test_id = format!("{}{}", adt_name, params);
+    test_id.retain(|c| c != ' ');
+    let test_id = TestId::Path(test_id);
 
     Some(Runnable { use_name_in_title: false, nav, kind: RunnableKind::DocTest { test_id }, cfg })
 }
@@ -441,10 +443,11 @@ fn module_def_doctest(db: &RootDatabase, def: Definition) -> Option<Runnable> {
                         format_to!(
                             path,
                             "<{}>",
-                            ty_args.format_with(", ", |ty, cb| cb(&ty.display(db)))
+                            ty_args.format_with(",", |ty, cb| cb(&ty.display(db)))
                         );
                     }
                     format_to!(path, "::{}", def_name);
+                    path.retain(|c| c != ' ');
                     return Some(path);
                 }
             }
@@ -2067,13 +2070,23 @@ fn doc_test_type_params() {
 $0
 struct Foo<T, U>;
 
+/// ```
+/// ```
 impl<T, U> Foo<T, U> {
     /// ```rust
     /// ````
     fn t() {}
 }
+
+/// ```
+/// ```
+impl Foo<Foo<(), ()>, ()> {
+    /// ```
+    /// ```
+    fn t() {}
+}
 "#,
-            &[DocTest],
+            &[DocTest, DocTest, DocTest, DocTest],
             expect![[r#"
                 [
                     Runnable {
@@ -2082,12 +2095,64 @@ fn t() {}
                             file_id: FileId(
                                 0,
                             ),
-                            full_range: 47..85,
+                            full_range: 20..103,
+                            focus_range: 47..56,
+                            name: "impl",
+                            kind: Impl,
+                        },
+                        kind: DocTest {
+                            test_id: Path(
+                                "Foo<T,U>",
+                            ),
+                        },
+                        cfg: None,
+                    },
+                    Runnable {
+                        use_name_in_title: false,
+                        nav: NavigationTarget {
+                            file_id: FileId(
+                                0,
+                            ),
+                            full_range: 63..101,
+                            name: "t",
+                        },
+                        kind: DocTest {
+                            test_id: Path(
+                                "Foo<T,U>::t",
+                            ),
+                        },
+                        cfg: None,
+                    },
+                    Runnable {
+                        use_name_in_title: false,
+                        nav: NavigationTarget {
+                            file_id: FileId(
+                                0,
+                            ),
+                            full_range: 105..188,
+                            focus_range: 126..146,
+                            name: "impl",
+                            kind: Impl,
+                        },
+                        kind: DocTest {
+                            test_id: Path(
+                                "Foo<Foo<(),()>,()>",
+                            ),
+                        },
+                        cfg: None,
+                    },
+                    Runnable {
+                        use_name_in_title: false,
+                        nav: NavigationTarget {
+                            file_id: FileId(
+                                0,
+                            ),
+                            full_range: 153..186,
                             name: "t",
                         },
                         kind: DocTest {
                             test_id: Path(
-                                "Foo<T, U>::t",
+                                "Foo<Foo<(),()>,()>::t",
                             ),
                         },
                         cfg: None,
index 15cb89dcce95f11b42882b07c37b5b4c68259830..2d86627643d7c8d66c2c84adbc133d0a9c01d813 100644 (file)
@@ -12,7 +12,7 @@
 // |===
 // | Editor  | Action Name
 //
-// | VS Code | **Rust Analyzer: Shuffle Crate Graph**
+// | VS Code | **rust-analyzer: Shuffle Crate Graph**
 // |===
 pub(crate) fn shuffle_crate_graph(db: &mut RootDatabase) {
     let crate_graph = db.crate_graph();
index d74b640415c76e83e4b8a9c0a10877453bfddf4a..cc79ee55b7dac2be43bf41ae084af390ae198b0e 100644 (file)
@@ -204,7 +204,7 @@ pub fn compute(analysis: &Analysis) -> StaticIndex<'_> {
 
 fn get_definition(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> Option<Definition> {
     for token in sema.descend_into_macros(token) {
-        let def = IdentClass::classify_token(sema, &token).map(IdentClass::definitions);
+        let def = IdentClass::classify_token(sema, &token).map(IdentClass::definitions_no_ops);
         if let Some(&[x]) = def.as_deref() {
             return Some(x);
         } else {
index 3191870eb5e8f888f85f4c66170e57d02d2a6b2e..32e39f82a0e9f2b6ef870bca1371db19cf319d02 100644 (file)
@@ -29,7 +29,7 @@ fn macro_syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats {
 // |===
 // | Editor  | Action Name
 //
-// | VS Code | **Rust Analyzer: Status**
+// | VS Code | **rust-analyzer: Status**
 // |===
 // image::https://user-images.githubusercontent.com/48062697/113065584-05f34500-91b1-11eb-98cc-5c196f76be7f.gif[]
 pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String {
index d013d6f4b19ff95b0ef03e178ed3a194983ca09a..3fb49b45d9888ebb7fcac3d4e4431b3f9f596e75 100644 (file)
@@ -13,7 +13,7 @@
 #[cfg(test)]
 mod tests;
 
-use hir::{InFile, Name, Semantics};
+use hir::{Name, Semantics};
 use ide_db::{FxHashMap, RootDatabase};
 use syntax::{
     ast, AstNode, AstToken, NodeOrToken, SyntaxKind::*, SyntaxNode, TextRange, WalkEvent, T,
@@ -325,7 +325,7 @@ fn item(&self) -> &ast::Item {
             Leave(NodeOrToken::Node(node)) => {
                 // Doc comment highlighting injection, we do this when leaving the node
                 // so that we overwrite the highlighting of the doc comment itself.
-                inject::doc_comment(hl, sema, InFile::new(file_id.into(), &node));
+                inject::doc_comment(hl, sema, file_id, &node);
                 continue;
             }
         };
index f779a985a99ae60eb9289044d604b64775532a35..f376f9fda7a57799c0be9b774a81508a065d2893 100644 (file)
@@ -5,7 +5,8 @@
 use either::Either;
 use hir::{InFile, Semantics};
 use ide_db::{
-    active_parameter::ActiveParameter, defs::Definition, rust_doc::is_rust_fence, SymbolKind,
+    active_parameter::ActiveParameter, base_db::FileId, defs::Definition, rust_doc::is_rust_fence,
+    SymbolKind,
 };
 use syntax::{
     ast::{self, AstNode, IsString, QuoteOffsets},
@@ -81,16 +82,18 @@ pub(super) fn ra_fixture(
 const RUSTDOC_FENCE_LENGTH: usize = 3;
 const RUSTDOC_FENCES: [&str; 2] = ["```", "~~~"];
 
-/// Injection of syntax highlighting of doctests.
+/// Injection of syntax highlighting of doctests and intra doc links.
 pub(super) fn doc_comment(
     hl: &mut Highlights,
     sema: &Semantics<'_, RootDatabase>,
-    InFile { file_id: src_file_id, value: node }: InFile<&SyntaxNode>,
+    src_file_id: FileId,
+    node: &SyntaxNode,
 ) {
     let (attributes, def) = match doc_attributes(sema, node) {
         Some(it) => it,
         None => return,
     };
+    let src_file_id = src_file_id.into();
 
     // Extract intra-doc links and emit highlights for them.
     if let Some((docs, doc_mapping)) = attributes.docs_with_rangemap(sema.db) {
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_inline.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_inline.html
new file mode 100644 (file)
index 0000000..8a1d698
--- /dev/null
@@ -0,0 +1,51 @@
+
+<style>
+body                { margin: 0; }
+pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
+
+.lifetime           { color: #DFAF8F; font-style: italic; }
+.label              { color: #DFAF8F; font-style: italic; }
+.comment            { color: #7F9F7F; }
+.documentation      { color: #629755; }
+.intra_doc_link     { font-style: italic; }
+.injected           { opacity: 0.65 ; }
+.struct, .enum      { color: #7CB8BB; }
+.enum_variant       { color: #BDE0F3; }
+.string_literal     { color: #CC9393; }
+.field              { color: #94BFF3; }
+.function           { color: #93E0E3; }
+.function.unsafe    { color: #BC8383; }
+.trait.unsafe       { color: #BC8383; }
+.operator.unsafe    { color: #BC8383; }
+.mutable.unsafe     { color: #BC8383; text-decoration: underline; }
+.keyword.unsafe     { color: #BC8383; font-weight: bold; }
+.macro.unsafe       { color: #BC8383; }
+.parameter          { color: #94BFF3; }
+.text               { color: #DCDCCC; }
+.type               { color: #7CB8BB; }
+.builtin_type       { color: #8CD0D3; }
+.type_param         { color: #DFAF8F; }
+.attribute          { color: #94BFF3; }
+.numeric_literal    { color: #BFEBBF; }
+.bool_literal       { color: #BFE6EB; }
+.macro              { color: #94BFF3; }
+.derive             { color: #94BFF3; font-style: italic; }
+.module             { color: #AFD8AF; }
+.value_param        { color: #DCDCCC; }
+.variable           { color: #DCDCCC; }
+.format_specifier   { color: #CC696B; }
+.mutable            { text-decoration: underline; }
+.escape_sequence    { color: #94BFF3; }
+.keyword            { color: #F0DFAF; font-weight: bold; }
+.control            { font-style: italic; }
+.reference          { font-style: italic; font-weight: bold; }
+
+.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
+</style>
+<pre><code><span class="comment documentation">//! </span><span class="struct documentation injected intra_doc_link">[Struct]</span>
+<span class="comment documentation">//! This is an intra doc injection test for modules</span>
+<span class="comment documentation">//! </span><span class="struct documentation injected intra_doc_link">[Struct]</span>
+<span class="comment documentation">//! This is an intra doc injection test for modules</span>
+
+<span class="keyword">pub</span> <span class="keyword">struct</span> <span class="struct declaration public">Struct</span><span class="semicolon">;</span>
+</code></pre>
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_outline.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_outline.html
new file mode 100644 (file)
index 0000000..c4c3e3d
--- /dev/null
@@ -0,0 +1,50 @@
+
+<style>
+body                { margin: 0; }
+pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
+
+.lifetime           { color: #DFAF8F; font-style: italic; }
+.label              { color: #DFAF8F; font-style: italic; }
+.comment            { color: #7F9F7F; }
+.documentation      { color: #629755; }
+.intra_doc_link     { font-style: italic; }
+.injected           { opacity: 0.65 ; }
+.struct, .enum      { color: #7CB8BB; }
+.enum_variant       { color: #BDE0F3; }
+.string_literal     { color: #CC9393; }
+.field              { color: #94BFF3; }
+.function           { color: #93E0E3; }
+.function.unsafe    { color: #BC8383; }
+.trait.unsafe       { color: #BC8383; }
+.operator.unsafe    { color: #BC8383; }
+.mutable.unsafe     { color: #BC8383; text-decoration: underline; }
+.keyword.unsafe     { color: #BC8383; font-weight: bold; }
+.macro.unsafe       { color: #BC8383; }
+.parameter          { color: #94BFF3; }
+.text               { color: #DCDCCC; }
+.type               { color: #7CB8BB; }
+.builtin_type       { color: #8CD0D3; }
+.type_param         { color: #DFAF8F; }
+.attribute          { color: #94BFF3; }
+.numeric_literal    { color: #BFEBBF; }
+.bool_literal       { color: #BFE6EB; }
+.macro              { color: #94BFF3; }
+.derive             { color: #94BFF3; font-style: italic; }
+.module             { color: #AFD8AF; }
+.value_param        { color: #DCDCCC; }
+.variable           { color: #DCDCCC; }
+.format_specifier   { color: #CC696B; }
+.mutable            { text-decoration: underline; }
+.escape_sequence    { color: #94BFF3; }
+.keyword            { color: #F0DFAF; font-weight: bold; }
+.control            { font-style: italic; }
+.reference          { font-style: italic; font-weight: bold; }
+
+.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
+</style>
+<pre><code><span class="comment documentation">/// </span><span class="struct documentation injected intra_doc_link">[crate::foo::Struct]</span>
+<span class="comment documentation">/// This is an intra doc injection test for modules</span>
+<span class="comment documentation">/// </span><span class="struct documentation injected intra_doc_link">[crate::foo::Struct]</span>
+<span class="comment documentation">/// This is an intra doc injection test for modules</span>
+<span class="keyword">mod</span> <span class="module declaration">foo</span><span class="semicolon">;</span>
+</code></pre>
\ No newline at end of file
index 6ba6153178da9ce5aceedffe45add51ebc615621..382735cb368df3cac89ca0bb72559896b944f28c 100644 (file)
@@ -915,6 +915,52 @@ fn main() {
 }
 
 #[test]
+fn test_mod_hl_injection() {
+    check_highlighting(
+        r##"
+//- /foo.rs
+//! [Struct]
+//! This is an intra doc injection test for modules
+//! [Struct]
+//! This is an intra doc injection test for modules
+
+pub struct Struct;
+//- /lib.rs crate:foo
+/// [crate::foo::Struct]
+/// This is an intra doc injection test for modules
+/// [crate::foo::Struct]
+/// This is an intra doc injection test for modules
+mod foo;
+"##,
+        expect_file!["./test_data/highlight_module_docs_inline.html"],
+        false,
+    );
+    check_highlighting(
+        r##"
+//- /lib.rs crate:foo
+/// [crate::foo::Struct]
+/// This is an intra doc injection test for modules
+/// [crate::foo::Struct]
+/// This is an intra doc injection test for modules
+mod foo;
+//- /foo.rs
+//! [Struct]
+//! This is an intra doc injection test for modules
+//! [Struct]
+//! This is an intra doc injection test for modules
+
+pub struct Struct;
+"##,
+        expect_file!["./test_data/highlight_module_docs_outline.html"],
+        false,
+    );
+}
+
+#[test]
+#[cfg_attr(
+    not(all(unix, target_pointer_width = "64")),
+    ignore = "depends on `DefaultHasher` outputs"
+)]
 fn test_rainbow_highlighting() {
     check_highlighting(
         r#"
index 9003e7cd34d091b1044313212f539d29a9f0f175..4256fea0f81e45679ff6567fda769c93c92578eb 100644 (file)
@@ -12,7 +12,7 @@
 // |===
 // | Editor  | Action Name
 //
-// | VS Code | **Rust Analyzer: Show Syntax Tree**
+// | VS Code | **rust-analyzer: Show Syntax Tree**
 // |===
 // image::https://user-images.githubusercontent.com/48062697/113065586-068bdb80-91b1-11eb-9507-fee67f9f45a0.gif[]
 pub(crate) fn syntax_tree(
index 51291a64532fee5791fb0d56d550ad0a78c9299c..bf7b7efe28228885712908e998c30b31135573d5 100644 (file)
@@ -16,7 +16,7 @@
 // |===
 // | Editor  | Action Name
 //
-// | VS Code | **Rust Analyzer: View Crate Graph**
+// | VS Code | **rust-analyzer: View Crate Graph**
 // |===
 pub(crate) fn view_crate_graph(db: &RootDatabase, full: bool) -> Result<String, String> {
     let crate_graph = db.crate_graph();
index 7312afe5310b414753f1db2f37510d6486361f9f..bf0835ed7e0d3a1f2a5f675e2f67754483e6d5ab 100644 (file)
@@ -8,7 +8,7 @@
 // |===
 // | Editor  | Action Name
 //
-// | VS Code | **Rust Analyzer: View Hir**
+// | VS Code | **rust-analyzer: View Hir**
 // |===
 // image::https://user-images.githubusercontent.com/48062697/113065588-068bdb80-91b1-11eb-9a78-0b4ef1e972fb.gif[]
 pub(crate) fn view_hir(db: &RootDatabase, position: FilePosition) -> String {
index 3dc03085d651c9f0f2727341f29c8ade90274430..9c1f93356ee2d0637733ae7f035f230313b0fa76 100644 (file)
@@ -9,7 +9,7 @@
 // |===
 // | Editor  | Action Name
 //
-// | VS Code | **Rust Analyzer: Debug ItemTree**
+// | VS Code | **rust-analyzer: Debug ItemTree**
 // |===
 pub(crate) fn view_item_tree(db: &RootDatabase, file_id: FileId) -> String {
     db.file_item_tree(file_id.into()).pretty_print()
index 3c1da80edb98b08d421eb186d73bd4a0a99b163c..d6a706a7cd73a82efc2dad0b97adc7ae4e9623ce 100644 (file)
@@ -2,12 +2,13 @@
 
 #![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
 
+#[cfg(feature = "tracking")]
 use std::sync::atomic::AtomicUsize;
 
 /// Represents a struct used to enforce a numerical limit.
 pub struct Limit {
     upper_bound: usize,
-    #[allow(unused)]
+    #[cfg(feature = "tracking")]
     max: AtomicUsize,
 }
 
@@ -15,14 +16,22 @@ impl Limit {
     /// Creates a new limit.
     #[inline]
     pub const fn new(upper_bound: usize) -> Self {
-        Self { upper_bound, max: AtomicUsize::new(0) }
+        Self {
+            upper_bound,
+            #[cfg(feature = "tracking")]
+            max: AtomicUsize::new(0),
+        }
     }
 
     /// Creates a new limit.
     #[inline]
     #[cfg(feature = "tracking")]
     pub const fn new_tracking(upper_bound: usize) -> Self {
-        Self { upper_bound, max: AtomicUsize::new(1) }
+        Self {
+            upper_bound,
+            #[cfg(feature = "tracking")]
+            max: AtomicUsize::new(1),
+        }
     }
 
     /// Gets the underlying numeric limit.
index f9efcef92a610129911e6381401b7d66ce4919a8..8de5d33a1936d42479470854e39bee711f1916a2 100644 (file)
@@ -54,7 +54,7 @@ fn path_for_qualifier(
     mut qual: CompletedMarker,
 ) -> CompletedMarker {
     loop {
-        let use_tree = matches!(p.nth(2), T![*] | T!['{']);
+        let use_tree = mode == Mode::Use && matches!(p.nth(2), T![*] | T!['{']);
         if p.at(T![::]) && !use_tree {
             let path = qual.precede(p);
             p.bump(T![::]);
index 025093f4a94ab6ea81d4297bb64d6bdb0e26a15f..6ae23ac841adaa6a7f97d8841c57aec96f2d2439 100644 (file)
@@ -106,6 +106,14 @@ fn as_ref(&self) -> &Path {
     }
 }
 
+impl ToOwned for AbsPath {
+    type Owned = AbsPathBuf;
+
+    fn to_owned(&self) -> Self::Owned {
+        AbsPathBuf(self.0.to_owned())
+    }
+}
+
 impl<'a> TryFrom<&'a Path> for &'a AbsPath {
     type Error = &'a Path;
     fn try_from(path: &'a Path) -> Result<&'a AbsPath, &'a Path> {
index d7010e825aa9fddb7b35ec7c0f34cc677114de4f..a3ea05f4aff8e9ca60cc2ca53e4858e0f5e1fe9c 100644 (file)
@@ -60,7 +60,7 @@ pub fn new(path: AbsPathBuf) -> io::Result<MacroDylib> {
 
         let info = version::read_dylib_info(&path)?;
         if info.version.0 < 1 || info.version.1 < 47 {
-            let msg = format!("proc-macro {} built by {:#?} is not supported by Rust Analyzer, please update your rust version.", path.display(), info);
+            let msg = format!("proc-macro {} built by {:#?} is not supported by rust-analyzer, please update your Rust version.", path.display(), info);
             return Err(io::Error::new(io::ErrorKind::InvalidData, msg));
         }
 
index bcf3f1184cf6515dd8844f54833eb25e5ce0dd71..705d09ea9458bdad7cb17e87e0a366a17aa2fdae 100644 (file)
@@ -5,7 +5,7 @@
 //! compiler into submodules of this module (e.g proc_macro_srv::abis::abi_1_47).
 //!
 //! All of these ABIs are subsumed in the `Abi` enum, which exposes a simple
-//! interface the rest of rust analyzer can use to talk to the macro
+//! interface the rest of rust-analyzer can use to talk to the macro
 //! provider.
 //!
 //! # Adding a new ABI
index 4b1858b8ed89e87c87b4e6d481911427936d7e6c..4c205b9cadac3abd8311f9a7c1ae4d4f113f1b63 100644 (file)
@@ -39,6 +39,8 @@ pub(crate) struct ProcMacroSrv {
     expanders: HashMap<(PathBuf, SystemTime), dylib::Expander>,
 }
 
+const EXPANDER_STACK_SIZE: usize = 8 * 1024 * 1024;
+
 impl ProcMacroSrv {
     pub fn expand(&mut self, task: ExpandMacro) -> Result<FlatTree, PanicMessage> {
         let expander = self.expander(task.lib.as_ref()).map_err(|err| {
@@ -66,13 +68,18 @@ pub fn expand(&mut self, task: ExpandMacro) -> Result<FlatTree, PanicMessage> {
         // FIXME: replace this with std's scoped threads once they stabilize
         // (then remove dependency on crossbeam)
         let result = crossbeam::scope(|s| {
-            let res = s
+            let res = match s
+                .builder()
+                .stack_size(EXPANDER_STACK_SIZE)
+                .name(task.macro_name.clone())
                 .spawn(|_| {
                     expander
                         .expand(&task.macro_name, &macro_body, attributes.as_ref())
                         .map(|it| FlatTree::new(&it))
-                })
-                .join();
+                }) {
+                Ok(handle) => handle.join(),
+                Err(e) => std::panic::resume_unwind(Box::new(e)),
+            };
 
             match res {
                 Ok(res) => res,
index 597880c2ca214c62fde565e39643a6998ac5baf8..eed955b42daae9816c97951a8250571257cd68cd 100644 (file)
@@ -19,7 +19,7 @@
 /// [`CargoWorkspace`] represents the logical structure of, well, a Cargo
 /// workspace. It pretty closely mirrors `cargo metadata` output.
 ///
-/// Note that internally, rust analyzer uses a different structure:
+/// Note that internally, rust-analyzer uses a different structure:
 /// `CrateGraph`. `CrateGraph` is lower-level: it knows only about the crates,
 /// while this knows about `Packages` & `Targets`: purely cargo-related
 /// concepts.
index 0ada4b73e842d9d7f814bf71f74c9dc4441158c3..5d1c013c3275b2fabf86110ec16ac13dc75e0a1f 100644 (file)
@@ -66,7 +66,9 @@ pub fn load_workspace(
     };
 
     let crate_graph = ws.to_crate_graph(
-        &mut |_, path: &AbsPath| load_proc_macro(proc_macro_client.as_ref(), path, &[]),
+        &mut |_, path: &AbsPath| {
+            load_proc_macro(proc_macro_client.as_ref().map_err(|e| &**e), path, &[])
+        },
         &mut |path: &AbsPath| {
             let contents = loader.load_sync(path);
             let path = vfs::VfsPath::from(path.to_path_buf());
index 202a01adf71083595ec95da60674003a9df9b576..09150c77d7dd1d9de53adaff2a67382132e32711 100644 (file)
@@ -8,7 +8,7 @@
 
 use crate::lsp_ext;
 
-pub(crate) type CheckFixes = Arc<FxHashMap<FileId, Vec<Fix>>>;
+pub(crate) type CheckFixes = Arc<FxHashMap<usize, FxHashMap<FileId, Vec<Fix>>>>;
 
 #[derive(Debug, Default, Clone)]
 pub struct DiagnosticsMapConfig {
@@ -22,7 +22,7 @@ pub(crate) struct DiagnosticCollection {
     // FIXME: should be FxHashMap<FileId, Vec<ra_id::Diagnostic>>
     pub(crate) native: FxHashMap<FileId, Vec<lsp_types::Diagnostic>>,
     // FIXME: should be Vec<flycheck::Diagnostic>
-    pub(crate) check: FxHashMap<FileId, Vec<lsp_types::Diagnostic>>,
+    pub(crate) check: FxHashMap<usize, FxHashMap<FileId, Vec<lsp_types::Diagnostic>>>,
     pub(crate) check_fixes: CheckFixes,
     changes: FxHashSet<FileId>,
 }
@@ -35,9 +35,19 @@ pub(crate) struct Fix {
 }
 
 impl DiagnosticCollection {
-    pub(crate) fn clear_check(&mut self) {
+    pub(crate) fn clear_check(&mut self, flycheck_id: usize) {
+        if let Some(it) = Arc::make_mut(&mut self.check_fixes).get_mut(&flycheck_id) {
+            it.clear();
+        }
+        if let Some(it) = self.check.get_mut(&flycheck_id) {
+            self.changes.extend(it.drain().map(|(key, _value)| key));
+        }
+    }
+
+    pub(crate) fn clear_check_all(&mut self) {
         Arc::make_mut(&mut self.check_fixes).clear();
-        self.changes.extend(self.check.drain().map(|(key, _value)| key))
+        self.changes
+            .extend(self.check.values_mut().flat_map(|it| it.drain().map(|(key, _value)| key)))
     }
 
     pub(crate) fn clear_native_for(&mut self, file_id: FileId) {
@@ -47,11 +57,12 @@ pub(crate) fn clear_native_for(&mut self, file_id: FileId) {
 
     pub(crate) fn add_check_diagnostic(
         &mut self,
+        flycheck_id: usize,
         file_id: FileId,
         diagnostic: lsp_types::Diagnostic,
         fix: Option<Fix>,
     ) {
-        let diagnostics = self.check.entry(file_id).or_default();
+        let diagnostics = self.check.entry(flycheck_id).or_default().entry(file_id).or_default();
         for existing_diagnostic in diagnostics.iter() {
             if are_diagnostics_equal(existing_diagnostic, &diagnostic) {
                 return;
@@ -59,7 +70,7 @@ pub(crate) fn add_check_diagnostic(
         }
 
         let check_fixes = Arc::make_mut(&mut self.check_fixes);
-        check_fixes.entry(file_id).or_default().extend(fix);
+        check_fixes.entry(flycheck_id).or_default().entry(file_id).or_default().extend(fix);
         diagnostics.push(diagnostic);
         self.changes.insert(file_id);
     }
@@ -89,7 +100,8 @@ pub(crate) fn diagnostics_for(
         file_id: FileId,
     ) -> impl Iterator<Item = &lsp_types::Diagnostic> {
         let native = self.native.get(&file_id).into_iter().flatten();
-        let check = self.check.get(&file_id).into_iter().flatten();
+        let check =
+            self.check.values().filter_map(move |it| it.get(&file_id)).into_iter().flatten();
         native.chain(check)
     }
 
index 8f881cba4dbd7b113534e3cfdf1d6aa85bf95d27..b5f6aef2e1a84e60abb268aeebf86bd6be85301c 100644 (file)
@@ -8,7 +8,7 @@
 use crossbeam_channel::{unbounded, Receiver, Sender};
 use flycheck::FlycheckHandle;
 use ide::{Analysis, AnalysisHost, Cancellable, Change, FileId};
-use ide_db::base_db::{CrateId, FileLoader, SourceDatabase};
+use ide_db::base_db::{CrateId, FileLoader, SourceDatabase, SourceDatabaseExt};
 use lsp_types::{SemanticTokens, Url};
 use parking_lot::{Mutex, RwLock};
 use proc_macro_api::ProcMacroServer;
@@ -176,7 +176,7 @@ pub(crate) fn new(sender: Sender<lsp_server::Message>, config: Config) -> Global
 
     pub(crate) fn process_changes(&mut self) -> bool {
         let _p = profile::span("GlobalState::process_changes");
-        let mut fs_changes = Vec::new();
+        let mut fs_refresh_changes = Vec::new();
         // A file was added or deleted
         let mut has_structure_changes = false;
 
@@ -192,15 +192,14 @@ pub(crate) fn process_changes(&mut self) -> bool {
                 if let Some(path) = vfs.file_path(file.file_id).as_path() {
                     let path = path.to_path_buf();
                     if reload::should_refresh_for_change(&path, file.change_kind) {
-                        self.fetch_workspaces_queue
-                            .request_op(format!("vfs file change: {}", path.display()));
+                        fs_refresh_changes.push((path, file.file_id));
                     }
-                    fs_changes.push((path, file.change_kind));
                     if file.is_created_or_deleted() {
                         has_structure_changes = true;
                     }
                 }
 
+                // Clear native diagnostics when their file gets deleted
                 if !file.exists() {
                     self.diagnostics.clear_native_for(file.file_id);
                 }
@@ -226,14 +225,25 @@ pub(crate) fn process_changes(&mut self) -> bool {
 
         self.analysis_host.apply_change(change);
 
-        let raw_database = &self.analysis_host.raw_database();
-        self.proc_macro_changed =
-            changed_files.iter().filter(|file| !file.is_created_or_deleted()).any(|file| {
-                let crates = raw_database.relevant_crates(file.file_id);
-                let crate_graph = raw_database.crate_graph();
+        {
+            let raw_database = self.analysis_host.raw_database();
+            let workspace_structure_change =
+                fs_refresh_changes.into_iter().find(|&(_, file_id)| {
+                    !raw_database.source_root(raw_database.file_source_root(file_id)).is_library
+                });
+            if let Some((path, _)) = workspace_structure_change {
+                self.fetch_workspaces_queue
+                    .request_op(format!("workspace vfs file change: {}", path.display()));
+            }
+            self.proc_macro_changed =
+                changed_files.iter().filter(|file| !file.is_created_or_deleted()).any(|file| {
+                    let crates = raw_database.relevant_crates(file.file_id);
+                    let crate_graph = raw_database.crate_graph();
+
+                    crates.iter().any(|&krate| crate_graph[krate].is_proc_macro)
+                });
+        }
 
-                crates.iter().any(|&krate| crate_graph[krate].is_proc_macro)
-            });
         true
     }
 
index deb777c952fdf7d7658f92b77b8d50f68244499c..47daa732d5d3254ab779a9af4ae2091697c0bd13 100644 (file)
@@ -1094,7 +1094,9 @@ pub(crate) fn handle_code_action(
     }
 
     // Fixes from `cargo check`.
-    for fix in snap.check_fixes.get(&frange.file_id).into_iter().flatten() {
+    for fix in
+        snap.check_fixes.values().filter_map(|it| it.get(&frange.file_id)).into_iter().flatten()
+    {
         // FIXME: this mapping is awkward and shouldn't exist. Refactor
         // `snap.check_fixes` to not convert to LSP prematurely.
         let intersect_fix_range = fix
index 47cdd8dfc75d8f9abf95f755eb054040be48cb9f..e49a98685a7f11302fbaff40afe55d36c3719355 100644 (file)
@@ -6,8 +6,8 @@
 //! code here exercise this specific completion, and thus have a fast
 //! edit/compile/test cycle.
 //!
-//! Note that "Rust Analyzer: Run" action does not allow running a single test
-//! in release mode in VS Code. There's however "Rust Analyzer: Copy Run Command Line"
+//! Note that "rust-analyzer: Run" action does not allow running a single test
+//! in release mode in VS Code. There's however "rust-analyzer: Copy Run Command Line"
 //! which you can use to paste the command in terminal and add `--release` manually.
 
 use std::sync::Arc;
index 5845cf712c899d6dd578956bcea77d4a37a69968..b504c248782667752c8adfb5f10d8cbe1ecef11a 100644 (file)
@@ -2,13 +2,15 @@
 //! requests/replies and notifications back to the client.
 use std::{
     fmt,
+    ops::Deref,
     sync::Arc,
     time::{Duration, Instant},
 };
 
 use always_assert::always;
 use crossbeam_channel::{select, Receiver};
-use ide_db::base_db::{SourceDatabaseExt, VfsPath};
+use ide_db::base_db::{SourceDatabase, SourceDatabaseExt, VfsPath};
+use itertools::Itertools;
 use lsp_server::{Connection, Notification, Request};
 use lsp_types::notification::Notification as _;
 use vfs::{ChangeKind, FileId};
@@ -371,7 +373,7 @@ fn handle_event(&mut self, event: Event) -> Result<()> {
                 let _p = profile::span("GlobalState::handle_event/flycheck");
                 loop {
                     match task {
-                        flycheck::Message::AddDiagnostic { workspace_root, diagnostic } => {
+                        flycheck::Message::AddDiagnostic { id, workspace_root, diagnostic } => {
                             let snap = self.snapshot();
                             let diagnostics =
                                 crate::diagnostics::to_proto::map_rust_diagnostic_to_lsp(
@@ -383,6 +385,7 @@ fn handle_event(&mut self, event: Event) -> Result<()> {
                             for diag in diagnostics {
                                 match url_to_file_id(&self.vfs.read().0, &diag.url) {
                                     Ok(file_id) => self.diagnostics.add_check_diagnostic(
+                                        id,
                                         file_id,
                                         diag.diagnostic,
                                         diag.fix,
@@ -400,7 +403,7 @@ fn handle_event(&mut self, event: Event) -> Result<()> {
                         flycheck::Message::Progress { id, progress } => {
                             let (state, message) = match progress {
                                 flycheck::Progress::DidStart => {
-                                    self.diagnostics.clear_check();
+                                    self.diagnostics.clear_check(id);
                                     (Progress::Begin, None)
                                 }
                                 flycheck::Progress::DidCheckCrate(target) => {
@@ -444,7 +447,10 @@ fn handle_event(&mut self, event: Event) -> Result<()> {
         let memdocs_added_or_removed = self.mem_docs.take_changes();
 
         if self.is_quiescent() {
-            if !was_quiescent {
+            if !was_quiescent
+                && !self.fetch_workspaces_queue.op_requested()
+                && !self.fetch_build_data_queue.op_requested()
+            {
                 for flycheck in &self.flycheck {
                     flycheck.update();
                 }
@@ -734,13 +740,76 @@ fn on_notification(&mut self, not: Notification) -> Result<()> {
                 Ok(())
             })?
             .on::<lsp_types::notification::DidSaveTextDocument>(|this, params| {
-                for flycheck in &this.flycheck {
-                    flycheck.update();
+                let mut updated = false;
+                if let Ok(vfs_path) = from_proto::vfs_path(&params.text_document.uri) {
+                    let (vfs, _) = &*this.vfs.read();
+                    if let Some(file_id) = vfs.file_id(&vfs_path) {
+                        let analysis = this.analysis_host.analysis();
+                        // Crates containing or depending on the saved file
+                        let crate_ids: Vec<_> = analysis
+                            .crate_for(file_id)?
+                            .into_iter()
+                            .flat_map(|id| {
+                                this.analysis_host
+                                    .raw_database()
+                                    .crate_graph()
+                                    .transitive_rev_deps(id)
+                            })
+                            .sorted()
+                            .unique()
+                            .collect();
+
+                        let crate_root_paths: Vec<_> = crate_ids
+                            .iter()
+                            .filter_map(|&crate_id| {
+                                analysis
+                                    .crate_root(crate_id)
+                                    .map(|file_id| {
+                                        vfs.file_path(file_id).as_path().map(ToOwned::to_owned)
+                                    })
+                                    .transpose()
+                            })
+                            .collect::<ide::Cancellable<_>>()?;
+                        let crate_root_paths: Vec<_> =
+                            crate_root_paths.iter().map(Deref::deref).collect();
+
+                        // Find all workspaces that have at least one target containing the saved file
+                        let workspace_ids =
+                            this.workspaces.iter().enumerate().filter(|(_, ws)| match ws {
+                                project_model::ProjectWorkspace::Cargo { cargo, .. } => {
+                                    cargo.packages().any(|pkg| {
+                                        cargo[pkg].targets.iter().any(|&it| {
+                                            crate_root_paths.contains(&cargo[it].root.as_path())
+                                        })
+                                    })
+                                }
+                                project_model::ProjectWorkspace::Json { project, .. } => project
+                                    .crates()
+                                    .any(|(c, _)| crate_ids.iter().any(|&crate_id| crate_id == c)),
+                                project_model::ProjectWorkspace::DetachedFiles { .. } => false,
+                            });
+
+                        // Find and trigger corresponding flychecks
+                        for flycheck in &this.flycheck {
+                            for (id, _) in workspace_ids.clone() {
+                                if id == flycheck.id() {
+                                    updated = true;
+                                    flycheck.update();
+                                    continue;
+                                }
+                            }
+                        }
+                    }
+                    if let Some(abs_path) = vfs_path.as_path() {
+                        if reload::should_refresh_for_change(&abs_path, ChangeKind::Modify) {
+                            this.fetch_workspaces_queue
+                                .request_op(format!("DidSaveTextDocument {}", abs_path.display()));
+                        }
+                    }
                 }
-                if let Ok(abs_path) = from_proto::abs_path(&params.text_document.uri) {
-                    if reload::should_refresh_for_change(&abs_path, ChangeKind::Modify) {
-                        this.fetch_workspaces_queue
-                            .request_op(format!("DidSaveTextDocument {}", abs_path.display()));
+                if !updated {
+                    for flycheck in &this.flycheck {
+                        flycheck.update();
                     }
                 }
                 Ok(())
index 9ae361b034e28959043b1fbd2a40298fb86a7146..49ccad71a10e851e0cdcac2aeadab773f2171f7b 100644 (file)
@@ -196,10 +196,7 @@ pub(crate) fn switch_workspaces(&mut self, cause: Cause) {
         }
 
         if let Err(error) = self.fetch_build_data_error() {
-            self.show_and_log_error(
-                "rust-analyzer failed to run build scripts".to_string(),
-                Some(error),
-            );
+            self.show_and_log_error("failed to run build scripts".to_string(), Some(error));
         }
 
         let workspaces = self
@@ -303,8 +300,12 @@ fn eq_ignore_build_data<'a>(
         let files_config = self.config.files();
         let project_folders = ProjectFolders::new(&self.workspaces, &files_config.exclude);
 
+        let standalone_server_name =
+            format!("rust-analyzer-proc-macro-srv{}", std::env::consts::EXE_SUFFIX);
+
         if self.proc_macro_clients.is_empty() {
             if let Some((path, args)) = self.config.proc_macro_srv() {
+                tracing::info!("Spawning proc-macro servers");
                 self.proc_macro_clients = self
                     .workspaces
                     .iter()
@@ -313,22 +314,20 @@ fn eq_ignore_build_data<'a>(
                         let mut path = path.clone();
 
                         if let ProjectWorkspace::Cargo { sysroot, .. } = ws {
-                            tracing::info!("Found a cargo workspace...");
+                            tracing::debug!("Found a cargo workspace...");
                             if let Some(sysroot) = sysroot.as_ref() {
-                                tracing::info!("Found a cargo workspace with a sysroot...");
-                                let server_path = sysroot
-                                    .root()
-                                    .join("libexec")
-                                    .join("rust-analyzer-proc-macro-srv");
+                                tracing::debug!("Found a cargo workspace with a sysroot...");
+                                let server_path =
+                                    sysroot.root().join("libexec").join(&standalone_server_name);
                                 if std::fs::metadata(&server_path).is_ok() {
-                                    tracing::info!(
+                                    tracing::debug!(
                                         "And the server exists at {}",
                                         server_path.display()
                                     );
                                     path = server_path;
                                     args = vec![];
                                 } else {
-                                    tracing::info!(
+                                    tracing::debug!(
                                         "And the server does not exist at {}",
                                         server_path.display()
                                     );
@@ -336,14 +335,10 @@ fn eq_ignore_build_data<'a>(
                             }
                         }
 
-                        tracing::info!(
-                            "Using proc-macro server at {} with args {:?}",
-                            path.display(),
-                            args
-                        );
+                        tracing::info!(?args, "Using proc-macro server at {}", path.display(),);
                         ProcMacroServer::spawn(path.clone(), args.clone()).map_err(|err| {
                             let error = format!(
-                                "Failed to run proc_macro_srv from path {}, error: {:?}",
+                                "Failed to run proc-macro server from path {}, error: {:?}",
                                 path.display(),
                                 err
                             );
@@ -389,7 +384,10 @@ fn eq_ignore_build_data<'a>(
 
             let mut crate_graph = CrateGraph::default();
             for (idx, ws) in self.workspaces.iter().enumerate() {
-                let proc_macro_client = self.proc_macro_clients[idx].as_ref();
+                let proc_macro_client = match self.proc_macro_clients.get(idx) {
+                    Some(res) => res.as_ref().map_err(|e| &**e),
+                    None => Err("Proc macros are disabled"),
+                };
                 let mut load_proc_macro = move |crate_name: &str, path: &AbsPath| {
                     load_proc_macro(
                         proc_macro_client,
@@ -454,7 +452,7 @@ fn reload_flycheck(&mut self) {
             Some(it) => it,
             None => {
                 self.flycheck = Vec::new();
-                self.diagnostics.clear_check();
+                self.diagnostics.clear_check_all();
                 return;
             }
         };
@@ -573,7 +571,7 @@ pub(crate) fn partition(&self, vfs: &vfs::Vfs) -> Vec<SourceRoot> {
 /// Load the proc-macros for the given lib path, replacing all expanders whose names are in `dummy_replace`
 /// with an identity dummy expander.
 pub(crate) fn load_proc_macro(
-    server: Result<&ProcMacroServer, &String>,
+    server: Result<&ProcMacroServer, &str>,
     path: &AbsPath,
     dummy_replace: &[Box<str>],
 ) -> ProcMacroLoadResult {
@@ -617,7 +615,10 @@ fn expander_to_proc_macro(
         };
         let expander: Arc<dyn ProcMacroExpander> =
             if dummy_replace.iter().any(|replace| &**replace == name) {
-                Arc::new(DummyExpander)
+                match kind {
+                    ProcMacroKind::Attr => Arc::new(IdentityExpander),
+                    _ => Arc::new(EmptyExpander),
+                }
             } else {
                 Arc::new(Expander(expander))
             };
@@ -643,11 +644,11 @@ fn expand(
         }
     }
 
-    /// Dummy identity expander, used for proc-macros that are deliberately ignored by the user.
+    /// Dummy identity expander, used for attribute proc-macros that are deliberately ignored by the user.
     #[derive(Debug)]
-    struct DummyExpander;
+    struct IdentityExpander;
 
-    impl ProcMacroExpander for DummyExpander {
+    impl ProcMacroExpander for IdentityExpander {
         fn expand(
             &self,
             subtree: &tt::Subtree,
@@ -657,27 +658,46 @@ fn expand(
             Ok(subtree.clone())
         }
     }
+
+    /// Empty expander, used for proc-macros that are deliberately ignored by the user.
+    #[derive(Debug)]
+    struct EmptyExpander;
+
+    impl ProcMacroExpander for EmptyExpander {
+        fn expand(
+            &self,
+            _: &tt::Subtree,
+            _: Option<&tt::Subtree>,
+            _: &Env,
+        ) -> Result<tt::Subtree, ProcMacroExpansionError> {
+            Ok(tt::Subtree::default())
+        }
+    }
 }
 
 pub(crate) fn should_refresh_for_change(path: &AbsPath, change_kind: ChangeKind) -> bool {
     const IMPLICIT_TARGET_FILES: &[&str] = &["build.rs", "src/main.rs", "src/lib.rs"];
     const IMPLICIT_TARGET_DIRS: &[&str] = &["src/bin", "examples", "tests", "benches"];
-    let file_name = path.file_name().unwrap_or_default();
 
-    if file_name == "Cargo.toml" || file_name == "Cargo.lock" {
+    let file_name = match path.file_name().unwrap_or_default().to_str() {
+        Some(it) => it,
+        None => return false,
+    };
+
+    if let "Cargo.toml" | "Cargo.lock" = file_name {
         return true;
     }
     if change_kind == ChangeKind::Modify {
         return false;
     }
+
+    // .cargo/config{.toml}
     if path.extension().unwrap_or_default() != "rs" {
-        if (file_name == "config.toml" || file_name == "config")
-            && path.parent().map(|parent| parent.as_ref().ends_with(".cargo")) == Some(true)
-        {
-            return true;
-        }
-        return false;
+        let is_cargo_config = matches!(file_name, "config.toml" | "config")
+            && path.parent().map(|parent| parent.as_ref().ends_with(".cargo")).unwrap_or(false);
+        return is_cargo_config;
     }
+
     if IMPLICIT_TARGET_FILES.iter().any(|it| path.as_ref().ends_with(it)) {
         return true;
     }
index 18f95925d9a49e71c34b0545680a35dbb4a0181b..58099a58de053acb0506bfc61a77b264a987e6dd 100644 (file)
@@ -13,9 +13,8 @@
 fn check_code_formatting() {
     let sh = &Shell::new().unwrap();
     sh.change_dir(sourcegen::project_root());
-    sh.set_var("RUSTUP_TOOLCHAIN", "stable");
 
-    let out = cmd!(sh, "rustfmt --version").read().unwrap();
+    let out = cmd!(sh, "rustup run stable rustfmt --version").read().unwrap();
     if !out.contains("stable") {
         panic!(
             "Failed to run rustfmt from toolchain 'stable'. \
@@ -23,9 +22,9 @@ fn check_code_formatting() {
         )
     }
 
-    let res = cmd!(sh, "cargo fmt -- --check").run();
+    let res = cmd!(sh, "rustup run stable cargo fmt -- --check").run();
     if res.is_err() {
-        let _ = cmd!(sh, "cargo fmt").run();
+        let _ = cmd!(sh, "rustup run stable cargo fmt").run();
     }
     res.unwrap()
 }
index ce0224ec744d9a40e5420306350824cde9d23451..4e0ee63f32f26a2e7ce56b832325e223bb0233b7 100644 (file)
@@ -136,7 +136,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 }
 
 fn ensure_rustfmt(sh: &Shell) {
-    let version = cmd!(sh, "rustfmt --version").read().unwrap_or_default();
+    let version = cmd!(sh, "rustup run stable rustfmt --version").read().unwrap_or_default();
     if !version.contains("stable") {
         panic!(
             "Failed to run rustfmt from toolchain 'stable'. \
@@ -147,13 +147,15 @@ fn ensure_rustfmt(sh: &Shell) {
 
 pub fn reformat(text: String) -> String {
     let sh = Shell::new().unwrap();
-    sh.set_var("RUSTUP_TOOLCHAIN", "stable");
     ensure_rustfmt(&sh);
     let rustfmt_toml = project_root().join("rustfmt.toml");
-    let mut stdout = cmd!(sh, "rustfmt --config-path {rustfmt_toml} --config fn_single_line=true")
-        .stdin(text)
-        .read()
-        .unwrap();
+    let mut stdout = cmd!(
+        sh,
+        "rustup run stable rustfmt --config-path {rustfmt_toml} --config fn_single_line=true"
+    )
+    .stdin(text)
+    .read()
+    .unwrap();
     if !stdout.ends_with('\n') {
         stdout.push('\n');
     }
index e3e928aecd4addb5027f44e15f0928ce93675d40..8efd58e2c39aa48c098844ad853a30993d314f42 100644 (file)
@@ -11,7 +11,7 @@
     ted::{self, Position},
     AstNode, AstToken, Direction,
     SyntaxKind::{ATTR, COMMENT, WHITESPACE},
-    SyntaxNode,
+    SyntaxNode, SyntaxToken,
 };
 
 use super::HasName;
@@ -506,19 +506,7 @@ pub fn add_field(&self, field: ast::RecordExprField) {
 
         let position = match self.fields().last() {
             Some(last_field) => {
-                let comma = match last_field
-                    .syntax()
-                    .siblings_with_tokens(Direction::Next)
-                    .filter_map(|it| it.into_token())
-                    .find(|it| it.kind() == T![,])
-                {
-                    Some(it) => it,
-                    None => {
-                        let comma = ast::make::token(T![,]);
-                        ted::insert(Position::after(last_field.syntax()), &comma);
-                        comma
-                    }
-                };
+                let comma = get_or_insert_comma_after(last_field.syntax());
                 Position::after(comma)
             }
             None => match self.l_curly_token() {
@@ -579,19 +567,8 @@ pub fn add_field(&self, field: ast::RecordPatField) {
 
         let position = match self.fields().last() {
             Some(last_field) => {
-                let comma = match last_field
-                    .syntax()
-                    .siblings_with_tokens(Direction::Next)
-                    .filter_map(|it| it.into_token())
-                    .find(|it| it.kind() == T![,])
-                {
-                    Some(it) => it,
-                    None => {
-                        let comma = ast::make::token(T![,]);
-                        ted::insert(Position::after(last_field.syntax()), &comma);
-                        comma
-                    }
-                };
+                let syntax = last_field.syntax();
+                let comma = get_or_insert_comma_after(syntax);
                 Position::after(comma)
             }
             None => match self.l_curly_token() {
@@ -606,12 +583,53 @@ pub fn add_field(&self, field: ast::RecordPatField) {
         }
     }
 }
+
+fn get_or_insert_comma_after(syntax: &SyntaxNode) -> SyntaxToken {
+    let comma = match syntax
+        .siblings_with_tokens(Direction::Next)
+        .filter_map(|it| it.into_token())
+        .find(|it| it.kind() == T![,])
+    {
+        Some(it) => it,
+        None => {
+            let comma = ast::make::token(T![,]);
+            ted::insert(Position::after(syntax), &comma);
+            comma
+        }
+    };
+    comma
+}
+
 impl ast::StmtList {
     pub fn push_front(&self, statement: ast::Stmt) {
         ted::insert(Position::after(self.l_curly_token().unwrap()), statement.syntax());
     }
 }
 
+impl ast::VariantList {
+    pub fn add_variant(&self, variant: ast::Variant) {
+        let (indent, position) = match self.variants().last() {
+            Some(last_item) => (
+                IndentLevel::from_node(last_item.syntax()),
+                Position::after(get_or_insert_comma_after(last_item.syntax())),
+            ),
+            None => match self.l_curly_token() {
+                Some(l_curly) => {
+                    normalize_ws_between_braces(self.syntax());
+                    (IndentLevel::from_token(&l_curly) + 1, Position::after(&l_curly))
+                }
+                None => (IndentLevel::single(), Position::last_child_of(self.syntax())),
+            },
+        };
+        let elements: Vec<SyntaxElement<_>> = vec![
+            make::tokens::whitespace(&format!("{}{}", "\n", indent)).into(),
+            variant.syntax().clone().into(),
+            ast::make::token(T![,]).into(),
+        ];
+        ted::insert_all(position, elements);
+    }
+}
+
 fn normalize_ws_between_braces(node: &SyntaxNode) -> Option<()> {
     let l = node
         .children_with_tokens()
@@ -661,6 +679,9 @@ impl<N: AstNode + Clone> Indent for N {}
 mod tests {
     use std::fmt;
 
+    use stdx::trim_indent;
+    use test_utils::assert_eq_text;
+
     use crate::SourceFile;
 
     use super::*;
@@ -714,4 +735,100 @@ fn test_increase_indent() {
         }",
         );
     }
+
+    #[test]
+    fn add_variant_to_empty_enum() {
+        let variant = make::variant(make::name("Bar"), None).clone_for_update();
+
+        check_add_variant(
+            r#"
+enum Foo {}
+"#,
+            r#"
+enum Foo {
+    Bar,
+}
+"#,
+            variant,
+        );
+    }
+
+    #[test]
+    fn add_variant_to_non_empty_enum() {
+        let variant = make::variant(make::name("Baz"), None).clone_for_update();
+
+        check_add_variant(
+            r#"
+enum Foo {
+    Bar,
+}
+"#,
+            r#"
+enum Foo {
+    Bar,
+    Baz,
+}
+"#,
+            variant,
+        );
+    }
+
+    #[test]
+    fn add_variant_with_tuple_field_list() {
+        let variant = make::variant(
+            make::name("Baz"),
+            Some(ast::FieldList::TupleFieldList(make::tuple_field_list(std::iter::once(
+                make::tuple_field(None, make::ty("bool")),
+            )))),
+        )
+        .clone_for_update();
+
+        check_add_variant(
+            r#"
+enum Foo {
+    Bar,
+}
+"#,
+            r#"
+enum Foo {
+    Bar,
+    Baz(bool),
+}
+"#,
+            variant,
+        );
+    }
+
+    #[test]
+    fn add_variant_with_record_field_list() {
+        let variant = make::variant(
+            make::name("Baz"),
+            Some(ast::FieldList::RecordFieldList(make::record_field_list(std::iter::once(
+                make::record_field(None, make::name("x"), make::ty("bool")),
+            )))),
+        )
+        .clone_for_update();
+
+        check_add_variant(
+            r#"
+enum Foo {
+    Bar,
+}
+"#,
+            r#"
+enum Foo {
+    Bar,
+    Baz { x: bool },
+}
+"#,
+            variant,
+        );
+    }
+
+    fn check_add_variant(before: &str, expected: &str, variant: ast::Variant) {
+        let enum_ = ast_mut_from_text::<ast::Enum>(before);
+        enum_.variant_list().map(|it| it.add_variant(variant));
+        let after = enum_.to_string();
+        assert_eq_text!(&trim_indent(expected.trim()), &trim_indent(&after.trim()));
+    }
 }
index cf90ba64cff1ab5ba6e41e3e7c9246698a21fc11..63309a155219e55ebec99bcfd3b416ede648df38 100644 (file)
@@ -880,7 +880,6 @@ impl ForExpr {
     pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) }
     pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
     pub fn in_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![in]) }
-    pub fn iterable(&self) -> Option<Expr> { support::child(&self.syntax) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -890,7 +889,6 @@ pub struct IfExpr {
 impl ast::HasAttrs for IfExpr {}
 impl IfExpr {
     pub fn if_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![if]) }
-    pub fn condition(&self) -> Option<Expr> { support::child(&self.syntax) }
     pub fn else_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![else]) }
 }
 
@@ -1051,7 +1049,6 @@ pub struct WhileExpr {
 impl ast::HasAttrs for WhileExpr {}
 impl WhileExpr {
     pub fn while_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![while]) }
-    pub fn condition(&self) -> Option<Expr> { support::child(&self.syntax) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -1170,7 +1167,6 @@ pub struct MatchGuard {
 }
 impl MatchGuard {
     pub fn if_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![if]) }
-    pub fn condition(&self) -> Option<Expr> { support::child(&self.syntax) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
index 5908dda8e6383d76cc5ca30dff4f0dc038af7de9..037de876d45c94f16955502621129bc2872b2b85 100644 (file)
@@ -745,7 +745,10 @@ pub fn tuple_field(visibility: Option<ast::Visibility>, ty: ast::Type) -> ast::T
 pub fn variant(name: ast::Name, field_list: Option<ast::FieldList>) -> ast::Variant {
     let field_list = match field_list {
         None => String::new(),
-        Some(it) => format!("{}", it),
+        Some(it) => match it {
+            ast::FieldList::RecordFieldList(record) => format!(" {}", record),
+            ast::FieldList::TupleFieldList(tuple) => format!("{}", tuple),
+        },
     };
     ast_from_text(&format!("enum f {{ {}{} }}", name, field_list))
 }
index b143df1f83f2ae3a2aa26dad048cd1fedc5c0492..bb92c51e9a90ed766bce24344f8ddeeb2337ed8c 100644 (file)
@@ -806,6 +806,19 @@ pub fn type_or_const_params(&self) -> impl Iterator<Item = ast::TypeOrConstParam
     }
 }
 
+impl ast::ForExpr {
+    pub fn iterable(&self) -> Option<ast::Expr> {
+        // If the iterable is a BlockExpr, check if the body is missing.
+        // If it is assume the iterable is the expression that is missing instead.
+        let mut exprs = support::children(self.syntax());
+        let first = exprs.next();
+        match first {
+            Some(ast::Expr::BlockExpr(_)) => exprs.next().and(first),
+            first => first,
+        }
+    }
+}
+
 impl ast::HasLoopBody for ast::ForExpr {
     fn loop_body(&self) -> Option<ast::BlockExpr> {
         let mut exprs = support::children(self.syntax());
@@ -815,6 +828,19 @@ fn loop_body(&self) -> Option<ast::BlockExpr> {
     }
 }
 
+impl ast::WhileExpr {
+    pub fn condition(&self) -> Option<ast::Expr> {
+        // If the condition is a BlockExpr, check if the body is missing.
+        // If it is assume the condition is the expression that is missing instead.
+        let mut exprs = support::children(self.syntax());
+        let first = exprs.next();
+        match first {
+            Some(ast::Expr::BlockExpr(_)) => exprs.next().and(first),
+            first => first,
+        }
+    }
+}
+
 impl ast::HasLoopBody for ast::WhileExpr {
     fn loop_body(&self) -> Option<ast::BlockExpr> {
         let mut exprs = support::children(self.syntax());
@@ -835,3 +861,15 @@ fn from(it: ast::Adt) -> Self {
         }
     }
 }
+
+impl ast::IfExpr {
+    pub fn condition(&self) -> Option<ast::Expr> {
+        support::child(&self.syntax)
+    }
+}
+
+impl ast::MatchGuard {
+    pub fn condition(&self) -> Option<ast::Expr> {
+        support::child(&self.syntax)
+    }
+}
index 7fa354c0c4652e7594dba526c7ee12f605f69d42..4f5e273a520a14212256f1ac7a898b354e942216 100644 (file)
@@ -1,4 +1,4 @@
-//! Syntax Tree library used throughout the rust analyzer.
+//! Syntax Tree library used throughout the rust-analyzer.
 //!
 //! Properties:
 //!   - easy and fast incremental re-parsing
index 4cfb8075cb155c5a47677701d8a50cc2c0938b28..6d2766225103f7b0aa2406a99939031a973b7274 100644 (file)
@@ -682,6 +682,8 @@ fn lower_rule(acc: &mut Vec<Field>, grammar: &Grammar, label: Option<&String>, r
                     | "value"
                     | "trait"
                     | "self_ty"
+                    | "iterable"
+                    | "condition"
             );
             if manually_implemented {
                 return;
index 4d33a9afb9635254a3fcd36e661ca3d55e15bbfe..d6d9c66159fe1fa624c742d69a9ecfbbd3918de2 100644 (file)
@@ -40,12 +40,15 @@ fn spawn(sender: loader::Sender) -> NotifyHandle {
             .expect("failed to spawn thread");
         NotifyHandle { sender, _thread: thread }
     }
+
     fn set_config(&mut self, config: loader::Config) {
         self.sender.send(Message::Config(config)).unwrap();
     }
+
     fn invalidate(&mut self, path: AbsPathBuf) {
         self.sender.send(Message::Invalidate(path)).unwrap();
     }
+
     fn load_sync(&mut self, path: &AbsPath) -> Option<Vec<u8>> {
         read(path)
     }
@@ -70,6 +73,7 @@ impl NotifyActor {
     fn new(sender: loader::Sender) -> NotifyActor {
         NotifyActor { sender, watched_entries: Vec::new(), watcher: None }
     }
+
     fn next_event(&self, receiver: &Receiver<Message>) -> Option<Event> {
         let watcher_receiver = self.watcher.as_ref().map(|(_, receiver)| receiver);
         select! {
@@ -77,9 +81,10 @@ fn next_event(&self, receiver: &Receiver<Message>) -> Option<Event> {
             recv(watcher_receiver.unwrap_or(&never())) -> it => Some(Event::NotifyEvent(it.unwrap())),
         }
     }
+
     fn run(mut self, inbox: Receiver<Message>) {
         while let Some(event) = self.next_event(&inbox) {
-            tracing::debug!("vfs-notify event: {:?}", event);
+            tracing::debug!(?event, "vfs-notify event");
             match event {
                 Event::Message(msg) => match msg {
                     Message::Config(config) => {
index 468f2b9e981fe29851a793c0fa412ed7718d378c..c7f152acc26690ecce60fdb3a9a15313e2d22ed7 100644 (file)
@@ -82,7 +82,7 @@ There's **"Run Extension (Debug Build)"** launch configuration for this in VS Co
 In general, I use one of the following workflows for fixing bugs and implementing features:
 
 If the problem concerns only internal parts of rust-analyzer (i.e. I don't need to touch the `rust-analyzer` crate or TypeScript code), there is a unit-test for it.
-So, I use **Rust Analyzer: Run** action in VS Code to run this single test, and then just do printf-driven development/debugging.
+So, I use **rust-analyzer: Run** action in VS Code to run this single test, and then just do printf-driven development/debugging.
 As a sanity check after I'm done, I use `cargo xtask install --server` and **Reload Window** action in VS Code to verify that the thing works as I expect.
 
 If the problem concerns only the VS Code extension, I use **Run Installed Extension** launch configuration from `launch.json`.
@@ -152,11 +152,11 @@ To log all communication between the server and the client, there are two choice
 
 There are also several VS Code commands which might be of interest:
 
-* `Rust Analyzer: Status` shows some memory-usage statistics.
+* `rust-analyzer: Status` shows some memory-usage statistics.
 
-* `Rust Analyzer: Syntax Tree` shows syntax tree of the current file/selection.
+* `rust-analyzer: Syntax Tree` shows syntax tree of the current file/selection.
 
-* `Rust Analyzer: View Hir` shows the HIR expressions within the function containing the cursor.
+* `rust-analyzer: View Hir` shows the HIR expressions within the function containing the cursor.
 
   You can hover over syntax nodes in the opened text file to see the appropriate
   rust code that it refers to and the rust editor will also highlight the proper
@@ -210,7 +210,8 @@ Release process is handled by `release`, `dist` and `promote` xtasks, `release`
 ./rust-rust-analyzer  # Note the name!
 ```
 
-Additionally, it assumes that the remote for `rust-analyzer` is called `upstream` (I use `origin` to point to my fork).
+The remote for `rust-analyzer` must be called `upstream` (I use `origin` to point to my fork).
+In addition, for `xtask promote` (see below), `rust-rust-analyzer` must have a `rust-analyzer` remote pointing to this repository on GitHub.
 
 `release` calls the GitHub API calls to scrape pull request comments and categorize them in the changelog.
 This step uses the `curl` and `jq` applications, which need to be available in `PATH`.
@@ -225,13 +226,13 @@ Release steps:
    * push it to `upstream`. This triggers GitHub Actions which:
      * runs `cargo xtask dist` to package binaries and VS Code extension
      * makes a GitHub release
-     * pushes VS Code extension to the marketplace
+     * publishes the VS Code extension to the marketplace
    * call the GitHub API for PR details
    * create a new changelog in `rust-analyzer.github.io`
 3. While the release is in progress, fill in the changelog
 4. Commit & push the changelog
 5. Tweet
-6. Inside `rust-analyzer`, run `cargo xtask promote` -- this will create a PR to rust-lang/rust updating rust-analyzer's submodule.
+6. Inside `rust-analyzer`, run `cargo xtask promote` -- this will create a PR to rust-lang/rust updating rust-analyzer's subtree.
    Self-approve the PR.
 
 If the GitHub Actions release fails because of a transient problem like a timeout, you can re-run the job from the Actions console.
index ea4035baf114c1599210a71f5d0630f1b413b67d..51e26c58a9175d4c8c17efa58df77249a73860cd 100644 (file)
@@ -371,7 +371,7 @@ That is, rust-analyzer requires unwinding.
 
 ### Testing
 
-Rust Analyzer has three interesting [system boundaries](https://www.tedinski.com/2018/04/10/making-tests-a-positive-influence-on-design.html) to concentrate tests on.
+rust-analyzer has three interesting [system boundaries](https://www.tedinski.com/2018/04/10/making-tests-a-positive-influence-on-design.html) to concentrate tests on.
 
 The outermost boundary is the `rust-analyzer` crate, which defines an LSP interface in terms of stdio.
 We do integration testing of this component, by feeding it with a stream of LSP requests and checking responses.
index 47ae3f3e6a9026dc027027e411b9db1e8d63af9d..808eb5d10bf4acb80fff8f02f7ba8c2b797b2175 100644 (file)
@@ -63,7 +63,7 @@ Next, let's talk about what the inputs to the `Analysis` are, precisely.
 
 ## Inputs
 
-Rust Analyzer never does any I/O itself, all inputs get passed explicitly via
+rust-analyzer never does any I/O itself, all inputs get passed explicitly via
 the `AnalysisHost::apply_change` method, which accepts a single argument, a
 `Change`. [`Change`] is a builder for a single change
 "transaction", so it suffices to study its methods to understand all of the
index 999a6437ab9ed3955573447d37bbb83cd424f710..c482fcbed0e01ccea9ab998dad16a7649f6fb61a 100644 (file)
@@ -479,7 +479,7 @@ You can follow instructions for installing <<rust-analyzer-language-server-binar
 == Troubleshooting
 
 Start with looking at the rust-analyzer version.
-Try **Rust Analyzer: Show RA Version** in VS Code (using **Command Palette** feature typically activated by Ctrl+Shift+P) or `rust-analyzer --version` in the command line.
+Try **rust-analyzer: Show RA Version** in VS Code (using **Command Palette** feature typically activated by Ctrl+Shift+P) or `rust-analyzer --version` in the command line.
 If the date is more than a week ago, it's better to update rust-analyzer version.
 
 The next thing to check would be panic messages in rust-analyzer's log.
@@ -492,7 +492,7 @@ To fully capture LSP messages between the editor and the server, set `"rust-anal
 The root cause for many "`nothing works`" problems is that rust-analyzer fails to understand the project structure.
 To debug that, first note the `rust-analyzer` section in the status bar.
 If it has an error icon and red, that's the problem (hover will have somewhat helpful error message).
-**Rust Analyzer: Status** prints dependency information for the current file.
+**rust-analyzer: Status** prints dependency information for the current file.
 Finally, `RA_LOG=project_model=debug` enables verbose logs during project loading.
 
 If rust-analyzer outright crashes, try running `rust-analyzer analysis-stats /path/to/project/directory/` on the command line.
index a13798d8b36c90e4afe7618c3b24e772263d9bc9..fbdc69c80137646c98187022e39030e4a791762d 100644 (file)
             {
                 "command": "rust-analyzer.syntaxTree",
                 "title": "Show Syntax Tree",
-                "category": "Rust Analyzer"
+                "category": "rust-analyzer"
             },
             {
                 "command": "rust-analyzer.viewHir",
                 "title": "View Hir",
-                "category": "Rust Analyzer"
+                "category": "rust-analyzer"
             },
             {
                 "command": "rust-analyzer.viewFileText",
                 "title": "View File Text (as seen by the server)",
-                "category": "Rust Analyzer"
+                "category": "rust-analyzer"
             },
             {
                 "command": "rust-analyzer.viewItemTree",
                 "title": "Debug ItemTree",
-                "category": "Rust Analyzer"
+                "category": "rust-analyzer"
             },
             {
                 "command": "rust-analyzer.viewCrateGraph",
                 "title": "View Crate Graph",
-                "category": "Rust Analyzer"
+                "category": "rust-analyzer"
             },
             {
                 "command": "rust-analyzer.viewFullCrateGraph",
                 "title": "View Crate Graph (Full)",
-                "category": "Rust Analyzer"
+                "category": "rust-analyzer"
             },
             {
                 "command": "rust-analyzer.expandMacro",
                 "title": "Expand macro recursively",
-                "category": "Rust Analyzer"
+                "category": "rust-analyzer"
             },
             {
                 "command": "rust-analyzer.matchingBrace",
                 "title": "Find matching brace",
-                "category": "Rust Analyzer"
+                "category": "rust-analyzer"
             },
             {
                 "command": "rust-analyzer.parentModule",
                 "title": "Locate parent module",
-                "category": "Rust Analyzer"
+                "category": "rust-analyzer"
             },
             {
                 "command": "rust-analyzer.joinLines",
                 "title": "Join lines",
-                "category": "Rust Analyzer"
+                "category": "rust-analyzer"
             },
             {
                 "command": "rust-analyzer.run",
                 "title": "Run",
-                "category": "Rust Analyzer"
+                "category": "rust-analyzer"
             },
             {
                 "command": "rust-analyzer.copyRunCommandLine",
                 "title": "Copy Run Command Line",
-                "category": "Rust Analyzer"
+                "category": "rust-analyzer"
             },
             {
                 "command": "rust-analyzer.debug",
                 "title": "Debug",
-                "category": "Rust Analyzer"
+                "category": "rust-analyzer"
             },
             {
                 "command": "rust-analyzer.newDebugConfig",
                 "title": "Generate launch configuration",
-                "category": "Rust Analyzer"
+                "category": "rust-analyzer"
             },
             {
                 "command": "rust-analyzer.analyzerStatus",
                 "title": "Status",
-                "category": "Rust Analyzer"
+                "category": "rust-analyzer"
             },
             {
                 "command": "rust-analyzer.memoryUsage",
                 "title": "Memory Usage (Clears Database)",
-                "category": "Rust Analyzer"
+                "category": "rust-analyzer"
             },
             {
                 "command": "rust-analyzer.shuffleCrateGraph",
                 "title": "Shuffle Crate Graph",
-                "category": "Rust Analyzer"
+                "category": "rust-analyzer"
             },
             {
                 "command": "rust-analyzer.reloadWorkspace",
                 "title": "Reload workspace",
-                "category": "Rust Analyzer"
+                "category": "rust-analyzer"
             },
             {
                 "command": "rust-analyzer.reload",
                 "title": "Restart server",
-                "category": "Rust Analyzer"
+                "category": "rust-analyzer"
             },
             {
                 "command": "rust-analyzer.onEnter",
                 "title": "Enhanced enter key",
-                "category": "Rust Analyzer"
+                "category": "rust-analyzer"
             },
             {
                 "command": "rust-analyzer.ssr",
                 "title": "Structural Search Replace",
-                "category": "Rust Analyzer"
+                "category": "rust-analyzer"
             },
             {
                 "command": "rust-analyzer.serverVersion",
                 "title": "Show RA Version",
-                "category": "Rust Analyzer"
+                "category": "rust-analyzer"
             },
             {
                 "command": "rust-analyzer.toggleInlayHints",
                 "title": "Toggle inlay hints",
-                "category": "Rust Analyzer"
+                "category": "rust-analyzer"
             },
             {
                 "command": "rust-analyzer.openDocs",
                 "title": "Open docs under cursor",
-                "category": "Rust Analyzer"
+                "category": "rust-analyzer"
             },
             {
                 "command": "rust-analyzer.openCargoToml",
                 "title": "Open Cargo.toml",
-                "category": "Rust Analyzer"
+                "category": "rust-analyzer"
             },
             {
                 "command": "rust-analyzer.peekTests",
                 "title": "Peek related tests",
-                "category": "Rust Analyzer"
+                "category": "rust-analyzer"
             },
             {
                 "command": "rust-analyzer.moveItemUp",
                 "title": "Move item up",
-                "category": "Rust Analyzer"
+                "category": "rust-analyzer"
             },
             {
                 "command": "rust-analyzer.moveItemDown",
                 "title": "Move item down",
-                "category": "Rust Analyzer"
+                "category": "rust-analyzer"
             }
         ],
         "keybindings": [
         ],
         "configuration": {
             "type": "object",
-            "title": "Rust Analyzer",
+            "title": "rust-analyzer",
             "properties": {
                 "rust-analyzer.cargoRunner": {
                     "type": [
                     "default": false,
                     "type": "boolean"
                 },
+                "rust-analyzer.typing.continueCommentsOnNewline": {
+                    "markdownDescription": "Whether to prefix newlines after comments with the corresponding comment prefix.",
+                    "default": true,
+                    "type": "boolean"
+                },
                 "$generated-start": {},
                 "rust-analyzer.assist.expressionFillDefault": {
                     "markdownDescription": "Placeholder expression to use for missing expressions in assists.",
index b04f18890b98a0917bb7c8175e0146b8947aa0b4..1c58040d58c2b4cc4d493937d8200135d4652fa7 100644 (file)
@@ -16,9 +16,13 @@ export class Config {
     readonly extensionId = "rust-lang.rust-analyzer";
 
     readonly rootSection = "rust-analyzer";
-    private readonly requiresWorkspaceReloadOpts = ["serverPath", "server"].map(
-        (opt) => `${this.rootSection}.${opt}`
-    );
+    private readonly requiresWorkspaceReloadOpts = [
+        "serverPath",
+        "server",
+        // FIXME: This shouldn't be here, changing this setting should reload
+        // `continueCommentsOnNewline` behavior without restart
+        "typing",
+    ].map((opt) => `${this.rootSection}.${opt}`);
     private readonly requiresReloadOpts = [
         "cargo",
         "procMacro",
@@ -140,6 +144,10 @@ export class Config {
         return this.get<boolean>("restartServerOnConfigChange");
     }
 
+    get typingContinueCommentsOnNewline() {
+        return this.get<boolean>("typing.continueCommentsOnNewline");
+    }
+
     get debug() {
         let sourceFileMap = this.get<Record<string, string> | "auto">("debug.sourceFileMap");
         if (sourceFileMap !== "auto") {
index 9ae20ddc4ac4b2ffde3369721fdc92227ed9ea70..d78b711a47a8f76628569026bcf8a961367c8ab1 100644 (file)
@@ -84,7 +84,9 @@ async function tryActivate(context: vscode.ExtensionContext): Promise<RustAnalyz
 
     warnAboutExtensionConflicts();
 
-    ctx.pushCleanup(configureLanguage());
+    if (config.typingContinueCommentsOnNewline) {
+        ctx.pushCleanup(configureLanguage());
+    }
 
     vscode.workspace.onDidChangeConfiguration(
         (_) =>
index dadee43b1085cbd9bf28d4b66d2be8c967513b2d..a3fe59e946ee9be8e60789c8b016d8231c9c48b4 100644 (file)
@@ -12,7 +12,7 @@
 };
 
 mod map;
-pub use map::ArenaMap;
+pub use map::{ArenaMap, Entry, OccupiedEntry, VacantEntry};
 
 /// The raw index of a value in an arena.
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -208,6 +208,16 @@ pub const fn new() -> Arena<T> {
         Arena { data: Vec::new() }
     }
 
+    /// Create a new empty arena with specific capacity.
+    ///
+    /// ```
+    /// let arena: la_arena::Arena<i32> = la_arena::Arena::with_capacity(42);
+    /// assert!(arena.is_empty());
+    /// ```
+    pub fn with_capacity(capacity: usize) -> Arena<T> {
+        Arena { data: Vec::with_capacity(capacity) }
+    }
+
     /// Empties the arena, removing all contained values.
     ///
     /// ```
index d27f086d37bf22350413667bae9b37d8fa88cff2..5f347e274500eefe7b5fcf0cda0b5d281cf8c040 100644 (file)
@@ -11,12 +11,52 @@ pub struct ArenaMap<IDX, V> {
 }
 
 impl<T, V> ArenaMap<Idx<T>, V> {
+    /// Creates a new empty map.
+    pub const fn new() -> Self {
+        Self { v: Vec::new(), _ty: PhantomData }
+    }
+
+    /// Create a new empty map with specific capacity.
+    pub fn with_capacity(capacity: usize) -> Self {
+        Self { v: Vec::with_capacity(capacity), _ty: PhantomData }
+    }
+
+    /// Reserves capacity for at least additional more elements to be inserted in the map.
+    pub fn reserve(&mut self, additional: usize) {
+        self.v.reserve(additional);
+    }
+
+    /// Clears the map, removing all elements.
+    pub fn clear(&mut self) {
+        self.v.clear();
+    }
+
+    /// Shrinks the capacity of the map as much as possible.
+    pub fn shrink_to_fit(&mut self) {
+        let min_len = self.v.iter().rposition(|slot| slot.is_some()).map_or(0, |i| i + 1);
+        self.v.truncate(min_len);
+        self.v.shrink_to_fit();
+    }
+
+    /// Returns whether the map contains a value for the specified index.
+    pub fn contains_idx(&self, idx: Idx<T>) -> bool {
+        matches!(self.v.get(Self::to_idx(idx)), Some(Some(_)))
+    }
+
+    /// Removes an index from the map, returning the value at the index if the index was previously in the map.
+    pub fn remove(&mut self, idx: Idx<T>) -> Option<V> {
+        self.v.get_mut(Self::to_idx(idx))?.take()
+    }
+
     /// Inserts a value associated with a given arena index into the map.
-    pub fn insert(&mut self, idx: Idx<T>, t: V) {
+    ///
+    /// If the map did not have this index present, None is returned.
+    /// Otherwise, the value is updated, and the old value is returned.
+    pub fn insert(&mut self, idx: Idx<T>, t: V) -> Option<V> {
         let idx = Self::to_idx(idx);
 
         self.v.resize_with((idx + 1).max(self.v.len()), || None);
-        self.v[idx] = Some(t);
+        self.v[idx].replace(t)
     }
 
     /// Returns a reference to the value associated with the provided index
@@ -46,6 +86,16 @@ pub fn iter(&self) -> impl Iterator<Item = (Idx<T>, &V)> {
         self.v.iter().enumerate().filter_map(|(idx, o)| Some((Self::from_idx(idx), o.as_ref()?)))
     }
 
+    /// Gets the given key's corresponding entry in the map for in-place manipulation.
+    pub fn entry(&mut self, idx: Idx<T>) -> Entry<'_, Idx<T>, V> {
+        let idx = Self::to_idx(idx);
+        self.v.resize_with((idx + 1).max(self.v.len()), || None);
+        match &mut self.v[idx] {
+            slot @ Some(_) => Entry::Occupied(OccupiedEntry { slot, _ty: PhantomData }),
+            slot @ None => Entry::Vacant(VacantEntry { slot, _ty: PhantomData }),
+        }
+    }
+
     fn to_idx(idx: Idx<T>) -> usize {
         u32::from(idx.into_raw()) as usize
     }
@@ -70,6 +120,119 @@ fn index_mut(&mut self, idx: Idx<V>) -> &mut T {
 
 impl<T, V> Default for ArenaMap<Idx<V>, T> {
     fn default() -> Self {
-        ArenaMap { v: Vec::new(), _ty: PhantomData }
+        Self::new()
+    }
+}
+
+impl<T, V> Extend<(Idx<V>, T)> for ArenaMap<Idx<V>, T> {
+    fn extend<I: IntoIterator<Item = (Idx<V>, T)>>(&mut self, iter: I) {
+        iter.into_iter().for_each(move |(k, v)| {
+            self.insert(k, v);
+        });
+    }
+}
+
+impl<T, V> FromIterator<(Idx<V>, T)> for ArenaMap<Idx<V>, T> {
+    fn from_iter<I: IntoIterator<Item = (Idx<V>, T)>>(iter: I) -> Self {
+        let mut this = Self::new();
+        this.extend(iter);
+        this
+    }
+}
+
+/// A view into a single entry in a map, which may either be vacant or occupied.
+///
+/// This `enum` is constructed from the [`entry`] method on [`ArenaMap`].
+///
+/// [`entry`]: ArenaMap::entry
+pub enum Entry<'a, IDX, V> {
+    /// A vacant entry.
+    Vacant(VacantEntry<'a, IDX, V>),
+    /// An occupied entry.
+    Occupied(OccupiedEntry<'a, IDX, V>),
+}
+
+impl<'a, IDX, V> Entry<'a, IDX, V> {
+    /// Ensures a value is in the entry by inserting the default if empty, and returns a mutable reference to
+    /// the value in the entry.
+    pub fn or_insert(self, default: V) -> &'a mut V {
+        match self {
+            Self::Vacant(ent) => ent.insert(default),
+            Self::Occupied(ent) => ent.into_mut(),
+        }
+    }
+
+    /// Ensures a value is in the entry by inserting the result of the default function if empty, and returns
+    /// a mutable reference to the value in the entry.
+    pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
+        match self {
+            Self::Vacant(ent) => ent.insert(default()),
+            Self::Occupied(ent) => ent.into_mut(),
+        }
+    }
+
+    /// Provides in-place mutable access to an occupied entry before any potential inserts into the map.
+    pub fn and_modify<F: FnOnce(&mut V)>(mut self, f: F) -> Self {
+        if let Self::Occupied(ent) = &mut self {
+            f(ent.get_mut());
+        }
+        self
+    }
+}
+
+impl<'a, IDX, V> Entry<'a, IDX, V>
+where
+    V: Default,
+{
+    /// Ensures a value is in the entry by inserting the default value if empty, and returns a mutable reference
+    /// to the value in the entry.
+    pub fn or_default(self) -> &'a mut V {
+        self.or_insert_with(Default::default)
+    }
+}
+
+/// A view into an vacant entry in a [`ArenaMap`]. It is part of the [`Entry`] enum.
+pub struct VacantEntry<'a, IDX, V> {
+    slot: &'a mut Option<V>,
+    _ty: PhantomData<IDX>,
+}
+
+impl<'a, IDX, V> VacantEntry<'a, IDX, V> {
+    /// Sets the value of the entry with the `VacantEntry`’s key, and returns a mutable reference to it.
+    pub fn insert(self, value: V) -> &'a mut V {
+        self.slot.insert(value)
+    }
+}
+
+/// A view into an occupied entry in a [`ArenaMap`]. It is part of the [`Entry`] enum.
+pub struct OccupiedEntry<'a, IDX, V> {
+    slot: &'a mut Option<V>,
+    _ty: PhantomData<IDX>,
+}
+
+impl<'a, IDX, V> OccupiedEntry<'a, IDX, V> {
+    /// Gets a reference to the value in the entry.
+    pub fn get(&self) -> &V {
+        self.slot.as_ref().expect("Occupied")
+    }
+
+    /// Gets a mutable reference to the value in the entry.
+    pub fn get_mut(&mut self) -> &mut V {
+        self.slot.as_mut().expect("Occupied")
+    }
+
+    /// Converts the entry into a mutable reference to its value.
+    pub fn into_mut(self) -> &'a mut V {
+        self.slot.as_mut().expect("Occupied")
+    }
+
+    /// Sets the value of the entry with the `OccupiedEntry`’s key, and returns the entry’s old value.
+    pub fn insert(&mut self, value: V) -> V {
+        self.slot.replace(value).expect("Occupied")
+    }
+
+    /// Takes the value of the entry out of the map, and returns it.
+    pub fn remove(self) -> V {
+        self.slot.take().expect("Occupied")
     }
 }
index 1c5fc64c2417e993b4f09f50f5269c3f58609b06..eda8fceef05ba2aa78da842a18f53be5987037bf 100644 (file)
@@ -77,18 +77,12 @@ pub(crate) fn run(self, sh: &Shell) -> anyhow::Result<()> {
         cmd!(sh, "git switch master").run()?;
         cmd!(sh, "git fetch upstream").run()?;
         cmd!(sh, "git reset --hard upstream/master").run()?;
-        cmd!(sh, "git submodule update --recursive").run()?;
 
         let date = date_iso(sh)?;
         let branch = format!("rust-analyzer-{date}");
         cmd!(sh, "git switch -c {branch}").run()?;
-        {
-            let _dir = sh.push_dir("src/tools/rust-analyzer");
-            cmd!(sh, "git fetch origin").run()?;
-            cmd!(sh, "git reset --hard origin/release").run()?;
-        }
-        cmd!(sh, "git add src/tools/rust-analyzer").run()?;
-        cmd!(sh, "git commit -m':arrow_up: rust-analyzer'").run()?;
+        cmd!(sh, "git subtree pull -m ':arrow_up: rust-analyzer' -P src/tools/rust-analyzer rust-analyzer release").run()?;
+
         if !self.dry_run {
             cmd!(sh, "git push -u origin {branch}").run()?;
             cmd!(
index 00281bf8f014a031589c236f8c3395414f27f5e5..b1d8b86496ad0fc630282192239f0fafa9312d8d 100644 (file)
@@ -79,11 +79,10 @@ crossbeam-utils = { version = "0.8.0", features = ["nightly"] }
 libc = { version = "0.2.79", features = ["align"] }
 # Ensure default features of libz-sys, which are disabled in some scenarios.
 libz-sys = { version = "1.1.2" }
-
-# looks like the only user of deprecated `use_std` feature is `combine`, so this
-# can be removed if/when https://github.com/Marwes/combine/pull/348 be merged and released.
+# The only user of memchr's deprecated `use_std` feature is `combine`, so this can be
+# removed if/when https://github.com/Marwes/combine/pull/348 is merged and released.
 memchr = { version = "2.5", features = ["std", "use_std"] }
-# same for regex
+# Ensure default features of regex, which are disabled in some scenarios.
 regex = { version = "1.5.6" }
 proc-macro2 = { version = "1", features = ["default"] }
 quote = { version = "1", features = ["default"] }
index a5121850369151582fc62858909e07febfa49f4e..70d5f94472f6b598829a7256a47e95c642a0d2c6 100644 (file)
@@ -201,6 +201,19 @@ async function main(argv) {
         process.setMaxListeners(opts["jobs"] + 1);
     }
 
+    // We catch this "event" to display a nicer message in case of unexpected exit (because of a
+    // missing `--no-sandbox`).
+    const exitHandling = (code) => {
+        if (!opts["no_sandbox"]) {
+            console.log("");
+            console.log(
+                "`browser-ui-test` crashed unexpectedly. Please try again with adding `--test-args \
+--no-sandbox` at the end. For example: `x.py test src/test/rustdoc-gui --test-args --no-sandbox`");
+            console.log("");
+        }
+    };
+    process.on('exit', exitHandling);
+
     const tests_queue = [];
     let results = {
         successful: [],
@@ -247,6 +260,9 @@ async function main(argv) {
     }
     status_bar.finish();
 
+    // We don't need this listener anymore.
+    process.removeListener("exit", exitHandling);
+
     if (debug) {
         results.successful.sort(by_filename);
         results.successful.forEach(r => {
index e26e24ec55ad6c40fe495ddc41c57cba89e218c5..fcc02eca42987c47c2d3f4393ce31253a81a3677 100644 (file)
@@ -145,7 +145,7 @@ fn is_tup_field_access(expr: &ast::Expr) -> bool {
 
     fn from_ast(context: &RewriteContext<'_>, expr: &ast::Expr) -> (ChainItemKind, Span) {
         let (kind, span) = match expr.kind {
-            ast::ExprKind::MethodCall(ref segment, ref expressions, _) => {
+            ast::ExprKind::MethodCall(ref segment, ref receiver, ref expressions, _) => {
                 let types = if let Some(ref generic_args) = segment.args {
                     if let ast::GenericArgs::AngleBracketed(ref data) = **generic_args {
                         data.args
@@ -163,7 +163,7 @@ fn from_ast(context: &RewriteContext<'_>, expr: &ast::Expr) -> (ChainItemKind, S
                 } else {
                     vec![]
                 };
-                let span = mk_sp(expressions[0].span.hi(), expr.span.hi());
+                let span = mk_sp(receiver.span.hi(), expr.span.hi());
                 let kind = ChainItemKind::MethodCall(segment.clone(), types, expressions.clone());
                 (kind, span)
             }
@@ -253,7 +253,7 @@ fn rewrite_method_call(
             format!("::<{}>", type_list.join(", "))
         };
         let callee_str = format!(".{}{}", rewrite_ident(context, method_name), type_str);
-        rewrite_call(context, &callee_str, &args[1..], span, shape)
+        rewrite_call(context, &callee_str, &args, span, shape)
     }
 }
 
@@ -400,8 +400,8 @@ fn make_subexpr_list(expr: &ast::Expr, context: &RewriteContext<'_>) -> Vec<ast:
     // is a try! macro, we'll convert it to shorthand when the option is set.
     fn pop_expr_chain(expr: &ast::Expr, context: &RewriteContext<'_>) -> Option<ast::Expr> {
         match expr.kind {
-            ast::ExprKind::MethodCall(_, ref expressions, _) => {
-                Some(Self::convert_try(&expressions[0], context))
+            ast::ExprKind::MethodCall(_, ref receiver, _, _) => {
+                Some(Self::convert_try(&receiver, context))
             }
             ast::ExprKind::Field(ref subexpr, _)
             | ast::ExprKind::Try(ref subexpr)
index 9615c4db6b4b51c4fc09fcdaa8f250539ee71415..025b8ab9f0af5f620809e1121c22c7ac224e96c1 100644 (file)
@@ -96,6 +96,8 @@ fn check_dir(dir: &Path) -> FilesystemSupport {
 
     #[cfg(unix)]
     pub fn check(path: &Path, bad: &mut bool) {
+        use std::ffi::OsStr;
+
         const ALLOWED: &[&str] = &["configure"];
 
         crate::walk_no_read(
@@ -117,9 +119,9 @@ pub fn check(path: &Path, bad: &mut bool) {
             },
             &mut |entry| {
                 let file = entry.path();
-                let filename = file.file_name().unwrap().to_string_lossy();
-                let extensions = [".py", ".sh"];
-                if extensions.iter().any(|e| filename.ends_with(e)) {
+                let extension = file.extension();
+                let scripts = ["py", "sh", "ps1"];
+                if scripts.into_iter().any(|e| extension == Some(OsStr::new(e))) {
                     return;
                 }
 
index 57d548f313dae1bdfe289d00a77d90d9cb583fd9..9187c3551d7de3f1427891fd2342739c942596dc 100644 (file)
@@ -41,9 +41,9 @@ fn python() -> &'static str {
     } else if python2 {
         PYTHON2
     } else {
-        // We would have returned early if we found that python is installed ...
-        // maybe this should panic with an error instead?
-        PYTHON
+        // Python was not found on path, so exit
+        eprintln!("Unable to find python in your PATH. Please check it is installed.");
+        process::exit(1);
     }
 }
 
index 9405730420ffc3443e5844a50c6a49b3c5a9ea93..902c74186fb67b2da9048de7ae11563048215663 100644 (file)
@@ -1 +1 @@
-1.64.0
+1.65.0
diff --git a/x.ps1 b/x.ps1
new file mode 100755 (executable)
index 0000000..1225443
--- /dev/null
+++ b/x.ps1
@@ -0,0 +1,28 @@
+#!/usr/bin/env pwsh
+
+# See x.sh for why these scripts exist.
+
+$xpy = Join-Path $PSScriptRoot x.py
+# Start-Process for some reason splits arguments on spaces. (Isn't powershell supposed to be simpler than bash?)
+# Double-quote all the arguments so it doesn't do that.
+$xpy_args = @("""$xpy""")
+foreach ($arg in $args) {
+    $xpy_args += """$arg"""
+}
+
+foreach ($python in "py", "python3", "python", "python2") {
+    # NOTE: this only tests that the command exists in PATH, not that it's actually
+    # executable. The latter is not possible in a portable way, see
+    # https://github.com/PowerShell/PowerShell/issues/12625.
+    if (Get-Command $python -ErrorAction SilentlyContinue) {
+        if ($python -eq "py") {
+            # Use python3, not python2
+            $xpy_args = @("-3") + $xpy_args
+        }
+        $process = Start-Process -NoNewWindow -Wait -PassThru $python $xpy_args
+        Exit $process.ExitCode
+    }
+}
+
+Write-Error "${PSCommandPath}: error: did not find python installed"
+Exit 1
diff --git a/x.py b/x.py
index 0289056fdcb163889cd3d59b24e6e20afbbd2e30..6c68907c581457c200050e841768c5763e06d6b3 100755 (executable)
--- a/x.py
+++ b/x.py
@@ -1,36 +1,16 @@
-#!/usr/bin/env bash
+#!/usr/bin/env python3
+# Some systems don't have `python3` in their PATH. This isn't supported by x.py directly;
+# they should use `x.sh` or `x.ps1` instead.
 
-# Modern Linux and macOS systems commonly only have a thing called `python3` and
-# not `python`, while Windows commonly does not have `python3`, so we cannot
-# directly use python in the shebang and have it consistently work. Instead we
-# embed some bash to look for a python to run the rest of the script.
-#
-# On Windows, `py -3` sometimes works. We need to try it first because `python3`
-# sometimes tries to launch the app store on Windows.
-'''':
-for PYTHON in "py -3" python3 python python2; do
-    if command -v $PYTHON >/dev/null; then
-        exec $PYTHON "$0" "$@"
-        break
-    fi
-done
-echo "$0: error: did not find python installed" >&2
-exit 1
-'''
-
-# The rest of this file is Python.
-#
 # This file is only a "symlink" to bootstrap.py, all logic should go there.
 
 import os
 import sys
 
 # If this is python2, check if python3 is available and re-execute with that
-# interpreter.
+# interpreter. Only python3 allows downloading CI LLVM.
 #
-# `./x.py` would not normally benefit from this because the bash above tries
-# python3 before 2, but this matters if someone ran `python x.py` and their
-# system's `python` is python2.
+# This matters if someone's system `python` is python2.
 if sys.version_info.major < 3:
     try:
         os.execvp("py", ["py", "-3"] + sys.argv)
diff --git a/x.sh b/x.sh
new file mode 100755 (executable)
index 0000000..704d0f7
--- /dev/null
+++ b/x.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+# Modern Linux and macOS systems commonly only have a thing called `python3` and
+# not `python`, while Windows commonly does not have `python3`, so we cannot
+# directly use python in the x.py shebang and have it consistently work. Instead we
+# have a shell script to look for a python to run x.py.
+
+set -eu
+
+realpath() {
+    if [ -d "$1" ]; then
+        CDPATH='' command cd "$1" && pwd -P   
+    else
+        echo "$(realpath "$(dirname "$1")")/$(basename "$1")"
+    fi
+}
+
+xpy=$(dirname "$(realpath "$0")")/x.py
+
+# On Windows, `py -3` sometimes works. We need to try it first because `python3`
+# sometimes tries to launch the app store on Windows.
+for SEARCH_PYTHON in py python3 python python2; do
+    if python=$(command -v $SEARCH_PYTHON) && [ -x "$python" ]; then
+        if [ $SEARCH_PYTHON = py ]; then
+            extra_arg="-3"
+        else
+            extra_arg=""
+        fi
+        exec "$python" $extra_arg "$xpy" "$@"
+    fi
+done
+echo "$0: error: did not find python installed" >&2
+exit 1