]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #105837 - compiler-errors:issue-105728, r=estebank
authorMatthias Krüger <matthias.krueger@famsik.de>
Thu, 22 Dec 2022 00:01:12 +0000 (01:01 +0100)
committerGitHub <noreply@github.com>
Thu, 22 Dec 2022 00:01:12 +0000 (01:01 +0100)
Don't ICE in `check_must_not_suspend_ty` for mismatched tuple arity

These expressions are just used for their spans, so make it best-effort here.

Fixes #105728

618 files changed:
.github/workflows/ci.yml
Cargo.lock
compiler/rustc_abi/src/lib.rs
compiler/rustc_ast/src/ast.rs
compiler/rustc_ast/src/node_id.rs
compiler/rustc_ast_lowering/src/expr.rs
compiler/rustc_ast_lowering/src/item.rs
compiler/rustc_ast_lowering/src/lib.rs
compiler/rustc_ast_passes/src/ast_validation.rs
compiler/rustc_borrowck/src/constraints/graph.rs
compiler/rustc_borrowck/src/constraints/mod.rs
compiler/rustc_borrowck/src/dataflow.rs
compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
compiler/rustc_borrowck/src/diagnostics/region_errors.rs
compiler/rustc_borrowck/src/lib.rs
compiler/rustc_borrowck/src/location.rs
compiler/rustc_borrowck/src/member_constraints.rs
compiler/rustc_borrowck/src/region_infer/mod.rs
compiler/rustc_borrowck/src/region_infer/values.rs
compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs
compiler/rustc_borrowck/src/type_check/mod.rs
compiler/rustc_builtin_macros/src/global_allocator.rs
compiler/rustc_builtin_macros/src/test.rs
compiler/rustc_codegen_llvm/src/asm.rs
compiler/rustc_codegen_llvm/src/attributes.rs
compiler/rustc_codegen_llvm/src/back/lto.rs
compiler/rustc_codegen_llvm/src/builder.rs
compiler/rustc_codegen_llvm/src/context.rs
compiler/rustc_codegen_llvm/src/errors.rs
compiler/rustc_codegen_llvm/src/va_arg.rs
compiler/rustc_codegen_ssa/src/back/archive.rs
compiler/rustc_codegen_ssa/src/back/link.rs
compiler/rustc_codegen_ssa/src/back/linker.rs
compiler/rustc_codegen_ssa/src/glue.rs
compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
compiler/rustc_const_eval/src/const_eval/error.rs
compiler/rustc_const_eval/src/const_eval/eval_queries.rs
compiler/rustc_const_eval/src/const_eval/machine.rs
compiler/rustc_const_eval/src/interpret/cast.rs
compiler/rustc_const_eval/src/interpret/eval_context.rs
compiler/rustc_const_eval/src/interpret/machine.rs
compiler/rustc_const_eval/src/interpret/memory.rs
compiler/rustc_const_eval/src/interpret/operand.rs
compiler/rustc_const_eval/src/interpret/operator.rs
compiler/rustc_const_eval/src/interpret/place.rs
compiler/rustc_const_eval/src/util/might_permit_raw_init.rs
compiler/rustc_data_structures/Cargo.toml
compiler/rustc_data_structures/src/graph/dominators/mod.rs
compiler/rustc_error_codes/src/error_codes.rs
compiler/rustc_error_codes/src/error_codes/E0158.md
compiler/rustc_error_codes/src/error_codes/E0320.md [new file with mode: 0644]
compiler/rustc_error_codes/src/error_codes/E0377.md [new file with mode: 0644]
compiler/rustc_error_codes/src/error_codes/E0457.md [new file with mode: 0644]
compiler/rustc_error_codes/src/error_codes/E0460.md [new file with mode: 0644]
compiler/rustc_error_codes/src/error_codes/E0472.md [new file with mode: 0644]
compiler/rustc_error_messages/locales/en-US/codegen_llvm.ftl
compiler/rustc_error_messages/locales/en-US/metadata.ftl
compiler/rustc_error_messages/locales/en-US/mir_build.ftl [new file with mode: 0644]
compiler/rustc_error_messages/locales/en-US/monomorphize.ftl
compiler/rustc_error_messages/locales/en-US/session.ftl
compiler/rustc_error_messages/src/lib.rs
compiler/rustc_expand/src/mbe/macro_check.rs
compiler/rustc_expand/src/mbe/macro_rules.rs
compiler/rustc_feature/src/accepted.rs
compiler/rustc_feature/src/active.rs
compiler/rustc_hir/src/hir_id.rs
compiler/rustc_hir/src/lang_items.rs
compiler/rustc_hir_analysis/src/astconv/mod.rs
compiler/rustc_hir_analysis/src/check/check.rs
compiler/rustc_hir_analysis/src/check/compare_method.rs
compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
compiler/rustc_hir_analysis/src/collect.rs
compiler/rustc_hir_typeck/src/callee.rs
compiler/rustc_hir_typeck/src/cast.rs
compiler/rustc_hir_typeck/src/closure.rs
compiler/rustc_hir_typeck/src/coercion.rs
compiler/rustc_hir_typeck/src/demand.rs
compiler/rustc_hir_typeck/src/expr.rs
compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs
compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs
compiler/rustc_hir_typeck/src/method/mod.rs
compiler/rustc_hir_typeck/src/method/suggest.rs
compiler/rustc_hir_typeck/src/pat.rs
compiler/rustc_incremental/src/assert_dep_graph.rs
compiler/rustc_index/src/vec/tests.rs
compiler/rustc_infer/src/infer/error_reporting/mod.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs
compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
compiler/rustc_infer/src/infer/mod.rs
compiler/rustc_infer/src/infer/outlives/obligations.rs
compiler/rustc_infer/src/infer/outlives/verify.rs
compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
compiler/rustc_infer/src/infer/undo_log.rs
compiler/rustc_infer/src/traits/project.rs
compiler/rustc_interface/src/queries.rs
compiler/rustc_interface/src/tests.rs
compiler/rustc_lint/src/builtin.rs
compiler/rustc_lint/src/context.rs
compiler/rustc_lint/src/for_loops_over_fallibles.rs
compiler/rustc_lint/src/levels.rs
compiler/rustc_lint/src/nonstandard_style.rs
compiler/rustc_lint/src/unused.rs
compiler/rustc_lint_defs/src/builtin.rs
compiler/rustc_macros/src/diagnostics/diagnostic.rs
compiler/rustc_macros/src/newtype.rs
compiler/rustc_metadata/src/creader.rs
compiler/rustc_metadata/src/errors.rs
compiler/rustc_metadata/src/rmeta/encoder.rs
compiler/rustc_middle/src/arena.rs
compiler/rustc_middle/src/middle/privacy.rs
compiler/rustc_middle/src/middle/region.rs
compiler/rustc_middle/src/mir/coverage.rs
compiler/rustc_middle/src/mir/mod.rs
compiler/rustc_middle/src/mir/mono.rs
compiler/rustc_middle/src/mir/pretty.rs
compiler/rustc_middle/src/mir/query.rs
compiler/rustc_middle/src/mir/tcx.rs
compiler/rustc_middle/src/query/keys.rs
compiler/rustc_middle/src/thir.rs
compiler/rustc_middle/src/ty/codec.rs
compiler/rustc_middle/src/ty/consts.rs
compiler/rustc_middle/src/ty/context.rs
compiler/rustc_middle/src/ty/fast_reject.rs
compiler/rustc_middle/src/ty/flags.rs
compiler/rustc_middle/src/ty/fold.rs
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/relate.rs
compiler/rustc_middle/src/ty/structural_impls.rs
compiler/rustc_middle/src/ty/sty.rs
compiler/rustc_middle/src/ty/subst.rs
compiler/rustc_middle/src/ty/typeck_results.rs [new file with mode: 0644]
compiler/rustc_middle/src/ty/util.rs
compiler/rustc_middle/src/ty/vtable.rs
compiler/rustc_mir_build/Cargo.toml
compiler/rustc_mir_build/src/build/custom/mod.rs
compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
compiler/rustc_mir_build/src/build/expr/as_constant.rs
compiler/rustc_mir_build/src/build/matches/mod.rs
compiler/rustc_mir_build/src/build/matches/test.rs
compiler/rustc_mir_build/src/build/mod.rs
compiler/rustc_mir_build/src/build/scope.rs
compiler/rustc_mir_build/src/check_unsafety.rs
compiler/rustc_mir_build/src/errors.rs [new file with mode: 0644]
compiler/rustc_mir_build/src/lib.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/mod.rs
compiler/rustc_mir_dataflow/src/move_paths/mod.rs
compiler/rustc_mir_transform/src/check_unsafety.rs
compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
compiler/rustc_mir_transform/src/const_prop.rs
compiler/rustc_mir_transform/src/coverage/graph.rs
compiler/rustc_mir_transform/src/dataflow_const_prop.rs
compiler/rustc_mir_transform/src/dest_prop.rs
compiler/rustc_mir_transform/src/lib.rs
compiler/rustc_mir_transform/src/normalize_array_len.rs
compiler/rustc_mir_transform/src/remove_false_edges.rs [deleted file]
compiler/rustc_mir_transform/src/sroa.rs
compiler/rustc_monomorphize/src/collector.rs
compiler/rustc_monomorphize/src/errors.rs
compiler/rustc_monomorphize/src/partitioning/mod.rs
compiler/rustc_parse/src/parser/mod.rs
compiler/rustc_parse/src/parser/path.rs
compiler/rustc_passes/src/dead.rs
compiler/rustc_passes/src/hir_stats.rs
compiler/rustc_passes/src/lang_items.rs
compiler/rustc_passes/src/liveness.rs
compiler/rustc_query_impl/src/on_disk_cache.rs
compiler/rustc_query_system/src/dep_graph/graph.rs
compiler/rustc_query_system/src/dep_graph/serialized.rs
compiler/rustc_resolve/src/build_reduced_graph.rs
compiler/rustc_resolve/src/late/diagnostics.rs
compiler/rustc_resolve/src/lib.rs
compiler/rustc_session/src/errors.rs
compiler/rustc_session/src/filesearch.rs
compiler/rustc_session/src/options.rs
compiler/rustc_session/src/session.rs
compiler/rustc_span/Cargo.toml
compiler/rustc_span/src/def_id.rs
compiler/rustc_span/src/hygiene.rs
compiler/rustc_span/src/lib.rs
compiler/rustc_span/src/source_map.rs
compiler/rustc_span/src/symbol.rs
compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
compiler/rustc_target/src/abi/mod.rs
compiler/rustc_trait_selection/src/traits/auto_trait.rs
compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
compiler/rustc_trait_selection/src/traits/wf.rs
compiler/rustc_transmute/src/layout/nfa.rs
compiler/rustc_transmute/src/maybe_transmutable/query_context.rs
compiler/rustc_type_ir/src/lib.rs
library/alloc/src/boxed.rs
library/alloc/src/collections/vec_deque/mod.rs
library/alloc/src/fmt.rs
library/alloc/src/rc.rs
library/alloc/src/sync.rs
library/core/src/array/mod.rs
library/core/src/cell.rs
library/core/src/convert/num.rs
library/core/src/ffi/mod.rs
library/core/src/fmt/mod.rs
library/core/src/future/mod.rs
library/core/src/intrinsics/mir.rs
library/core/src/iter/traits/iterator.rs
library/core/src/marker.rs
library/core/src/ops/mod.rs
library/core/src/ops/unsize.rs
library/core/src/pin.rs
library/core/src/ptr/non_null.rs
library/core/src/slice/mod.rs
library/core/src/task/wake.rs
library/std/src/fs/tests.rs
library/std/src/path.rs
library/std/src/process.rs
library/std/src/sys/unix/fs.rs
library/std/src/sys/unix/pipe.rs
library/std/src/sys/unix/process/process_fuchsia.rs
library/std/src/sys/unix/process/process_unix.rs
library/std/src/sys/unix/process/process_unsupported.rs
library/std/src/sys/unix/process/process_vxworks.rs
library/std/src/sys/unsupported/mod.rs
library/std/src/sys/unsupported/once.rs [new file with mode: 0644]
library/std/src/sys/unsupported/pipe.rs
library/std/src/sys/unsupported/process.rs
library/std/src/sys/wasi/mod.rs
library/std/src/sys/wasm/mod.rs
library/std/src/sys/windows/pipe.rs
library/std/src/sys/windows/process.rs
library/std/src/sys_common/once/generic.rs [deleted file]
library/std/src/sys_common/once/mod.rs
library/std/src/sys_common/once/queue.rs [new file with mode: 0644]
library/std/src/sys_common/process.rs
library/test/src/cli.rs
library/test/src/formatters/json.rs
library/test/src/formatters/mod.rs
library/test/src/formatters/pretty.rs
library/test/src/lib.rs
library/test/src/test_result.rs
library/test/src/time.rs
src/bootstrap/builder.rs
src/bootstrap/config.rs
src/bootstrap/flags.rs
src/bootstrap/format.rs
src/bootstrap/install.rs
src/bootstrap/lib.rs
src/bootstrap/mk/Makefile.in
src/bootstrap/native.rs
src/bootstrap/setup.rs
src/ci/docker/host-x86_64/mingw-check/Dockerfile
src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
src/ci/github-actions/ci.yml
src/ci/run.sh
src/doc/nomicon
src/doc/rust-by-example
src/doc/rustc-dev-guide
src/doc/rustc/src/exploit-mitigations.md
src/doc/rustc/src/linker-plugin-lto.md
src/doc/rustc/src/platform-support/android.md
src/doc/rustc/src/platform-support/armv6k-nintendo-3ds.md
src/doc/rustc/src/platform-support/fuchsia.md
src/doc/rustc/src/targets/custom.md
src/doc/unstable-book/src/compiler-flags/branch-protection.md
src/doc/unstable-book/src/compiler-flags/control-flow-guard.md
src/doc/unstable-book/src/compiler-flags/sanitizer.md
src/doc/unstable-book/src/compiler-flags/virtual-function-elimination.md
src/doc/unstable-book/src/language-features/auto-traits.md
src/doc/unstable-book/src/language-features/unboxed-closures.md
src/doc/unstable-book/src/library-features/default-free-fn.md
src/doc/unstable-book/src/library-features/fn-traits.md
src/librustdoc/clean/cfg.rs
src/librustdoc/clean/inline.rs
src/librustdoc/clean/types.rs
src/librustdoc/html/markdown.rs
src/librustdoc/html/render/mod.rs
src/librustdoc/html/static/css/rustdoc.css
src/librustdoc/html/static/css/settings.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/js/source-script.js
src/librustdoc/html/templates/page.html
src/test/assembly/x86_64-no-jump-tables.rs [new file with mode: 0644]
src/test/codegen/dst-vtable-align-nonzero.rs
src/test/codegen/dst-vtable-size-range.rs [new file with mode: 0644]
src/test/codegen/enum-match.rs
src/test/codegen/no-jump-tables.rs [new file with mode: 0644]
src/test/mir-opt/building/custom/enums.rs [new file with mode: 0644]
src/test/mir-opt/building/custom/enums.set_discr.built.after.mir [new file with mode: 0644]
src/test/mir-opt/building/custom/enums.set_discr_repr.built.after.mir [new file with mode: 0644]
src/test/mir-opt/building/custom/enums.switch_bool.built.after.mir [new file with mode: 0644]
src/test/mir-opt/building/custom/enums.switch_option.built.after.mir [new file with mode: 0644]
src/test/mir-opt/building/custom/enums.switch_option_repr.built.after.mir [new file with mode: 0644]
src/test/mir-opt/building/custom/projections.rs [new file with mode: 0644]
src/test/mir-opt/building/custom/projections.set.built.after.mir [new file with mode: 0644]
src/test/mir-opt/building/custom/projections.simple_index.built.after.mir [new file with mode: 0644]
src/test/mir-opt/building/custom/projections.tuples.built.after.mir [new file with mode: 0644]
src/test/mir-opt/building/custom/projections.unions.built.after.mir [new file with mode: 0644]
src/test/mir-opt/building/custom/projections.unwrap.built.after.mir [new file with mode: 0644]
src/test/mir-opt/building/custom/projections.unwrap_deref.built.after.mir [new file with mode: 0644]
src/test/mir-opt/building/custom/references.raw_pointer.built.after.mir [new file with mode: 0644]
src/test/mir-opt/building/custom/references.rs
src/test/mir-opt/building/custom/terminators.assert_nonzero.built.after.mir [new file with mode: 0644]
src/test/mir-opt/building/custom/terminators.direct_call.built.after.mir [new file with mode: 0644]
src/test/mir-opt/building/custom/terminators.drop_first.built.after.mir [new file with mode: 0644]
src/test/mir-opt/building/custom/terminators.drop_second.built.after.mir [new file with mode: 0644]
src/test/mir-opt/building/custom/terminators.indirect_call.built.after.mir [new file with mode: 0644]
src/test/mir-opt/building/custom/terminators.rs [new file with mode: 0644]
src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff
src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff
src/test/mir-opt/dest-prop/unreachable.f.DestinationPropagation.diff [new file with mode: 0644]
src/test/mir-opt/dest-prop/unreachable.rs [new file with mode: 0644]
src/test/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff
src/test/mir-opt/lower_array_len_e2e.rs
src/test/mir-opt/remove_fake_borrows.match_guard.CleanupNonCodegenStatements.diff [deleted file]
src/test/mir-opt/remove_fake_borrows.match_guard.CleanupPostBorrowck.diff [new file with mode: 0644]
src/test/mir-opt/remove_fake_borrows.rs
src/test/run-make-fulldeps/core-no-fp-fmt-parse/Makefile
src/test/rustdoc-gui/code-sidebar-toggle.goml
src/test/rustdoc-gui/codeblock-sub.goml [new file with mode: 0644]
src/test/rustdoc-gui/codeblock-tooltip.goml
src/test/rustdoc-gui/cursor.goml
src/test/rustdoc-gui/scrape-examples-layout.goml [new file with mode: 0644]
src/test/rustdoc-gui/sidebar-source-code-display.goml
src/test/rustdoc-gui/source-code-page.goml
src/test/rustdoc-gui/src/scrape_examples/examples/check-many-1.rs
src/test/rustdoc-gui/src/scrape_examples/examples/check-many-2.rs
src/test/rustdoc-gui/src/scrape_examples/examples/check-many-3.rs
src/test/rustdoc-gui/src/scrape_examples/examples/check-many-4.rs
src/test/rustdoc-gui/src/scrape_examples/examples/check-many-5.rs
src/test/rustdoc-gui/src/scrape_examples/examples/check-many-6.rs
src/test/rustdoc-gui/src/scrape_examples/examples/check-many-7.rs
src/test/rustdoc-gui/src/test_docs/lib.rs
src/test/rustdoc-gui/struct-fields.goml
src/test/rustdoc-ui/z-help.stdout
src/test/rustdoc/read-more-unneeded.rs [new file with mode: 0644]
src/test/rustdoc/trait-impl.rs
src/test/ui-fulldeps/macro-crate-rlib.stderr
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/basic.stderr
src/test/ui/asm/bad-arch.mirunsafeck.stderr
src/test/ui/asm/bad-arch.thirunsafeck.stderr
src/test/ui/associated-inherent-types/style.rs [new file with mode: 0644]
src/test/ui/associated-inherent-types/style.stderr [new file with mode: 0644]
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-unconstrained.stderr
src/test/ui/async-await/async-await-let-else.drop-tracking.stderr
src/test/ui/async-await/in-trait/bad-signatures.rs [new file with mode: 0644]
src/test/ui/async-await/in-trait/bad-signatures.stderr [new file with mode: 0644]
src/test/ui/async-await/issue-68112.drop_tracking.stderr
src/test/ui/async-await/issue-68112.no_drop_tracking.stderr
src/test/ui/async-await/issue-69446-fnmut-capture.stderr
src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr
src/test/ui/async-await/issues/issue-102206.rs [new file with mode: 0644]
src/test/ui/async-await/issues/issue-102206.stderr [new file with mode: 0644]
src/test/ui/async-await/partial-drop-partial-reinit.drop_tracking.stderr
src/test/ui/async-await/partial-drop-partial-reinit.no_drop_tracking.stderr
src/test/ui/borrowck/issue-103095.rs [new file with mode: 0644]
src/test/ui/codegen/issue-55976.rs [new file with mode: 0644]
src/test/ui/confuse-field-and-method/issue-33784.stderr
src/test/ui/const-generics/defaults/complex-unord-param.min.stderr [deleted file]
src/test/ui/const-generics/issue-105689.rs [new file with mode: 0644]
src/test/ui/const-generics/type-after-const-ok.min.stderr [deleted file]
src/test/ui/const-ptr/forbidden_slices.32bit.stderr
src/test/ui/const-ptr/forbidden_slices.64bit.stderr
src/test/ui/const-ptr/forbidden_slices.rs
src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr
src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr
src/test/ui/consts/const-eval/ub-ref-ptr.rs
src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr
src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr
src/test/ui/consts/const-eval/ub-wide-ptr.rs
src/test/ui/consts/copy-intrinsic.rs
src/test/ui/consts/extra-const-ub/detect-extra-ub.rs
src/test/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr
src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.stderr
src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.stderr
src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr
src/test/ui/dyn-star/dyn-to-rigid.rs [new file with mode: 0644]
src/test/ui/dyn-star/dyn-to-rigid.stderr [new file with mode: 0644]
src/test/ui/empty/empty-struct-braces-expr.stderr
src/test/ui/error-codes/E0057.stderr
src/test/ui/error-codes/E0377.rs [new file with mode: 0644]
src/test/ui/error-codes/E0377.stderr [new file with mode: 0644]
src/test/ui/error-codes/E0790.stderr
src/test/ui/feature-gates/feature-gate-unsized_fn_params.rs
src/test/ui/feature-gates/feature-gate-unsized_fn_params.stderr
src/test/ui/feature-gates/feature-gate-unsized_locals.stderr
src/test/ui/functions-closures/fn-help-with-err.stderr
src/test/ui/generator/ref-upvar-not-send.rs [new file with mode: 0644]
src/test/ui/generator/ref-upvar-not-send.stderr [new file with mode: 0644]
src/test/ui/higher-rank-trait-bounds/issue-30786.stderr
src/test/ui/higher-rank-trait-bounds/issue-58451.stderr
src/test/ui/higher-rank-trait-bounds/issue-62203-hrtb-ice.stderr
src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr
src/test/ui/impl-trait/no-method-suggested-traits.stderr
src/test/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.rs [new file with mode: 0644]
src/test/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.stderr [new file with mode: 0644]
src/test/ui/implied-bounds/impl-implied-bounds-compatibility.rs [new file with mode: 0644]
src/test/ui/implied-bounds/impl-implied-bounds-compatibility.stderr [new file with mode: 0644]
src/test/ui/inference/issue-80816.rs [new file with mode: 0644]
src/test/ui/inference/issue-80816.stderr [new file with mode: 0644]
src/test/ui/infinite/issue-41731-infinite-macro-print.rs [new file with mode: 0644]
src/test/ui/infinite/issue-41731-infinite-macro-print.stderr [new file with mode: 0644]
src/test/ui/infinite/issue-41731-infinite-macro-println.rs [new file with mode: 0644]
src/test/ui/infinite/issue-41731-infinite-macro-println.stderr [new file with mode: 0644]
src/test/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADTARGET.stderr
src/test/ui/invalid-compile-flags/branch-protection-missing-pac-ret.rs
src/test/ui/issues/issue-18107.stderr
src/test/ui/issues/issue-30123.stderr
src/test/ui/issues/issue-3044.stderr
src/test/ui/issues/issue-31173.stderr
src/test/ui/issues/issue-33941.rs
src/test/ui/issues/issue-33941.stderr
src/test/ui/issues/issue-41880.stderr
src/test/ui/issues/issue-42312.stderr
src/test/ui/issues/issue-5883.stderr
src/test/ui/iterators/invalid-iterator-chain.rs
src/test/ui/iterators/invalid-iterator-chain.stderr
src/test/ui/lint/lint-uppercase-variables.rs
src/test/ui/lint/lint-uppercase-variables.stderr
src/test/ui/lto/auxiliary/thinlto-dylib.rs [new file with mode: 0644]
src/test/ui/lto/issue-105637.rs [new file with mode: 0644]
src/test/ui/lto/issue-105637.run.stderr [new file with mode: 0644]
src/test/ui/methods/issues/issue-105732.rs [new file with mode: 0644]
src/test/ui/methods/issues/issue-105732.stderr [new file with mode: 0644]
src/test/ui/methods/method-not-found-generic-arg-elision.stderr
src/test/ui/mir/issue-105809.rs [new file with mode: 0644]
src/test/ui/mismatched_types/issue-36053-2.stderr
src/test/ui/missing/missing-alloc_error_handler.rs [deleted file]
src/test/ui/missing/missing-alloc_error_handler.stderr [deleted file]
src/test/ui/never_type/fallback-closure-wrap.fallback.stderr
src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr
src/test/ui/regions/closure-in-projection-issue-97405.rs
src/test/ui/regions/closure-in-projection-issue-97405.stderr
src/test/ui/resolve/issue-5035-2.stderr
src/test/ui/rfc-2632-const-trait-impl/const-impl-trait.rs [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/tilde-const-invalid-places.rs
src/test/ui/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr
src/test/ui/suggestions/clone-on-unconstrained-borrowed-type-param.fixed [new file with mode: 0644]
src/test/ui/suggestions/clone-on-unconstrained-borrowed-type-param.rs [new file with mode: 0644]
src/test/ui/suggestions/clone-on-unconstrained-borrowed-type-param.stderr [new file with mode: 0644]
src/test/ui/suggestions/enum-variant-arg-mismatch.rs [new file with mode: 0644]
src/test/ui/suggestions/enum-variant-arg-mismatch.stderr [new file with mode: 0644]
src/test/ui/suggestions/issue-104327.rs [new file with mode: 0644]
src/test/ui/suggestions/issue-104327.stderr [new file with mode: 0644]
src/test/ui/suggestions/issue-104328.rs [new file with mode: 0644]
src/test/ui/suggestions/issue-104328.stderr [new file with mode: 0644]
src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr
src/test/ui/svh/changing-crates.stderr
src/test/ui/svh/svh-change-lit.stderr
src/test/ui/svh/svh-change-significant-cfg.stderr
src/test/ui/svh/svh-change-trait-bound.stderr
src/test/ui/svh/svh-change-type-arg.stderr
src/test/ui/svh/svh-change-type-ret.stderr
src/test/ui/svh/svh-change-type-static.stderr
src/test/ui/svh/svh-use-trait.stderr
src/test/ui/traits/assoc-type-in-superbad.rs
src/test/ui/traits/assoc-type-in-superbad.stderr
src/test/ui/traits/bound/not-on-bare-trait.stderr
src/test/ui/traits/static-method-generic-inference.stderr
src/test/ui/type-alias-impl-trait/auxiliary/coherence_cross_crate_trait_decl.rs [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/coherence_cross_crate.rs [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/coherence_cross_crate.stderr [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/destructuring.rs [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/issue-57961.rs
src/test/ui/type-alias-impl-trait/issue-57961.stderr
src/test/ui/typeck/explain_clone_autoref.stderr
src/test/ui/typeck/issue-57404.rs [new file with mode: 0644]
src/test/ui/typeck/issue-57404.stderr [new file with mode: 0644]
src/test/ui/unboxed-closures/unboxed-closures-static-call-wrong-trait.stderr
src/tools/cargo
src/tools/clippy/.github/workflows/clippy_bors.yml
src/tools/clippy/CHANGELOG.md
src/tools/clippy/Cargo.toml
src/tools/clippy/book/src/README.md
src/tools/clippy/build.rs
src/tools/clippy/clippy_lints/Cargo.toml
src/tools/clippy/clippy_lints/src/almost_complete_letter_range.rs [deleted file]
src/tools/clippy/clippy_lints/src/almost_complete_range.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/box_default.rs
src/tools/clippy/clippy_lints/src/casts/mod.rs
src/tools/clippy/clippy_lints/src/declared_lints.rs
src/tools/clippy/clippy_lints/src/dereference.rs
src/tools/clippy/clippy_lints/src/derive.rs
src/tools/clippy/clippy_lints/src/disallowed_macros.rs
src/tools/clippy/clippy_lints/src/format_args.rs
src/tools/clippy/clippy_lints/src/from_over_into.rs
src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs
src/tools/clippy/clippy_lints/src/indexing_slicing.rs
src/tools/clippy/clippy_lints/src/len_zero.rs
src/tools/clippy/clippy_lints/src/lib.rs
src/tools/clippy/clippy_lints/src/loops/utils.rs
src/tools/clippy/clippy_lints/src/manual_assert.rs
src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
src/tools/clippy/clippy_lints/src/manual_let_else.rs
src/tools/clippy/clippy_lints/src/manual_retain.rs
src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
src/tools/clippy/clippy_lints/src/methods/mod.rs
src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs
src/tools/clippy/clippy_lints/src/misc.rs
src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
src/tools/clippy/clippy_lints/src/operators/identity_op.rs
src/tools/clippy/clippy_lints/src/operators/mod.rs
src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
src/tools/clippy/clippy_lints/src/renamed_lints.rs
src/tools/clippy/clippy_lints/src/semicolon_block.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/strings.rs
src/tools/clippy/clippy_lints/src/utils/conf.rs
src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs
src/tools/clippy/clippy_utils/Cargo.toml
src/tools/clippy/clippy_utils/src/lib.rs
src/tools/clippy/clippy_utils/src/macros.rs
src/tools/clippy/clippy_utils/src/msrvs.rs
src/tools/clippy/clippy_utils/src/paths.rs
src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
src/tools/clippy/clippy_utils/src/ty.rs
src/tools/clippy/declare_clippy_lint/Cargo.toml
src/tools/clippy/rust-toolchain
src/tools/clippy/rustc_tools_util/CHANGELOG.md [new file with mode: 0644]
src/tools/clippy/rustc_tools_util/Cargo.toml
src/tools/clippy/rustc_tools_util/README.md
src/tools/clippy/rustc_tools_util/src/lib.rs
src/tools/clippy/src/driver.rs
src/tools/clippy/src/main.rs
src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr
src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs
src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/clippy.toml
src/tools/clippy/tests/ui-toml/suppress_lint_in_const/clippy.toml [new file with mode: 0644]
src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.rs [new file with mode: 0644]
src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
src/tools/clippy/tests/ui/almost_complete_letter_range.fixed [deleted file]
src/tools/clippy/tests/ui/almost_complete_letter_range.rs [deleted file]
src/tools/clippy/tests/ui/almost_complete_letter_range.stderr [deleted file]
src/tools/clippy/tests/ui/almost_complete_range.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/almost_complete_range.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/almost_complete_range.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/arithmetic_side_effects.stderr
src/tools/clippy/tests/ui/auxiliary/macro_rules.rs
src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs
src/tools/clippy/tests/ui/cast_lossless_integer.fixed
src/tools/clippy/tests/ui/cast_lossless_integer.rs
src/tools/clippy/tests/ui/collapsible_str_replace.fixed
src/tools/clippy/tests/ui/collapsible_str_replace.rs
src/tools/clippy/tests/ui/collapsible_str_replace.stderr
src/tools/clippy/tests/ui/explicit_counter_loop.rs
src/tools/clippy/tests/ui/from_over_into.fixed
src/tools/clippy/tests/ui/from_over_into.rs
src/tools/clippy/tests/ui/from_over_into.stderr
src/tools/clippy/tests/ui/identity_op.fixed
src/tools/clippy/tests/ui/identity_op.rs
src/tools/clippy/tests/ui/identity_op.stderr
src/tools/clippy/tests/ui/implicit_clone.fixed
src/tools/clippy/tests/ui/implicit_clone.rs
src/tools/clippy/tests/ui/indexing_slicing_index.rs
src/tools/clippy/tests/ui/indexing_slicing_index.stderr
src/tools/clippy/tests/ui/len_zero.fixed
src/tools/clippy/tests/ui/len_zero.rs
src/tools/clippy/tests/ui/len_zero.stderr
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.edition2021.stderr
src/tools/clippy/tests/ui/manual_assert.rs
src/tools/clippy/tests/ui/manual_is_ascii_check.fixed
src/tools/clippy/tests/ui/manual_is_ascii_check.rs
src/tools/clippy/tests/ui/manual_is_ascii_check.stderr
src/tools/clippy/tests/ui/manual_let_else_match.rs
src/tools/clippy/tests/ui/manual_let_else_match.stderr
src/tools/clippy/tests/ui/needless_parens_on_range_literals.fixed
src/tools/clippy/tests/ui/needless_parens_on_range_literals.rs
src/tools/clippy/tests/ui/new_ret_no_self.rs
src/tools/clippy/tests/ui/new_ret_no_self.stderr
src/tools/clippy/tests/ui/redundant_static_lifetimes.fixed
src/tools/clippy/tests/ui/redundant_static_lifetimes.rs
src/tools/clippy/tests/ui/redundant_static_lifetimes.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/seek_to_start_instead_of_rewind.fixed
src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.rs
src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.stderr
src/tools/clippy/tests/ui/semicolon_inside_block.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/semicolon_inside_block.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/semicolon_inside_block.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/semicolon_outside_block.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/semicolon_outside_block.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/semicolon_outside_block.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/string_lit_as_bytes.fixed
src/tools/clippy/tests/ui/string_lit_as_bytes.rs
src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2018.fixed
src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.fixed
src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.stderr
src/tools/clippy/tests/ui/uninlined_format_args_panic.rs
src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
src/tools/clippy/tests/ui/unnecessary_to_owned.rs
src/tools/clippy/tests/ui/zero_ptr_no_std.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/zero_ptr_no_std.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/zero_ptr_no_std.stderr [new file with mode: 0644]
src/tools/clippy/tests/versioncheck.rs
src/tools/clippy/triagebot.toml
src/tools/miri/src/machine.rs
src/tools/remote-test-server/src/main.rs
src/tools/tidy/src/error_codes_check.rs
src/tools/tidy/src/main.rs
src/tools/tidy/src/style.rs
src/tools/x/src/main.rs

index b29b3a418038ee4407809a38b67f67b7dcf3a010..2b6e96b467e3555d0611aa845aabd522b575714c 100644 (file)
@@ -301,7 +301,7 @@ jobs:
           - name: dist-x86_64-apple
             env:
               SCRIPT: "./x.py dist bootstrap --include-default-paths --host=x86_64-apple-darwin --target=x86_64-apple-darwin"
-              RUST_CONFIGURE_ARGS: "--enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
+              RUST_CONFIGURE_ARGS: "--enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false --set rust.lto=thin"
               RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
               MACOSX_DEPLOYMENT_TARGET: 10.7
               SELECT_XCODE: /Applications/Xcode_13.4.1.app
index 5d05a09f038938cf4e26241a3883989ee8e4dc22..3d09068dbdf3321fff92db3780d976065416d8af 100644 (file)
@@ -294,7 +294,7 @@ dependencies = [
 
 [[package]]
 name = "cargo"
-version = "0.68.0"
+version = "0.69.0"
 dependencies = [
  "anyhow",
  "bytesize",
@@ -394,7 +394,7 @@ dependencies = [
  "directories",
  "rustc-build-sysroot",
  "rustc-workspace-hack",
- "rustc_tools_util",
+ "rustc_tools_util 0.2.1",
  "rustc_version",
  "serde",
  "serde_json",
@@ -658,7 +658,7 @@ dependencies = [
 
 [[package]]
 name = "clippy"
-version = "0.1.67"
+version = "0.1.68"
 dependencies = [
  "clippy_lints",
  "clippy_utils",
@@ -673,7 +673,7 @@ dependencies = [
  "regex",
  "rustc-semver",
  "rustc-workspace-hack",
- "rustc_tools_util",
+ "rustc_tools_util 0.3.0",
  "semver",
  "serde",
  "syn",
@@ -700,7 +700,7 @@ dependencies = [
 
 [[package]]
 name = "clippy_lints"
-version = "0.1.67"
+version = "0.1.68"
 dependencies = [
  "cargo_metadata 0.14.0",
  "clippy_utils",
@@ -723,7 +723,7 @@ dependencies = [
 
 [[package]]
 name = "clippy_utils"
-version = "0.1.67"
+version = "0.1.68"
 dependencies = [
  "arrayvec",
  "if_chain",
@@ -966,9 +966,9 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-deque"
-version = "0.8.1"
+version = "0.8.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"
+checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc"
 dependencies = [
  "cfg-if 1.0.0",
  "crossbeam-epoch",
@@ -977,25 +977,24 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-epoch"
-version = "0.9.6"
+version = "0.9.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97242a70df9b89a65d0b6df3c4bf5b9ce03c5b7309019777fbde37e7537f8762"
+checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a"
 dependencies = [
+ "autocfg",
  "cfg-if 1.0.0",
  "crossbeam-utils",
- "lazy_static",
  "memoffset",
  "scopeguard",
 ]
 
 [[package]]
 name = "crossbeam-utils"
-version = "0.8.8"
+version = "0.8.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38"
+checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f"
 dependencies = [
  "cfg-if 1.0.0",
- "lazy_static",
 ]
 
 [[package]]
@@ -1068,7 +1067,7 @@ checksum = "a0afaad2b26fa326569eb264b1363e8ae3357618c43982b3f285f0774ce76b69"
 
 [[package]]
 name = "declare_clippy_lint"
-version = "0.1.67"
+version = "0.1.68"
 dependencies = [
  "itertools",
  "quote",
@@ -2379,9 +2378,9 @@ dependencies = [
 
 [[package]]
 name = "memoffset"
-version = "0.6.5"
+version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
+checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4"
 dependencies = [
  "autocfg",
 ]
@@ -3591,7 +3590,7 @@ version = "0.0.0"
 dependencies = [
  "arrayvec",
  "bitflags",
- "cfg-if 0.1.10",
+ "cfg-if 1.0.0",
  "ena",
  "indexmap",
  "jobserver",
@@ -4070,6 +4069,7 @@ dependencies = [
  "rustc_hir",
  "rustc_index",
  "rustc_infer",
+ "rustc_macros",
  "rustc_middle",
  "rustc_serialize",
  "rustc_session",
@@ -4374,7 +4374,7 @@ dependencies = [
 name = "rustc_span"
 version = "0.0.0"
 dependencies = [
- "cfg-if 0.1.10",
+ "cfg-if 1.0.0",
  "md-5",
  "rustc_arena",
  "rustc_data_structures",
@@ -4429,6 +4429,12 @@ version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "598f48ce2a421542b3e64828aa742b687cc1b91d2f96591cfdb7ac5988cd6366"
 
+[[package]]
+name = "rustc_tools_util"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ba09476327c4b70ccefb6180f046ef588c26a24cf5d269a9feba316eb4f029f"
+
 [[package]]
 name = "rustc_trait_selection"
 version = "0.0.0"
index 8c71332bfabb13d9f45813414978a05c1c9c2fcc..4582d3c6badf99491254930d6e7c0f3ee6d7cff8 100644 (file)
@@ -774,6 +774,18 @@ pub fn align<C: HasDataLayout>(self, cx: &C) -> AbiAndPrefAlign {
         }
     }
 
+    /// Returns the largest signed value that can be represented by this Integer.
+    #[inline]
+    pub fn signed_max(self) -> i128 {
+        match self {
+            I8 => i8::MAX as i128,
+            I16 => i16::MAX as i128,
+            I32 => i32::MAX as i128,
+            I64 => i64::MAX as i128,
+            I128 => i128::MAX,
+        }
+    }
+
     /// Finds the smallest Integer type which can represent the signed value.
     #[inline]
     pub fn fit_signed(x: i128) -> Integer {
index f933b9b161ca91f56bfb0db9e3f39eaae37e4d54..31596a1e9bf889ca1f684fcca0c20673add5c558 100644 (file)
@@ -2554,10 +2554,9 @@ pub enum AttrStyle {
 }
 
 rustc_index::newtype_index! {
-    pub struct AttrId {
-        ENCODABLE = custom
-        DEBUG_FORMAT = "AttrId({})"
-    }
+    #[custom_encodable]
+    #[debug_format = "AttrId({})]"]
+    pub struct AttrId {}
 }
 
 impl<S: Encoder> Encodable<S> for AttrId {
index 7b5acc3f4859624c4d48baf3a99a346b00fae8f8..daa82996b3d11f52a9fead380c10c879ac7e9896 100644 (file)
@@ -8,9 +8,8 @@
     /// This is later turned into [`DefId`] and `HirId` for the HIR.
     ///
     /// [`DefId`]: rustc_span::def_id::DefId
-    pub struct NodeId {
-        DEBUG_FORMAT = "NodeId({})"
-    }
+    #[debug_format = "NodeId({})"]
+    pub struct NodeId {}
 }
 
 rustc_data_structures::define_id_collections!(NodeMap, NodeSet, NodeMapEntry, NodeId);
index e86e807279d6f10157264705e42e49c8b8c872d0..a3f5c18f2e75cfe836ecd66639d9114fd3ccbd1a 100644 (file)
@@ -16,7 +16,7 @@
 use rustc_hir::definitions::DefPathData;
 use rustc_session::errors::report_lit_error;
 use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned};
-use rustc_span::symbol::{kw, sym, Ident};
+use rustc_span::symbol::{sym, Ident};
 use rustc_span::DUMMY_SP;
 use thin_vec::thin_vec;
 
@@ -596,38 +596,14 @@ pub(super) fn make_async_expr(
     ) -> hir::ExprKind<'hir> {
         let output = ret_ty.unwrap_or_else(|| hir::FnRetTy::DefaultReturn(self.lower_span(span)));
 
-        // Resume argument type, which should be `&mut Context<'_>`.
-        // NOTE: Using the `'static` lifetime here is technically cheating.
-        // The `Future::poll` argument really is `&'a mut Context<'b>`, but we cannot
-        // express the fact that we are not storing it across yield-points yet,
-        // and we would thus run into lifetime errors.
-        // See <https://github.com/rust-lang/rust/issues/68923>.
-        // Our lowering makes sure we are not mis-using the `_task_context` input type
-        // in the sense that we are indeed not using it across yield points. We
-        // get a fresh `&mut Context` for each resume / call of `Future::poll`.
-        // This "cheating" was previously done with a `ResumeTy` that contained a raw
-        // pointer, and a `get_context` accessor that pulled the `Context` lifetimes
-        // out of thin air.
-        let context_lifetime_ident = Ident::with_dummy_span(kw::StaticLifetime);
-        let context_lifetime = self.arena.alloc(hir::Lifetime {
-            hir_id: self.next_id(),
-            ident: context_lifetime_ident,
-            res: hir::LifetimeName::Static,
-        });
-        let context_path =
-            hir::QPath::LangItem(hir::LangItem::Context, self.lower_span(span), None);
-        let context_ty = hir::MutTy {
-            ty: self.arena.alloc(hir::Ty {
-                hir_id: self.next_id(),
-                kind: hir::TyKind::Path(context_path),
-                span: self.lower_span(span),
-            }),
-            mutbl: hir::Mutability::Mut,
-        };
+        // Resume argument type: `ResumeTy`
+        let unstable_span =
+            self.mark_span_with_reason(DesugaringKind::Async, span, self.allow_gen_future.clone());
+        let resume_ty = hir::QPath::LangItem(hir::LangItem::ResumeTy, unstable_span, None);
         let input_ty = hir::Ty {
             hir_id: self.next_id(),
-            kind: hir::TyKind::Rptr(context_lifetime, context_ty),
-            span: self.lower_span(span),
+            kind: hir::TyKind::Path(resume_ty),
+            span: unstable_span,
         };
 
         // The closure/generator `FnDecl` takes a single (resume) argument of type `input_ty`.
@@ -686,9 +662,12 @@ pub(super) fn make_async_expr(
             .map_or(false, |attrs| attrs.into_iter().any(|attr| attr.has_name(sym::track_caller)));
 
         let hir_id = self.lower_node_id(closure_node_id);
-        let unstable_span =
-            self.mark_span_with_reason(DesugaringKind::Async, span, self.allow_gen_future.clone());
         if track_caller {
+            let unstable_span = self.mark_span_with_reason(
+                DesugaringKind::Async,
+                span,
+                self.allow_gen_future.clone(),
+            );
             self.lower_attrs(
                 hir_id,
                 &[Attribute {
@@ -731,7 +710,7 @@ pub(super) fn make_async_expr(
     ///     mut __awaitee => loop {
     ///         match unsafe { ::std::future::Future::poll(
     ///             <::std::pin::Pin>::new_unchecked(&mut __awaitee),
-    ///             task_context,
+    ///             ::std::future::get_context(task_context),
     ///         ) } {
     ///             ::std::task::Poll::Ready(result) => break result,
     ///             ::std::task::Poll::Pending => {}
@@ -772,7 +751,7 @@ fn lower_expr_await(&mut self, dot_await_span: Span, expr: &Expr) -> hir::ExprKi
         // unsafe {
         //     ::std::future::Future::poll(
         //         ::std::pin::Pin::new_unchecked(&mut __awaitee),
-        //         task_context,
+        //         ::std::future::get_context(task_context),
         //     )
         // }
         let poll_expr = {
@@ -790,10 +769,16 @@ fn lower_expr_await(&mut self, dot_await_span: Span, expr: &Expr) -> hir::ExprKi
                 arena_vec![self; ref_mut_awaitee],
                 Some(expr_hir_id),
             );
+            let get_context = self.expr_call_lang_item_fn_mut(
+                gen_future_span,
+                hir::LangItem::GetContext,
+                arena_vec![self; task_context],
+                Some(expr_hir_id),
+            );
             let call = self.expr_call_lang_item_fn(
                 span,
                 hir::LangItem::FuturePoll,
-                arena_vec![self; new_unchecked, task_context],
+                arena_vec![self; new_unchecked, get_context],
                 Some(expr_hir_id),
             );
             self.arena.alloc(self.expr_unsafe(call))
index 73065ab516350fe33c50fae50de39a228278340f..9d4c2900eaf41aa12e6edb21621132a071f88374 100644 (file)
@@ -1,6 +1,6 @@
 use super::errors::{InvalidAbi, InvalidAbiSuggestion, MisplacedRelaxTraitBound};
 use super::ResolverAstLoweringExt;
-use super::{Arena, AstOwner, ImplTraitContext, ImplTraitPosition};
+use super::{AstOwner, ImplTraitContext, ImplTraitPosition};
 use super::{FnDeclKind, LoweringContext, ParamMode};
 
 use rustc_ast::ptr::P;
@@ -24,7 +24,6 @@
 pub(super) struct ItemLowerer<'a, 'hir> {
     pub(super) tcx: TyCtxt<'hir>,
     pub(super) resolver: &'a mut ResolverAstLowering,
-    pub(super) ast_arena: &'a Arena<'static>,
     pub(super) ast_index: &'a IndexVec<LocalDefId, AstOwner<'a>>,
     pub(super) owners: &'a mut IndexVec<LocalDefId, hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>>>,
 }
@@ -60,7 +59,6 @@ fn with_lctx(
             tcx: self.tcx,
             resolver: self.resolver,
             arena: self.tcx.hir_arena,
-            ast_arena: self.ast_arena,
 
             // HirId handling.
             bodies: Vec::new(),
index d67ede6e1302ef731017cf5f61d9ec7ab56dc87a..0ef784a4453dcf131193f9be757250671328b413 100644 (file)
@@ -42,7 +42,6 @@
 
 use crate::errors::{AssocTyParentheses, AssocTyParenthesesSub, MisplacedImplTrait, TraitFnAsync};
 
-use rustc_arena::declare_arena;
 use rustc_ast::ptr::P;
 use rustc_ast::visit;
 use rustc_ast::{self as ast, *};
@@ -94,13 +93,6 @@ struct LoweringContext<'a, 'hir> {
     /// Used to allocate HIR nodes.
     arena: &'hir hir::Arena<'hir>,
 
-    /// Used to allocate temporary AST nodes for use during lowering.
-    /// This allows us to create "fake" AST -- these nodes can sometimes
-    /// be allocated on the stack, but other times we need them to live longer
-    /// than the current stack frame, so they can be collected into vectors
-    /// and things like that.
-    ast_arena: &'a Arena<'static>,
-
     /// Bodies inside the owner being lowered.
     bodies: Vec<(hir::ItemLocalId, &'hir hir::Body<'hir>)>,
     /// Attributes inside the owner being lowered.
@@ -146,15 +138,6 @@ struct LoweringContext<'a, 'hir> {
     generics_def_id_map: Vec<FxHashMap<LocalDefId, LocalDefId>>,
 }
 
-declare_arena!([
-    [] tys: rustc_ast::Ty,
-    [] aba: rustc_ast::AngleBracketedArgs,
-    [] ptr: rustc_ast::PolyTraitRef,
-    // This _marker field is needed because `declare_arena` creates `Arena<'tcx>` and we need to
-    // use `'tcx`. If we don't have this we get a compile error.
-    [] _marker: std::marker::PhantomData<&'tcx ()>,
-]);
-
 trait ResolverAstLoweringExt {
     fn legacy_const_generic_args(&self, expr: &Expr) -> Option<Vec<usize>>;
     fn get_partial_res(&self, id: NodeId) -> Option<PartialRes>;
@@ -442,13 +425,10 @@ pub fn lower_to_hir<'hir>(tcx: TyCtxt<'hir>, (): ()) -> hir::Crate<'hir> {
         tcx.definitions_untracked().def_index_count(),
     );
 
-    let ast_arena = Arena::default();
-
     for def_id in ast_index.indices() {
         item::ItemLowerer {
             tcx,
             resolver: &mut resolver,
-            ast_arena: &ast_arena,
             ast_index: &ast_index,
             owners: &mut owners,
         }
@@ -620,7 +600,7 @@ fn with_hir_id_owner(
         self.impl_trait_defs = current_impl_trait_defs;
         self.impl_trait_bounds = current_impl_trait_bounds;
 
-        debug_assert!(self.children.iter().find(|(id, _)| id == &def_id).is_none());
+        debug_assert!(!self.children.iter().any(|(id, _)| id == &def_id));
         self.children.push((def_id, hir::MaybeOwner::Owner(info)));
     }
 
@@ -1001,8 +981,12 @@ fn lower_assoc_ty_constraint(
                 }
                 GenericArgs::Parenthesized(data) => {
                     self.emit_bad_parenthesized_trait_in_assoc_ty(data);
-                    let aba = self.ast_arena.aba.alloc(data.as_angle_bracketed_args());
-                    self.lower_angle_bracketed_parameter_data(aba, ParamMode::Explicit, itctx).0
+                    self.lower_angle_bracketed_parameter_data(
+                        &data.as_angle_bracketed_args(),
+                        ParamMode::Explicit,
+                        itctx,
+                    )
+                    .0
                 }
             };
             gen_args_ctor.into_generic_args(self)
@@ -1067,13 +1051,15 @@ fn lower_assoc_ty_constraint(
 
                     self.with_dyn_type_scope(false, |this| {
                         let node_id = this.next_node_id();
-                        let ty = this.ast_arena.tys.alloc(Ty {
-                            id: node_id,
-                            kind: TyKind::ImplTrait(impl_trait_node_id, bounds.clone()),
-                            span: this.lower_span(constraint.span),
-                            tokens: None,
-                        });
-                        let ty = this.lower_ty(ty, itctx);
+                        let ty = this.lower_ty(
+                            &Ty {
+                                id: node_id,
+                                kind: TyKind::ImplTrait(impl_trait_node_id, bounds.clone()),
+                                span: this.lower_span(constraint.span),
+                                tokens: None,
+                            },
+                            itctx,
+                        );
 
                         hir::TypeBindingKind::Equality { term: ty.into() }
                     })
@@ -1217,13 +1203,12 @@ fn lower_path_ty(
             && let Some(Res::Def(DefKind::Trait | DefKind::TraitAlias, _)) = partial_res.full_res()
         {
             let (bounds, lifetime_bound) = self.with_dyn_type_scope(true, |this| {
-                let poly_trait_ref = this.ast_arena.ptr.alloc(PolyTraitRef {
-                    bound_generic_params: vec![],
-                    trait_ref: TraitRef { path: path.clone(), ref_id: t.id },
-                    span: t.span
-                });
                 let bound = this.lower_poly_trait_ref(
-                    poly_trait_ref,
+                    &PolyTraitRef {
+                        bound_generic_params: vec![],
+                        trait_ref: TraitRef { path: path.clone(), ref_id: t.id },
+                        span: t.span
+                    },
                     itctx,
                 );
                 let bounds = this.arena.alloc_from_iter([bound]);
index eb9c841d80c16b05a74f3f0e7be3404b5c59a974..55ea12d25ea2ceead70b4c4e6c4de49548a84852 100644 (file)
@@ -42,7 +42,6 @@ enum SelfSemantic {
 /// What is the context that prevents using `~const`?
 enum DisallowTildeConstContext<'a> {
     TraitObject,
-    ImplTrait,
     Fn(FnKind<'a>),
 }
 
@@ -187,11 +186,7 @@ fn with_banned_assoc_ty_bound(&mut self, f: impl FnOnce(&mut Self)) {
 
     fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
         let old = mem::replace(&mut self.outer_impl_trait, outer);
-        if outer.is_some() {
-            self.with_banned_tilde_const(DisallowTildeConstContext::ImplTrait, f);
-        } else {
-            f(self);
-        }
+        f(self);
         self.outer_impl_trait = old;
     }
 
@@ -1384,7 +1379,6 @@ fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) {
                     let mut err = self.err_handler().struct_span_err(bound.span(), "`~const` is not allowed here");
                     match reason {
                         DisallowTildeConstContext::TraitObject => err.note("trait objects cannot have `~const` trait bounds"),
-                        DisallowTildeConstContext::ImplTrait => err.note("`impl Trait`s cannot have `~const` trait bounds"),
                         DisallowTildeConstContext::Fn(FnKind::Closure(..)) => err.note("closures cannot have `~const` trait bounds"),
                         DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => err.span_note(ident.span, "this function is not `const`, so it cannot have `~const` trait bounds"),
                     };
index 385f153174c3c2a9170b7b41957d67682efe0e17..c780d047992cdb994c709277bbe81443bc3b45e9 100644 (file)
@@ -148,7 +148,7 @@ fn next(&mut self) -> Option<Self::Item> {
         if let Some(p) = self.pointer {
             self.pointer = self.graph.next_constraints[p];
 
-            Some(self.constraints[p].clone())
+            Some(self.constraints[p])
         } else if let Some(next_static_idx) = self.next_static_idx {
             self.next_static_idx = if next_static_idx == (self.graph.first_constraints.len() - 1) {
                 None
index 84a93e5f72e9dd3b508782306ea15fc46d653995..1f0b8adeaf16c1ecbe31529b0f0ea6efe0ec5371 100644 (file)
@@ -115,13 +115,11 @@ fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
 }
 
 rustc_index::newtype_index! {
-    pub struct OutlivesConstraintIndex {
-        DEBUG_FORMAT = "OutlivesConstraintIndex({})"
-    }
+    #[debug_format = "OutlivesConstraintIndex({})"]
+    pub struct OutlivesConstraintIndex {}
 }
 
 rustc_index::newtype_index! {
-    pub struct ConstraintSccIndex {
-        DEBUG_FORMAT = "ConstraintSccIndex({})"
-    }
+    #[debug_format = "ConstraintSccIndex({})"]
+    pub struct ConstraintSccIndex {}
 }
index f825b1d8f70ef502952699fe81e4aecf57edb849..8c4885770ad37b6d009eb450d82a7e2b47a4d057 100644 (file)
@@ -108,9 +108,8 @@ fn reconstruct_terminator_effect(
 }
 
 rustc_index::newtype_index! {
-    pub struct BorrowIndex {
-        DEBUG_FORMAT = "bw{}"
-    }
+    #[debug_format = "bw{}"]
+    pub struct BorrowIndex {}
 }
 
 /// `Borrows` stores the data used in the analyses that track the flow
index 72c0257756ef2f15d1adfdc8f47a2e143ced6ccc..8d5c5a7124f88aeee0e472d5557d80b74cbea1ad 100644 (file)
@@ -649,7 +649,7 @@ fn suggest_assign_value(
         if !assign_value.is_empty() {
             err.span_suggestion_verbose(
                 sugg_span.shrink_to_hi(),
-                format!("consider assigning a value"),
+                "consider assigning a value",
                 format!(" = {}", assign_value),
                 Applicability::MaybeIncorrect,
             );
index 304683618d83ef9dc531c7fcb7f7ed91ed329a7f..00f5e8a83972f9c6456c51635867e2a7bfa59227 100644 (file)
@@ -270,7 +270,7 @@ pub(crate) fn add_explanation_to_diagnostic(
                 for extra in extra_info {
                     match extra {
                         ExtraConstraintInfo::PlaceholderFromPredicate(span) => {
-                            err.span_note(*span, format!("due to current limitations in the borrow checker, this implies a `'static` lifetime"));
+                            err.span_note(*span, "due to current limitations in the borrow checker, this implies a `'static` lifetime");
                         }
                     }
                 }
index f8ec5e5e799149c888e001dd4ddc1b488847c8d2..bcc8afbfd952d15763d32cd6239c5c129ee8f35b 100644 (file)
 use rustc_middle::hir::place::PlaceBase;
 use rustc_middle::mir::{ConstraintCategory, ReturnConstraint};
 use rustc_middle::ty::subst::InternalSubsts;
-use rustc_middle::ty::Region;
 use rustc_middle::ty::TypeVisitor;
 use rustc_middle::ty::{self, RegionVid, Ty};
+use rustc_middle::ty::{Region, TyCtxt};
 use rustc_span::symbol::{kw, Ident};
-use rustc_span::Span;
+use rustc_span::{Span, DUMMY_SP};
 
 use crate::borrowck_errors;
 use crate::session_diagnostics::{
@@ -70,7 +70,25 @@ fn description(&self) -> &'static str {
 ///
 /// Usually we expect this to either be empty or contain a small number of items, so we can avoid
 /// allocation most of the time.
-pub(crate) type RegionErrors<'tcx> = Vec<RegionErrorKind<'tcx>>;
+pub(crate) struct RegionErrors<'tcx>(Vec<RegionErrorKind<'tcx>>, TyCtxt<'tcx>);
+
+impl<'tcx> RegionErrors<'tcx> {
+    pub fn new(tcx: TyCtxt<'tcx>) -> Self {
+        Self(vec![], tcx)
+    }
+    #[track_caller]
+    pub fn push(&mut self, val: impl Into<RegionErrorKind<'tcx>>) {
+        let val = val.into();
+        self.1.sess.delay_span_bug(DUMMY_SP, "{val:?}");
+        self.0.push(val);
+    }
+    pub fn is_empty(&self) -> bool {
+        self.0.is_empty()
+    }
+    pub fn into_iter(self) -> impl Iterator<Item = RegionErrorKind<'tcx>> {
+        self.0.into_iter()
+    }
+}
 
 #[derive(Clone, Debug)]
 pub(crate) enum RegionErrorKind<'tcx> {
@@ -472,7 +490,7 @@ pub(crate) fn report_region_error(
         for extra in extra_info {
             match extra {
                 ExtraConstraintInfo::PlaceholderFromPredicate(span) => {
-                    diag.span_note(span, format!("due to current limitations in the borrow checker, this implies a `'static` lifetime"));
+                    diag.span_note(span, "due to current limitations in the borrow checker, this implies a `'static` lifetime");
                 }
             }
         }
index 5289de9b0abf2ffa3d0d2d142904b392070dc2d9..d8c22fbe59f015929ad04085baa1d6664e213ca3 100644 (file)
@@ -2059,12 +2059,7 @@ fn is_local_ever_initialized(
     ) -> Option<InitIndex> {
         let mpi = self.move_data.rev_lookup.find_local(local);
         let ii = &self.move_data.init_path_map[mpi];
-        for &index in ii {
-            if flow_state.ever_inits.contains(index) {
-                return Some(index);
-            }
-        }
-        None
+        ii.into_iter().find(|&&index| flow_state.ever_inits.contains(index)).copied()
     }
 
     /// Adds the place into the used mutable variables set
index 9fa7e218b1b6f65ceb09a92420043f5f823f41f1..288b7d85be2d41d4d5e89fe1eab90f597f1668bd 100644 (file)
@@ -20,9 +20,8 @@ pub struct LocationTable {
 }
 
 rustc_index::newtype_index! {
-    pub struct LocationIndex {
-        DEBUG_FORMAT = "LocationIndex({})"
-    }
+    #[debug_format = "LocationIndex({})"]
+    pub struct LocationIndex {}
 }
 
 #[derive(Copy, Clone, Debug)]
index b5e00f471d26a0d266e021e330cfeb78f56fef1f..b63e286676ff48fc2129344547850f320da554d0 100644 (file)
@@ -55,9 +55,8 @@ pub(crate) struct NllMemberConstraint<'tcx> {
 }
 
 rustc_index::newtype_index! {
-    pub(crate) struct NllMemberConstraintIndex {
-        DEBUG_FORMAT = "MemberConstraintIndex({})"
-    }
+    #[debug_format = "MemberConstraintIndex({})"]
+    pub(crate) struct NllMemberConstraintIndex {}
 }
 
 impl Default for MemberConstraintSet<'_, ty::RegionVid> {
index e9c98bdc514967a63f4f1dc39be0e6be7d1919ed..308f6e19a73e86b2277985a092a5748a77827bd2 100644 (file)
@@ -562,7 +562,7 @@ pub(super) fn solve(
         let mir_def_id = body.source.def_id();
         self.propagate_constraints(body);
 
-        let mut errors_buffer = RegionErrors::new();
+        let mut errors_buffer = RegionErrors::new(infcx.tcx);
 
         // If this is a closure, we can propagate unsatisfied
         // `outlives_requirements` to our creator, so create a vector
@@ -831,7 +831,6 @@ fn check_type_tests(
             if self.eval_verify_bound(
                 infcx,
                 param_env,
-                body,
                 generic_ty,
                 type_test.lower_bound,
                 &type_test.verify_bound,
@@ -962,14 +961,7 @@ fn try_promote_type_test(
             // where `ur` is a local bound -- we are sometimes in a
             // position to prove things that our caller cannot.  See
             // #53570 for an example.
-            if self.eval_verify_bound(
-                infcx,
-                param_env,
-                body,
-                generic_ty,
-                ur,
-                &type_test.verify_bound,
-            ) {
+            if self.eval_verify_bound(infcx, param_env, generic_ty, ur, &type_test.verify_bound) {
                 continue;
             }
 
@@ -1190,7 +1182,6 @@ fn eval_verify_bound(
         &self,
         infcx: &InferCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
-        body: &Body<'tcx>,
         generic_ty: Ty<'tcx>,
         lower_bound: RegionVid,
         verify_bound: &VerifyBound<'tcx>,
@@ -1213,25 +1204,11 @@ fn eval_verify_bound(
             }
 
             VerifyBound::AnyBound(verify_bounds) => verify_bounds.iter().any(|verify_bound| {
-                self.eval_verify_bound(
-                    infcx,
-                    param_env,
-                    body,
-                    generic_ty,
-                    lower_bound,
-                    verify_bound,
-                )
+                self.eval_verify_bound(infcx, param_env, generic_ty, lower_bound, verify_bound)
             }),
 
             VerifyBound::AllBounds(verify_bounds) => verify_bounds.iter().all(|verify_bound| {
-                self.eval_verify_bound(
-                    infcx,
-                    param_env,
-                    body,
-                    generic_ty,
-                    lower_bound,
-                    verify_bound,
-                )
+                self.eval_verify_bound(infcx, param_env, generic_ty, lower_bound, verify_bound)
             }),
         }
     }
@@ -1670,26 +1647,29 @@ fn check_bound_universal_region(
         let longer_fr_scc = self.constraint_sccs.scc(longer_fr);
         debug!("check_bound_universal_region: longer_fr_scc={:?}", longer_fr_scc,);
 
-        // If we have some bound universal region `'a`, then the only
-        // elements it can contain is itself -- we don't know anything
-        // else about it!
-        let Some(error_element) = ({
-            self.scc_values.elements_contained_in(longer_fr_scc).find(|element| match element {
-                RegionElement::Location(_) => true,
-                RegionElement::RootUniversalRegion(_) => true,
-                RegionElement::PlaceholderRegion(placeholder1) => placeholder != *placeholder1,
-            })
-        }) else {
-            return;
-        };
-        debug!("check_bound_universal_region: error_element = {:?}", error_element);
+        for error_element in self.scc_values.elements_contained_in(longer_fr_scc) {
+            match error_element {
+                RegionElement::Location(_) | RegionElement::RootUniversalRegion(_) => {}
+                // If we have some bound universal region `'a`, then the only
+                // elements it can contain is itself -- we don't know anything
+                // else about it!
+                RegionElement::PlaceholderRegion(placeholder1) => {
+                    if placeholder == placeholder1 {
+                        continue;
+                    }
+                }
+            }
 
-        // Find the region that introduced this `error_element`.
-        errors_buffer.push(RegionErrorKind::BoundUniversalRegionError {
-            longer_fr,
-            error_element,
-            placeholder,
-        });
+            errors_buffer.push(RegionErrorKind::BoundUniversalRegionError {
+                longer_fr,
+                error_element,
+                placeholder,
+            });
+
+            // Stop after the first error, it gets too noisy otherwise, and does not provide more information.
+            break;
+        }
+        debug!("check_bound_universal_region: all bounds satisfied");
     }
 
     #[instrument(level = "debug", skip(self, infcx, errors_buffer))]
index 7498ddccf196a1fc136f07cac6e20768c606ce60..c3dfeedc205f7e8e4a4841fea994ea2abf79070f 100644 (file)
@@ -90,12 +90,14 @@ pub(crate) fn point_in_range(&self, index: PointIndex) -> bool {
 rustc_index::newtype_index! {
     /// A single integer representing a `Location` in the MIR control-flow
     /// graph. Constructed efficiently from `RegionValueElements`.
-    pub struct PointIndex { DEBUG_FORMAT = "PointIndex({})" }
+    #[debug_format = "PointIndex({})"]
+    pub struct PointIndex {}
 }
 
 rustc_index::newtype_index! {
     /// A single integer representing a `ty::Placeholder`.
-    pub struct PlaceholderIndex { DEBUG_FORMAT = "PlaceholderIndex({})" }
+    #[debug_format = "PlaceholderIndex({})"]
+    pub struct PlaceholderIndex {}
 }
 
 /// An individual element in a region value -- the value of a
index fda2cee43fbf1dde8e3f746ec86b025b493a4eb5..8023ef60d205290478d37c467291d88c17ac093b 100644 (file)
@@ -46,7 +46,7 @@ struct Appearance {
 }
 
 rustc_index::newtype_index! {
-    pub struct AppearanceIndex { .. }
+    pub struct AppearanceIndex {}
 }
 
 impl vll::LinkElem for Appearance {
index 814bc275019ca0109e4e3d265406630f2cf07398..247607ff29e20717196020ee862ae279fbb268b6 100644 (file)
@@ -612,7 +612,7 @@ fn sanitize_promoted(&mut self, promoted_body: &'b Body<'tcx>, location: Locatio
 
         let locations = location.to_locations();
         for constraint in constraints.outlives().iter() {
-            let mut constraint = constraint.clone();
+            let mut constraint = *constraint;
             constraint.locations = locations;
             if let ConstraintCategory::Return(_)
             | ConstraintCategory::UseAsConst
@@ -1153,16 +1153,23 @@ fn relate_type_and_user_type(
         category: ConstraintCategory<'tcx>,
     ) -> Fallible<()> {
         let annotated_type = self.user_type_annotations[user_ty.base].inferred_ty;
+        trace!(?annotated_type);
         let mut curr_projected_ty = PlaceTy::from_ty(annotated_type);
 
         let tcx = self.infcx.tcx;
 
         for proj in &user_ty.projs {
+            if let ty::Alias(ty::Opaque, ..) = curr_projected_ty.ty.kind() {
+                // There is nothing that we can compare here if we go through an opaque type.
+                // We're always in its defining scope as we can otherwise not project through
+                // it, so we're constraining it anyways.
+                return Ok(());
+            }
             let projected_ty = curr_projected_ty.projection_ty_core(
                 tcx,
                 self.param_env,
                 proj,
-                |this, field, _| {
+                |this, field, ()| {
                     let ty = this.field_ty(tcx, field);
                     self.normalize(ty, locations)
                 },
@@ -1170,10 +1177,7 @@ fn relate_type_and_user_type(
             );
             curr_projected_ty = projected_ty;
         }
-        debug!(
-            "user_ty base: {:?} freshened: {:?} projs: {:?} yields: {:?}",
-            user_ty.base, annotated_type, user_ty.projs, curr_projected_ty
-        );
+        trace!(?curr_projected_ty);
 
         let ty = curr_projected_ty.ty;
         self.relate_types(ty, v.xform(ty::Variance::Contravariant), a, locations, category)?;
index 41531580c1987ca92c0a2e76c10dc993c1c7e16a..f8761653bf5b7d80dde81339468a465eb1f0cfb3 100644 (file)
@@ -35,7 +35,7 @@ pub fn expand(
             (item, true, ecx.with_def_site_ctxt(ty.span))
         } else {
             ecx.sess.parse_sess.span_diagnostic.span_err(item.span(), "allocators must be statics");
-            return vec![orig_item.clone()]
+            return vec![orig_item];
         };
 
     // Generate a bunch of new items using the AllocFnFactory
index f5f02fc772ab6b5b08b1082ab3fdb8ee6ec99f3c..729ae4071e2008b53e1e7276484ab8fb4e021ceb 100644 (file)
@@ -239,8 +239,7 @@ pub fn expand_test_or_bench(
             cx.attr_nested_word(sym::cfg, sym::test, attr_sp),
             // #[rustc_test_marker = "test_case_sort_key"]
             cx.attr_name_value_str(sym::rustc_test_marker, test_path_symbol, attr_sp),
-        ]
-        .into(),
+        ],
         // const $ident: test::TestDescAndFn =
         ast::ItemKind::Const(
             ast::Defaultness::Final,
index 219a4f8fa89594a909cfb3936557c950067fdac9..606f710641fc0e25a17fd6f2b598058328a1e6b4 100644 (file)
@@ -144,7 +144,7 @@ fn codegen_inline_asm(
                     // We prefer the latter because it matches the behavior of
                     // Clang.
                     if late && matches!(reg, InlineAsmRegOrRegClass::Reg(_)) {
-                        constraints.push(format!("{}", reg_to_llvm(reg, Some(&in_value.layout))));
+                        constraints.push(reg_to_llvm(reg, Some(&in_value.layout)).to_string());
                     } else {
                         constraints.push(format!("{}", op_idx[&idx]));
                     }
index f3bdacf6085552109871140a10cacd1e2757d24b..487eead22b897de056ab822dbc78247244c0b4c3 100644 (file)
@@ -137,6 +137,14 @@ fn instrument_function_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribu
     }
 }
 
+fn nojumptables_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
+    if !cx.sess().opts.unstable_opts.no_jump_tables {
+        return None;
+    }
+
+    Some(llvm::CreateAttrStringValue(cx.llcx, "no-jump-tables", "true"))
+}
+
 fn probestack_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
     // Currently stack probes seem somewhat incompatible with the address
     // sanitizer and thread sanitizer. With asan we're already protected from
@@ -293,6 +301,7 @@ pub fn from_fn_attrs<'ll, 'tcx>(
     // FIXME: none of these three functions interact with source level attributes.
     to_add.extend(frame_pointer_type_attr(cx));
     to_add.extend(instrument_function_attr(cx));
+    to_add.extend(nojumptables_attr(cx));
     to_add.extend(probestack_attr(cx));
     to_add.extend(stackprotector_attr(cx));
 
index e20dc906bce9a42bb3c639c27f33d7bfb8db56b2..6c0faf37a63ce453b906185924ccb6d420dffb09 100644 (file)
@@ -425,7 +425,7 @@ fn thin_lto(
         info!("going for that thin, thin LTO");
 
         let green_modules: FxHashMap<_, _> =
-            cached_modules.iter().map(|&(_, ref wp)| (wp.cgu_name.clone(), wp.clone())).collect();
+            cached_modules.iter().map(|(_, wp)| (wp.cgu_name.clone(), wp.clone())).collect();
 
         let full_scope_len = modules.len() + serialized_modules.len() + cached_modules.len();
         let mut thin_buffers = Vec::with_capacity(modules.len());
index 853a8b82853f43400a223804c629bd7b0b9c0e75..5bf45a81e4347cd7de59a42a80fdaaa796131bd6 100644 (file)
@@ -233,8 +233,8 @@ fn invoke(
         // Set KCFI operand bundle
         let is_indirect_call = unsafe { llvm::LLVMIsAFunction(llfn).is_none() };
         let kcfi_bundle =
-            if self.tcx.sess.is_sanitizer_kcfi_enabled() && fn_abi.is_some() && is_indirect_call {
-                let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi.unwrap());
+            if self.tcx.sess.is_sanitizer_kcfi_enabled() && let Some(fn_abi) = fn_abi && is_indirect_call {
+                let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi);
                 Some(llvm::OperandBundleDef::new("kcfi", &[self.const_u32(kcfi_typeid)]))
             } else {
                 None
index aa1735f38acfd1e8c4c65e49f1998939407e84af..f3bff5d57161e25422ab811186ab2a1367cecefa 100644 (file)
@@ -3,7 +3,6 @@
 use crate::callee::get_fn;
 use crate::coverageinfo;
 use crate::debuginfo;
-use crate::errors::BranchProtectionRequiresAArch64;
 use crate::llvm;
 use crate::llvm_util;
 use crate::type_::Type;
@@ -281,9 +280,7 @@ pub unsafe fn create_module<'ll>(
     }
 
     if let Some(BranchProtection { bti, pac_ret }) = sess.opts.unstable_opts.branch_protection {
-        if sess.target.arch != "aarch64" {
-            sess.emit_err(BranchProtectionRequiresAArch64);
-        } else {
+        if sess.target.arch == "aarch64" {
             llvm::LLVMRustAddModuleFlag(
                 llmod,
                 llvm::LLVMModFlagBehavior::Error,
@@ -309,6 +306,11 @@ pub unsafe fn create_module<'ll>(
                 "sign-return-address-with-bkey\0".as_ptr().cast(),
                 u32::from(pac_opts.key == PAuthKey::B),
             );
+        } else {
+            bug!(
+                "branch-protection used on non-AArch64 target; \
+                  this should be checked in rustc_session."
+            );
         }
     }
 
index af9f31fc3249309ee4aee8db7d4b0176f5fabf75..b46209972421fe894fd4b217013d7072558d6682 100644 (file)
@@ -51,10 +51,6 @@ pub(crate) struct SymbolAlreadyDefined<'a> {
     pub symbol_name: &'a str,
 }
 
-#[derive(Diagnostic)]
-#[diag(codegen_llvm_branch_protection_requires_aarch64)]
-pub(crate) struct BranchProtectionRequiresAArch64;
-
 #[derive(Diagnostic)]
 #[diag(codegen_llvm_invalid_minimum_alignment)]
 pub(crate) struct InvalidMinimumAlignment {
index ceb3d5a84abf3ecf795eae8b82cacddb8014e6ef..b19398e68c260186ec637b8d02a1f25dba1c8385 100644 (file)
@@ -175,6 +175,89 @@ fn emit_aapcs_va_arg<'ll, 'tcx>(
     val
 }
 
+fn emit_s390x_va_arg<'ll, 'tcx>(
+    bx: &mut Builder<'_, 'll, 'tcx>,
+    list: OperandRef<'tcx, &'ll Value>,
+    target_ty: Ty<'tcx>,
+) -> &'ll Value {
+    // Implementation of the s390x ELF ABI calling convention for va_args see
+    // https://github.com/IBM/s390x-abi (chapter 1.2.4)
+    let va_list_addr = list.immediate();
+    let va_list_layout = list.deref(bx.cx).layout;
+    let va_list_ty = va_list_layout.llvm_type(bx);
+    let layout = bx.cx.layout_of(target_ty);
+
+    let in_reg = bx.append_sibling_block("va_arg.in_reg");
+    let in_mem = bx.append_sibling_block("va_arg.in_mem");
+    let end = bx.append_sibling_block("va_arg.end");
+
+    // FIXME: vector ABI not yet supported.
+    let target_ty_size = bx.cx.size_of(target_ty).bytes();
+    let indirect: bool = target_ty_size > 8 || !target_ty_size.is_power_of_two();
+    let unpadded_size = if indirect { 8 } else { target_ty_size };
+    let padded_size = 8;
+    let padding = padded_size - unpadded_size;
+
+    let gpr_type = indirect || !layout.is_single_fp_element(bx.cx);
+    let (max_regs, reg_count_field, reg_save_index, reg_padding) =
+        if gpr_type { (5, 0, 2, padding) } else { (4, 1, 16, 0) };
+
+    // Check whether the value was passed in a register or in memory.
+    let reg_count = bx.struct_gep(
+        va_list_ty,
+        va_list_addr,
+        va_list_layout.llvm_field_index(bx.cx, reg_count_field),
+    );
+    let reg_count_v = bx.load(bx.type_i64(), reg_count, Align::from_bytes(8).unwrap());
+    let use_regs = bx.icmp(IntPredicate::IntULT, reg_count_v, bx.const_u64(max_regs));
+    bx.cond_br(use_regs, in_reg, in_mem);
+
+    // Emit code to load the value if it was passed in a register.
+    bx.switch_to_block(in_reg);
+
+    // Work out the address of the value in the register save area.
+    let reg_ptr =
+        bx.struct_gep(va_list_ty, va_list_addr, va_list_layout.llvm_field_index(bx.cx, 3));
+    let reg_ptr_v = bx.load(bx.type_i8p(), reg_ptr, bx.tcx().data_layout.pointer_align.abi);
+    let scaled_reg_count = bx.mul(reg_count_v, bx.const_u64(8));
+    let reg_off = bx.add(scaled_reg_count, bx.const_u64(reg_save_index * 8 + reg_padding));
+    let reg_addr = bx.gep(bx.type_i8(), reg_ptr_v, &[reg_off]);
+
+    // Update the register count.
+    let new_reg_count_v = bx.add(reg_count_v, bx.const_u64(1));
+    bx.store(new_reg_count_v, reg_count, Align::from_bytes(8).unwrap());
+    bx.br(end);
+
+    // Emit code to load the value if it was passed in memory.
+    bx.switch_to_block(in_mem);
+
+    // Work out the address of the value in the argument overflow area.
+    let arg_ptr =
+        bx.struct_gep(va_list_ty, va_list_addr, va_list_layout.llvm_field_index(bx.cx, 2));
+    let arg_ptr_v = bx.load(bx.type_i8p(), arg_ptr, bx.tcx().data_layout.pointer_align.abi);
+    let arg_off = bx.const_u64(padding);
+    let mem_addr = bx.gep(bx.type_i8(), arg_ptr_v, &[arg_off]);
+
+    // Update the argument overflow area pointer.
+    let arg_size = bx.cx().const_u64(padded_size);
+    let new_arg_ptr_v = bx.inbounds_gep(bx.type_i8(), arg_ptr_v, &[arg_size]);
+    bx.store(new_arg_ptr_v, arg_ptr, bx.tcx().data_layout.pointer_align.abi);
+    bx.br(end);
+
+    // Return the appropriate result.
+    bx.switch_to_block(end);
+    let val_addr = bx.phi(bx.type_i8p(), &[reg_addr, mem_addr], &[in_reg, in_mem]);
+    let val_type = layout.llvm_type(bx);
+    let val_addr = if indirect {
+        let ptr_type = bx.cx.type_ptr_to(val_type);
+        let ptr_addr = bx.bitcast(val_addr, bx.cx.type_ptr_to(ptr_type));
+        bx.load(ptr_type, ptr_addr, bx.tcx().data_layout.pointer_align.abi)
+    } else {
+        bx.bitcast(val_addr, bx.cx.type_ptr_to(val_type))
+    };
+    bx.load(val_type, val_addr, layout.align.abi)
+}
+
 pub(super) fn emit_va_arg<'ll, 'tcx>(
     bx: &mut Builder<'_, 'll, 'tcx>,
     addr: OperandRef<'tcx, &'ll Value>,
@@ -200,6 +283,7 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
             emit_ptr_va_arg(bx, addr, target_ty, false, Align::from_bytes(8).unwrap(), true)
         }
         "aarch64" => emit_aapcs_va_arg(bx, addr, target_ty),
+        "s390x" => emit_s390x_va_arg(bx, addr, target_ty),
         // Windows x86_64
         "x86_64" if target.is_like_windows => {
             let target_ty_size = bx.cx.size_of(target_ty).bytes();
index 5266d8858d47d35dcc9c12e0e935bb9327b1d4f0..6eb120157da0205b34c762ec5787d2a9665bd9b0 100644 (file)
@@ -123,7 +123,7 @@ fn try_filter_fat_archs<'a>(
 ) -> io::Result<Option<(&'a [u8], u64)>> {
     let archs = archs.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
 
-    let desired = match archs.iter().filter(|a| a.architecture() == target_arch).next() {
+    let desired = match archs.iter().find(|a| a.architecture() == target_arch) {
         Some(a) => a,
         None => return Ok(None),
     };
index 882430694e16d7f65668154330f9796d7f8ff924..a1c77ec0cfca7b7f24a90324cf10bb666b0f0a17 100644 (file)
@@ -253,7 +253,7 @@ pub fn each_linked_rlib(
     };
     for &cnum in crates {
         match fmts.get(cnum.as_usize() - 1) {
-            Some(&Linkage::NotLinked | &Linkage::IncludedFromDylib) => continue,
+            Some(&Linkage::NotLinked | &Linkage::Dynamic | &Linkage::IncludedFromDylib) => continue,
             Some(_) => {}
             None => return Err(errors::LinkRlibError::MissingFormat),
         }
@@ -722,7 +722,7 @@ fn link_natively<'a>(
 
     linker::disable_localization(&mut cmd);
 
-    for &(ref k, ref v) in sess.target.link_env.as_ref() {
+    for (k, v) in sess.target.link_env.as_ref() {
         cmd.env(k.as_ref(), v.as_ref());
     }
     for k in sess.target.link_env_remove.as_ref() {
index f087d903e5568f835476c6a43d8dd8c4f7dda6ce..0268659d3b9a13d8515eace64f9d4d2851945bec 100644 (file)
@@ -108,7 +108,7 @@ pub fn get_linker<'a>(
     if sess.target.is_like_msvc {
         if let Some(ref tool) = msvc_tool {
             cmd.args(tool.args());
-            for &(ref k, ref v) in tool.env() {
+            for (k, v) in tool.env() {
                 if k == "PATH" {
                     new_path.extend(env::split_paths(v));
                     msvc_changed_path = true;
index 6015d48decae930ac7cfc764663680d25d830c8b..0f6e6032f9bffb68a2a7098886643f284cb40ea0 100644 (file)
@@ -29,6 +29,9 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
             let align = meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_ALIGN)
                 .get_usize(bx, vtable);
 
+            // Size is always <= isize::MAX.
+            let size_bound = bx.data_layout().ptr_sized_integer().signed_max() as u128;
+            bx.range_metadata(size, WrappingRange { start: 0, end: size_bound });
             // Alignment is always nonzero.
             bx.range_metadata(align, WrappingRange { start: 1, end: !0 });
 
index 215edbe02c08e95244984fdf3ca817459f31ab73..a75609260eda49f874c909be5583d6693d98c148 100644 (file)
@@ -110,10 +110,16 @@ pub fn codegen_intrinsic_call(
                     _ => bug!(),
                 };
                 let value = meth::VirtualIndex::from_index(idx).get_usize(bx, vtable);
-                if name == sym::vtable_align {
+                match name {
+                    // Size is always <= isize::MAX.
+                    sym::vtable_size => {
+                        let size_bound = bx.data_layout().ptr_sized_integer().signed_max() as u128;
+                        bx.range_metadata(value, WrappingRange { start: 0, end: size_bound });
+                    },
                     // Alignment is always nonzero.
-                    bx.range_metadata(value, WrappingRange { start: 1, end: !0 });
-                };
+                    sym::vtable_align => bx.range_metadata(value, WrappingRange { start: 1, end: !0 }),
+                    _ => {}
+                }
                 value
             }
             sym::pref_align_of
index c60d6e4fed9f55277ba8640f9fb8ed81d4612dfc..13472cc2bfa0a5c4b8ed7ba81baa6eb3114ac9f9 100644 (file)
@@ -86,6 +86,59 @@ pub(super) fn report(&self, tcx: TyCtxtAt<'tcx>, message: &str) -> ErrorHandled
         self.report_decorated(tcx, message, |_| {})
     }
 
+    #[instrument(level = "trace", skip(self, decorate))]
+    pub(super) fn decorate(&self, err: &mut Diagnostic, decorate: impl FnOnce(&mut Diagnostic)) {
+        trace!("reporting const eval failure at {:?}", self.span);
+        // Add some more context for select error types.
+        match self.error {
+            InterpError::Unsupported(
+                UnsupportedOpInfo::ReadPointerAsBytes
+                | UnsupportedOpInfo::PartialPointerOverwrite(_)
+                | UnsupportedOpInfo::PartialPointerCopy(_),
+            ) => {
+                err.help("this code performed an operation that depends on the underlying bytes representing a pointer");
+                err.help("the absolute address of a pointer is not known at compile-time, so such operations are not supported");
+            }
+            _ => {}
+        }
+        // Add spans for the stacktrace. Don't print a single-line backtrace though.
+        if self.stacktrace.len() > 1 {
+            // Helper closure to print duplicated lines.
+            let mut flush_last_line = |last_frame, times| {
+                if let Some((line, span)) = last_frame {
+                    err.span_note(span, &line);
+                    // Don't print [... additional calls ...] if the number of lines is small
+                    if times < 3 {
+                        for _ in 0..times {
+                            err.span_note(span, &line);
+                        }
+                    } else {
+                        err.span_note(
+                            span,
+                            format!("[... {} additional calls {} ...]", times, &line),
+                        );
+                    }
+                }
+            };
+
+            let mut last_frame = None;
+            let mut times = 0;
+            for frame_info in &self.stacktrace {
+                let frame = (frame_info.to_string(), frame_info.span);
+                if last_frame.as_ref() == Some(&frame) {
+                    times += 1;
+                } else {
+                    flush_last_line(last_frame, times);
+                    last_frame = Some(frame);
+                    times = 0;
+                }
+            }
+            flush_last_line(last_frame, times);
+        }
+        // Let the caller attach any additional information it wants.
+        decorate(err);
+    }
+
     /// Create a diagnostic for this const eval error.
     ///
     /// Sets the message passed in via `message` and adds span labels with detailed error
@@ -101,88 +154,30 @@ pub(super) fn report_decorated(
         message: &str,
         decorate: impl FnOnce(&mut Diagnostic),
     ) -> ErrorHandled {
-        let finish = |err: &mut Diagnostic, span_msg: Option<String>| {
-            trace!("reporting const eval failure at {:?}", self.span);
-            if let Some(span_msg) = span_msg {
-                err.span_label(self.span, span_msg);
-            }
-            // Add some more context for select error types.
-            match self.error {
-                InterpError::Unsupported(
-                    UnsupportedOpInfo::ReadPointerAsBytes
-                    | UnsupportedOpInfo::PartialPointerOverwrite(_)
-                    | UnsupportedOpInfo::PartialPointerCopy(_),
-                ) => {
-                    err.help("this code performed an operation that depends on the underlying bytes representing a pointer");
-                    err.help("the absolute address of a pointer is not known at compile-time, so such operations are not supported");
-                }
-                _ => {}
-            }
-            // Add spans for the stacktrace. Don't print a single-line backtrace though.
-            if self.stacktrace.len() > 1 {
-                // Helper closure to print duplicated lines.
-                let mut flush_last_line = |last_frame, times| {
-                    if let Some((line, span)) = last_frame {
-                        err.span_note(span, &line);
-                        // Don't print [... additional calls ...] if the number of lines is small
-                        if times < 3 {
-                            for _ in 0..times {
-                                err.span_note(span, &line);
-                            }
-                        } else {
-                            err.span_note(
-                                span,
-                                format!("[... {} additional calls {} ...]", times, &line),
-                            );
-                        }
-                    }
-                };
-
-                let mut last_frame = None;
-                let mut times = 0;
-                for frame_info in &self.stacktrace {
-                    let frame = (frame_info.to_string(), frame_info.span);
-                    if last_frame.as_ref() == Some(&frame) {
-                        times += 1;
-                    } else {
-                        flush_last_line(last_frame, times);
-                        last_frame = Some(frame);
-                        times = 0;
-                    }
-                }
-                flush_last_line(last_frame, times);
-            }
-            // Let the caller attach any additional information it wants.
-            decorate(err);
-        };
-
         debug!("self.error: {:?}", self.error);
         // Special handling for certain errors
         match &self.error {
             // Don't emit a new diagnostic for these errors
             err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
-                return ErrorHandled::TooGeneric;
-            }
-            err_inval!(AlreadyReported(error_reported)) => {
-                return ErrorHandled::Reported(*error_reported);
+                ErrorHandled::TooGeneric
             }
+            err_inval!(AlreadyReported(error_reported)) => ErrorHandled::Reported(*error_reported),
             err_inval!(Layout(LayoutError::SizeOverflow(_))) => {
                 // We must *always* hard error on these, even if the caller wants just a lint.
                 // The `message` makes little sense here, this is a more serious error than the
                 // caller thinks anyway.
                 // See <https://github.com/rust-lang/rust/pull/63152>.
                 let mut err = struct_error(tcx, &self.error.to_string());
-                finish(&mut err, None);
-                return ErrorHandled::Reported(err.emit());
+                self.decorate(&mut err, decorate);
+                ErrorHandled::Reported(err.emit())
             }
-            _ => {}
-        };
-
-        let err_msg = self.error.to_string();
-
-        // Report as hard error.
-        let mut err = struct_error(tcx, message);
-        finish(&mut err, Some(err_msg));
-        ErrorHandled::Reported(err.emit())
+            _ => {
+                // Report as hard error.
+                let mut err = struct_error(tcx, message);
+                err.span_label(self.span, self.error.to_string());
+                self.decorate(&mut err, decorate);
+                ErrorHandled::Reported(err.emit())
+            }
+        }
     }
 }
index 319f2b2c25ebf320f71c6d0fe83bca042fe3f191..18e01567ca35e44888e52e19abd6bb07edca0d0e 100644 (file)
@@ -1,3 +1,4 @@
+use crate::const_eval::CheckAlignment;
 use std::borrow::Cow;
 
 use either::{Left, Right};
@@ -76,7 +77,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
             None => InternKind::Constant,
         }
     };
-    ecx.machine.check_alignment = false; // interning doesn't need to respect alignment
+    ecx.machine.check_alignment = CheckAlignment::No; // interning doesn't need to respect alignment
     intern_const_alloc_recursive(ecx, intern_kind, &ret)?;
     // we leave alignment checks off, since this `ecx` will not be used for further evaluation anyway
 
@@ -102,11 +103,7 @@ pub(super) fn mk_eval_cx<'mir, 'tcx>(
         tcx,
         root_span,
         param_env,
-        CompileTimeInterpreter::new(
-            tcx.const_eval_limit(),
-            can_access_statics,
-            /*check_alignment:*/ false,
-        ),
+        CompileTimeInterpreter::new(tcx.const_eval_limit(), can_access_statics, CheckAlignment::No),
     )
 }
 
@@ -311,7 +308,11 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
         CompileTimeInterpreter::new(
             tcx.const_eval_limit(),
             /*can_access_statics:*/ is_static,
-            /*check_alignment:*/ tcx.sess.opts.unstable_opts.extra_const_ub_checks,
+            if tcx.sess.opts.unstable_opts.extra_const_ub_checks {
+                CheckAlignment::Error
+            } else {
+                CheckAlignment::FutureIncompat
+            },
         ),
     );
 
index 3dfded2d930a052c305859ed257536285303eda8..e006a62feeabd12bc568da7c5c42e76bdde1cc2f 100644 (file)
@@ -1,9 +1,10 @@
 use rustc_hir::def::DefKind;
-use rustc_hir::LangItem;
+use rustc_hir::{LangItem, CRATE_HIR_ID};
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::PointerArithmetic;
 use rustc_middle::ty::layout::FnAbiOf;
 use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_session::lint::builtin::INVALID_ALIGNMENT;
 use std::borrow::Borrow;
 use std::hash::Hash;
 use std::ops::ControlFlow;
@@ -47,14 +48,34 @@ pub struct CompileTimeInterpreter<'mir, 'tcx> {
     pub(super) can_access_statics: bool,
 
     /// Whether to check alignment during evaluation.
-    pub(super) check_alignment: bool,
+    pub(super) check_alignment: CheckAlignment,
+}
+
+#[derive(Copy, Clone)]
+pub enum CheckAlignment {
+    /// Ignore alignment when following relocations.
+    /// This is mainly used in interning.
+    No,
+    /// Hard error when dereferencing a misaligned pointer.
+    Error,
+    /// Emit a future incompat lint when dereferencing a misaligned pointer.
+    FutureIncompat,
+}
+
+impl CheckAlignment {
+    pub fn should_check(&self) -> bool {
+        match self {
+            CheckAlignment::No => false,
+            CheckAlignment::Error | CheckAlignment::FutureIncompat => true,
+        }
+    }
 }
 
 impl<'mir, 'tcx> CompileTimeInterpreter<'mir, 'tcx> {
     pub(crate) fn new(
         const_eval_limit: Limit,
         can_access_statics: bool,
-        check_alignment: bool,
+        check_alignment: CheckAlignment,
     ) -> Self {
         CompileTimeInterpreter {
             steps_remaining: const_eval_limit.0,
@@ -309,7 +330,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
     const PANIC_ON_ALLOC_FAIL: bool = false; // will be raised as a proper error
 
     #[inline(always)]
-    fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
+    fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> CheckAlignment {
         ecx.machine.check_alignment
     }
 
@@ -318,6 +339,36 @@ fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
         ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks
     }
 
+    fn alignment_check_failed(
+        ecx: &InterpCx<'mir, 'tcx, Self>,
+        has: Align,
+        required: Align,
+        check: CheckAlignment,
+    ) -> InterpResult<'tcx, ()> {
+        let err = err_ub!(AlignmentCheckFailed { has, required }).into();
+        match check {
+            CheckAlignment::Error => Err(err),
+            CheckAlignment::No => span_bug!(
+                ecx.cur_span(),
+                "`alignment_check_failed` called when no alignment check requested"
+            ),
+            CheckAlignment::FutureIncompat => {
+                let err = ConstEvalErr::new(ecx, err, None);
+                ecx.tcx.struct_span_lint_hir(
+                    INVALID_ALIGNMENT,
+                    ecx.stack().iter().find_map(|frame| frame.lint_root()).unwrap_or(CRATE_HIR_ID),
+                    err.span,
+                    err.error.to_string(),
+                    |db| {
+                        err.decorate(db, |_| {});
+                        db
+                    },
+                );
+                Ok(())
+            }
+        }
+    }
+
     fn load_mir(
         ecx: &InterpCx<'mir, 'tcx, Self>,
         instance: ty::InstanceDef<'tcx>,
index b1fdeb01b100abd58f5b0b44c678b07ffc2ebe75..986b6d655300168046dad275e318667b1adff014 100644 (file)
@@ -332,7 +332,7 @@ fn unsize_into_ptr(
                     Immediate::new_slice(ptr, length.eval_usize(*self.tcx, self.param_env), self);
                 self.write_immediate(val, dest)
             }
-            (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => {
+            (ty::Dynamic(data_a, ..), ty::Dynamic(data_b, ..)) => {
                 let val = self.read_immediate(src)?;
                 if data_a.principal() == data_b.principal() {
                     // A NOP cast that doesn't actually change anything, should be allowed even with mismatching vtables.
index 0b2809f1d2c285238c1a93a8bb65fc314483de87..f551b5c29114d9984fcf108ceb1b9e12628db580 100644 (file)
@@ -248,6 +248,15 @@ pub fn current_span(&self) -> Span {
             Right(span) => span,
         }
     }
+
+    pub fn lint_root(&self) -> Option<hir::HirId> {
+        self.current_source_info().and_then(|source_info| {
+            match &self.body.source_scopes[source_info.scope].local_data {
+                mir::ClearCrossCrate::Set(data) => Some(data.lint_root),
+                mir::ClearCrossCrate::Clear => None,
+            }
+        })
+    }
 }
 
 impl<'tcx> fmt::Display for FrameInfo<'tcx> {
@@ -954,12 +963,7 @@ pub fn generate_stacktrace_from_stack(
         // This deliberately does *not* honor `requires_caller_location` since it is used for much
         // more than just panics.
         for frame in stack.iter().rev() {
-            let lint_root = frame.current_source_info().and_then(|source_info| {
-                match &frame.body.source_scopes[source_info.scope].local_data {
-                    mir::ClearCrossCrate::Set(data) => Some(data.lint_root),
-                    mir::ClearCrossCrate::Clear => None,
-                }
-            });
+            let lint_root = frame.lint_root();
             let span = frame.current_span();
 
             frames.push(FrameInfo { span, instance: frame.instance, lint_root });
index 0604d5ee6fa4c93e94211111da45abd2e4715f15..1d4ef20d0651f7bd11d7cb466f0290d375ff27d8 100644 (file)
 use rustc_middle::mir;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::def_id::DefId;
-use rustc_target::abi::Size;
+use rustc_target::abi::{Align, Size};
 use rustc_target::spec::abi::Abi as CallAbi;
 
+use crate::const_eval::CheckAlignment;
+
 use super::{
     AllocId, AllocRange, Allocation, ConstAllocation, Frame, ImmTy, InterpCx, InterpResult,
     MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar, StackPopUnwind,
@@ -122,7 +124,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
     const PANIC_ON_ALLOC_FAIL: bool;
 
     /// Whether memory accesses should be alignment-checked.
-    fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
+    fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> CheckAlignment;
 
     /// Whether, when checking alignment, we should look at the actual address and thus support
     /// custom alignment logic based on whatever the integer address happens to be.
@@ -130,6 +132,13 @@ pub trait Machine<'mir, 'tcx>: Sized {
     /// If this returns true, Provenance::OFFSET_IS_ADDR must be true.
     fn use_addr_for_alignment_check(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
 
+    fn alignment_check_failed(
+        ecx: &InterpCx<'mir, 'tcx, Self>,
+        has: Align,
+        required: Align,
+        check: CheckAlignment,
+    ) -> InterpResult<'tcx, ()>;
+
     /// Whether to enforce the validity invariant
     fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
 
index 528c1cb06c0ebadf1e2ca0cb324cc51bd8c0e794..5b1ac6b2f65e29f7bc7a726d3044a6fd5cb95654 100644 (file)
@@ -18,6 +18,8 @@
 use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TyCtxt};
 use rustc_target::abi::{Align, HasDataLayout, Size};
 
+use crate::const_eval::CheckAlignment;
+
 use super::{
     alloc_range, AllocId, AllocMap, AllocRange, Allocation, CheckInAllocMsg, GlobalAlloc, InterpCx,
     InterpResult, Machine, MayLeak, Pointer, PointerArithmetic, Provenance, Scalar,
@@ -349,11 +351,11 @@ fn get_ptr_access(
         size: Size,
         align: Align,
     ) -> InterpResult<'tcx, Option<(AllocId, Size, M::ProvenanceExtra)>> {
-        let align = M::enforce_alignment(&self).then_some(align);
         self.check_and_deref_ptr(
             ptr,
             size,
             align,
+            M::enforce_alignment(self),
             CheckInAllocMsg::MemoryAccessTest,
             |alloc_id, offset, prov| {
                 let (size, align) = self.get_live_alloc_size_and_align(alloc_id)?;
@@ -373,10 +375,17 @@ pub fn check_ptr_access_align(
         align: Align,
         msg: CheckInAllocMsg,
     ) -> InterpResult<'tcx> {
-        self.check_and_deref_ptr(ptr, size, Some(align), msg, |alloc_id, _, _| {
-            let (size, align) = self.get_live_alloc_size_and_align(alloc_id)?;
-            Ok((size, align, ()))
-        })?;
+        self.check_and_deref_ptr(
+            ptr,
+            size,
+            align,
+            CheckAlignment::Error,
+            msg,
+            |alloc_id, _, _| {
+                let (size, align) = self.get_live_alloc_size_and_align(alloc_id)?;
+                Ok((size, align, ()))
+            },
+        )?;
         Ok(())
     }
 
@@ -388,7 +397,8 @@ fn check_and_deref_ptr<T>(
         &self,
         ptr: Pointer<Option<M::Provenance>>,
         size: Size,
-        align: Option<Align>,
+        align: Align,
+        check: CheckAlignment,
         msg: CheckInAllocMsg,
         alloc_size: impl FnOnce(
             AllocId,
@@ -396,19 +406,6 @@ fn check_and_deref_ptr<T>(
             M::ProvenanceExtra,
         ) -> InterpResult<'tcx, (Size, Align, T)>,
     ) -> InterpResult<'tcx, Option<T>> {
-        fn check_offset_align<'tcx>(offset: u64, align: Align) -> InterpResult<'tcx> {
-            if offset % align.bytes() == 0 {
-                Ok(())
-            } else {
-                // The biggest power of two through which `offset` is divisible.
-                let offset_pow2 = 1 << offset.trailing_zeros();
-                throw_ub!(AlignmentCheckFailed {
-                    has: Align::from_bytes(offset_pow2).unwrap(),
-                    required: align,
-                })
-            }
-        }
-
         Ok(match self.ptr_try_get_alloc_id(ptr) {
             Err(addr) => {
                 // We couldn't get a proper allocation. This is only okay if the access size is 0,
@@ -417,8 +414,8 @@ fn check_offset_align<'tcx>(offset: u64, align: Align) -> InterpResult<'tcx> {
                     throw_ub!(DanglingIntPointer(addr, msg));
                 }
                 // Must be aligned.
-                if let Some(align) = align {
-                    check_offset_align(addr, align)?;
+                if check.should_check() {
+                    self.check_offset_align(addr, align, check)?;
                 }
                 None
             }
@@ -441,16 +438,16 @@ fn check_offset_align<'tcx>(offset: u64, align: Align) -> InterpResult<'tcx> {
                 }
                 // Test align. Check this last; if both bounds and alignment are violated
                 // we want the error to be about the bounds.
-                if let Some(align) = align {
+                if check.should_check() {
                     if M::use_addr_for_alignment_check(self) {
                         // `use_addr_for_alignment_check` can only be true if `OFFSET_IS_ADDR` is true.
-                        check_offset_align(ptr.addr().bytes(), align)?;
+                        self.check_offset_align(ptr.addr().bytes(), align, check)?;
                     } else {
                         // Check allocation alignment and offset alignment.
                         if alloc_align.bytes() < align.bytes() {
-                            throw_ub!(AlignmentCheckFailed { has: alloc_align, required: align });
+                            M::alignment_check_failed(self, alloc_align, align, check)?;
                         }
-                        check_offset_align(offset.bytes(), align)?;
+                        self.check_offset_align(offset.bytes(), align, check)?;
                     }
                 }
 
@@ -460,6 +457,21 @@ fn check_offset_align<'tcx>(offset: u64, align: Align) -> InterpResult<'tcx> {
             }
         })
     }
+
+    fn check_offset_align(
+        &self,
+        offset: u64,
+        align: Align,
+        check: CheckAlignment,
+    ) -> InterpResult<'tcx> {
+        if offset % align.bytes() == 0 {
+            Ok(())
+        } else {
+            // The biggest power of two through which `offset` is divisible.
+            let offset_pow2 = 1 << offset.trailing_zeros();
+            M::alignment_check_failed(self, Align::from_bytes(offset_pow2).unwrap(), align, check)
+        }
+    }
 }
 
 /// Allocation accessors
@@ -560,11 +572,11 @@ pub fn get_ptr_alloc<'a>(
         size: Size,
         align: Align,
     ) -> InterpResult<'tcx, Option<AllocRef<'a, 'tcx, M::Provenance, M::AllocExtra>>> {
-        let align = M::enforce_alignment(self).then_some(align);
         let ptr_and_alloc = self.check_and_deref_ptr(
             ptr,
             size,
             align,
+            M::enforce_alignment(self),
             CheckInAllocMsg::MemoryAccessTest,
             |alloc_id, offset, prov| {
                 let alloc = self.get_alloc_raw(alloc_id)?;
index 221e359d24ab8d517a1d98ed60de780bdea9c468..f9e3a2bdc06fe528dcb3bcfa7ef980a2cf3a2d41 100644 (file)
@@ -39,7 +39,7 @@ pub enum Immediate<Prov: Provenance = AllocId> {
 impl<Prov: Provenance> From<Scalar<Prov>> for Immediate<Prov> {
     #[inline(always)]
     fn from(val: Scalar<Prov>) -> Self {
-        Immediate::Scalar(val.into())
+        Immediate::Scalar(val)
     }
 }
 
@@ -53,7 +53,7 @@ pub fn from_maybe_pointer(p: Pointer<Option<Prov>>, cx: &impl HasDataLayout) ->
     }
 
     pub fn new_slice(val: Scalar<Prov>, len: u64, cx: &impl HasDataLayout) -> Self {
-        Immediate::ScalarPair(val.into(), Scalar::from_machine_usize(len, cx).into())
+        Immediate::ScalarPair(val, Scalar::from_machine_usize(len, cx))
     }
 
     pub fn new_dyn_trait(
@@ -61,7 +61,7 @@ pub fn new_dyn_trait(
         vtable: Pointer<Option<Prov>>,
         cx: &impl HasDataLayout,
     ) -> Self {
-        Immediate::ScalarPair(val.into(), Scalar::from_maybe_pointer(vtable, cx))
+        Immediate::ScalarPair(val, Scalar::from_maybe_pointer(vtable, cx))
     }
 
     #[inline]
@@ -341,10 +341,7 @@ fn read_immediate_from_mplace_raw(
                     alloc_range(b_offset, b_size),
                     /*read_provenance*/ b.is_ptr(),
                 )?;
-                Some(ImmTy {
-                    imm: Immediate::ScalarPair(a_val.into(), b_val.into()),
-                    layout: mplace.layout,
-                })
+                Some(ImmTy { imm: Immediate::ScalarPair(a_val, b_val), layout: mplace.layout })
             }
             _ => {
                 // Neither a scalar nor scalar pair.
index 949f95c5fa81c2a8909ac6fd353b8578946b9535..e8ff70e3a4095075ebe765e16a18549decfd866d 100644 (file)
@@ -36,7 +36,7 @@ pub fn binop_with_overflow(
         if let Abi::ScalarPair(..) = dest.layout.abi {
             // We can use the optimized path and avoid `place_field` (which might do
             // `force_allocation`).
-            let pair = Immediate::ScalarPair(val.into(), Scalar::from_bool(overflowed).into());
+            let pair = Immediate::ScalarPair(val, Scalar::from_bool(overflowed));
             self.write_immediate(pair, dest)?;
         } else {
             assert!(self.tcx.sess.opts.unstable_opts.randomize_layout);
index c47cfe8bb69fd05831734e1f42cf16e3781d7049..97a73e98abcbca9d563027620fc8a74630014606 100644 (file)
@@ -141,7 +141,7 @@ pub fn to_ref(self, cx: &impl HasDataLayout) -> Immediate<Prov> {
         match self.meta {
             MemPlaceMeta::None => Immediate::from(Scalar::from_maybe_pointer(self.ptr, cx)),
             MemPlaceMeta::Meta(meta) => {
-                Immediate::ScalarPair(Scalar::from_maybe_pointer(self.ptr, cx).into(), meta.into())
+                Immediate::ScalarPair(Scalar::from_maybe_pointer(self.ptr, cx), meta)
             }
         }
     }
@@ -364,13 +364,8 @@ pub fn check_mplace(&self, mplace: MPlaceTy<'tcx, M::Provenance>) -> InterpResul
             .size_and_align_of_mplace(&mplace)?
             .unwrap_or((mplace.layout.size, mplace.layout.align.abi));
         assert!(mplace.align <= align, "dynamic alignment less strict than static one?");
-        let align = M::enforce_alignment(self).then_some(align);
-        self.check_ptr_access_align(
-            mplace.ptr,
-            size,
-            align.unwrap_or(Align::ONE),
-            CheckInAllocMsg::DerefTest,
-        )?;
+        let align = if M::enforce_alignment(self).should_check() { align } else { Align::ONE };
+        self.check_ptr_access_align(mplace.ptr, size, align, CheckInAllocMsg::DerefTest)?;
         Ok(())
     }
 
index 6ca71223391d2a5828b39b655cb113473cd0e46f..4ce107ea68d4f0f3869cebe3cce00c706a42f58d 100644 (file)
@@ -3,7 +3,7 @@
 use rustc_session::Limit;
 use rustc_target::abi::{Abi, FieldsShape, InitKind, Scalar, Variants};
 
-use crate::const_eval::CompileTimeInterpreter;
+use crate::const_eval::{CheckAlignment, CompileTimeInterpreter};
 use crate::interpret::{InterpCx, MemoryKind, OpTy};
 
 /// Determines if this type permits "raw" initialization by just transmuting some memory into an
@@ -41,7 +41,7 @@ fn might_permit_raw_init_strict<'tcx>(
     let machine = CompileTimeInterpreter::new(
         Limit::new(0),
         /*can_access_statics:*/ false,
-        /*check_alignment:*/ true,
+        CheckAlignment::Error,
     );
 
     let mut cx = InterpCx::new(tcx, rustc_span::DUMMY_SP, ParamEnv::reveal_all(), machine);
index 5afce15e26bfcc55e3fa8c7454c010dc0aca2296..0366fb0a148c7c1c6e22f33e2171c520b7579f44 100644 (file)
@@ -8,7 +8,7 @@ edition = "2021"
 [dependencies]
 arrayvec = { version = "0.7", default-features = false }
 bitflags = "1.2.1"
-cfg-if = "0.1.2"
+cfg-if = "1.0"
 ena = "0.14"
 indexmap = { version = "1.9.1" }
 jobserver_crate = { version = "0.1.13", package = "jobserver" }
@@ -21,7 +21,11 @@ rustc-hash = "1.1.0"
 rustc_index = { path = "../rustc_index", package = "rustc_index" }
 rustc_macros = { path = "../rustc_macros" }
 rustc_serialize = { path = "../rustc_serialize" }
-smallvec = { version = "1.8.1", features = ["const_generics", "union", "may_dangle"] }
+smallvec = { version = "1.8.1", features = [
+    "const_generics",
+    "union",
+    "may_dangle",
+] }
 stable_deref_trait = "1.0.0"
 stacker = "0.1.15"
 tempfile = "3.2"
index 00913a483db0efe6bc39aeb1743f30ee2351181b..94a8c1fc051dd6f3bb9aedcab3b33a74e0adca80 100644 (file)
@@ -22,7 +22,7 @@ struct PreOrderFrame<Iter> {
 }
 
 rustc_index::newtype_index! {
-    struct PreorderIndex { .. }
+    struct PreorderIndex {}
 }
 
 pub fn dominators<G: ControlFlowGraph>(graph: G) -> Dominators<G::Node> {
index 31a709c36d4bc57461cf93cc57840ece6635ebc2..276f83f1f237dd93a0f84ecc3f45ab4d28a40ce9 100644 (file)
 E0312: include_str!("./error_codes/E0312.md"),
 E0316: include_str!("./error_codes/E0316.md"),
 E0317: include_str!("./error_codes/E0317.md"),
+E0320: include_str!("./error_codes/E0320.md"),
 E0321: include_str!("./error_codes/E0321.md"),
 E0322: include_str!("./error_codes/E0322.md"),
 E0323: include_str!("./error_codes/E0323.md"),
 E0374: include_str!("./error_codes/E0374.md"),
 E0375: include_str!("./error_codes/E0375.md"),
 E0376: include_str!("./error_codes/E0376.md"),
+E0377: include_str!("./error_codes/E0377.md"),
 E0378: include_str!("./error_codes/E0378.md"),
 E0379: include_str!("./error_codes/E0379.md"),
 E0380: include_str!("./error_codes/E0380.md"),
 E0453: include_str!("./error_codes/E0453.md"),
 E0454: include_str!("./error_codes/E0454.md"),
 E0455: include_str!("./error_codes/E0455.md"),
+E0457: include_str!("./error_codes/E0457.md"),
 E0458: include_str!("./error_codes/E0458.md"),
 E0459: include_str!("./error_codes/E0459.md"),
+E0460: include_str!("./error_codes/E0460.md"),
 E0463: include_str!("./error_codes/E0463.md"),
 E0464: include_str!("./error_codes/E0464.md"),
 E0466: include_str!("./error_codes/E0466.md"),
 E0468: include_str!("./error_codes/E0468.md"),
 E0469: include_str!("./error_codes/E0469.md"),
+E0472: include_str!("./error_codes/E0472.md"),
 E0477: include_str!("./error_codes/E0477.md"),
 E0478: include_str!("./error_codes/E0478.md"),
 E0482: include_str!("./error_codes/E0482.md"),
 //  E0314, // closure outlives stack frame
 //  E0315, // cannot invoke closure outside of its lifetime
 //  E0319, // trait impls for defaulted traits allowed just for structs/enums
-    E0320, // recursive overflow during dropck
 //  E0372, // coherence not object safe
-    E0377, // the trait `CoerceUnsized` may only be implemented for a coercion
-           // between structures with the same definition
 //  E0385, // {} in an aliasable location
 //  E0402, // cannot use an outer type parameter in this context
 //  E0406, // merged into 420
 //  E0421, // merged into 531
 //  E0427, // merged into 530
 //  E0456, // plugin `..` is not available for triple `..`
-    E0457, // plugin `..` only found in rlib format, but must be available...
-    E0460, // found possibly newer version of crate `..`
     E0461, // couldn't find crate `..` with expected target triple ..
     E0462, // found staticlib `..` instead of rlib or dylib
     E0465, // multiple .. candidates for `..` found
 //  E0467, // removed
 //  E0470, // removed
 //  E0471, // constant evaluation error (in pattern)
-    E0472, // llvm_asm! is unsupported on this target
 //  E0473, // dereference of reference outside its lifetime
 //  E0474, // captured variable `..` does not outlive the enclosing closure
 //  E0475, // index of slice outside its lifetime
index 0a9ef9c39385cc6aa18af1c4e22df9a05ba70179..03b93d925c19a3f5c0eab3202af14735ab04cfdf 100644 (file)
@@ -1,38 +1,53 @@
-An associated const has been referenced in a pattern.
+An associated `const`, `const` parameter or `static` has been referenced
+in a pattern.
 
 Erroneous code example:
 
 ```compile_fail,E0158
-enum EFoo { A, B, C, D }
+enum Foo {
+    One,
+    Two
+}
 
-trait Foo {
-    const X: EFoo;
+trait Bar {
+    const X: Foo;
 }
 
-fn test<A: Foo>(arg: EFoo) {
+fn test<A: Bar>(arg: Foo) {
     match arg {
-        A::X => { // error!
-            println!("A::X");
-        }
+        A::X => println!("A::X"), // error: E0158: associated consts cannot be
+                                  //        referenced in patterns
+        Foo::Two => println!("Two")
     }
 }
 ```
 
-`const` and `static` mean different things. A `const` is a compile-time
-constant, an alias for a literal value. This property means you can match it
-directly within a pattern.
+Associated `const`s cannot be referenced in patterns because it is impossible
+for the compiler to prove exhaustiveness (that some pattern will always match).
+Take the above example, because Rust does type checking in the *generic*
+method, not the *monomorphized* specific instance. So because `Bar` could have
+theoretically infinite implementations, there's no way to always be sure that
+`A::X` is `Foo::One`. So this code must be rejected. Even if code can be
+proven exhaustive by a programmer, the compiler cannot currently prove this.
 
-The `static` keyword, on the other hand, guarantees a fixed location in memory.
-This does not always mean that the value is constant. For example, a global
-mutex can be declared `static` as well.
+The same holds true of `const` parameters and `static`s.
 
-If you want to match against a `static`, consider using a guard instead:
+If you want to match against an associated `const`, `const` parameter or
+`static` consider using a guard instead:
 
 ```
-static FORTY_TWO: i32 = 42;
+trait Trait {
+    const X: char;
+}
+
+static FOO: char = 'j';
 
-match Some(42) {
-    Some(x) if x == FORTY_TWO => {}
-    _ => {}
+fn test<A: Trait, const Y: char>(arg: char) {
+    match arg {
+        c if c == A::X => println!("A::X"),
+        c if c == Y => println!("Y"),
+        c if c == FOO => println!("FOO"),
+        _ => ()
+    }
 }
 ```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0320.md b/compiler/rustc_error_codes/src/error_codes/E0320.md
new file mode 100644 (file)
index 0000000..e6e1b7c
--- /dev/null
@@ -0,0 +1,27 @@
+Recursion limit reached while creating drop-check rules.
+
+Example of erroneous code:
+
+```compile_fail,E0320
+enum A<T> {
+    B,
+    C(T, Box<A<(T, T)>>)
+}
+
+fn foo<T>() {
+    A::<T>::B; // error: overflow while adding drop-check rules for A<T>
+}
+```
+
+The Rust compiler must be able to reason about how a type is [`Drop`]ped, and
+by extension the types of its fields, to be able to generate the glue to
+properly drop a value. The code example above shows a type where this inference
+is impossible because it is recursive. Note that this is *not* the same as
+[E0072](E0072.html), where a type has an infinite size; the type here has a
+finite size but any attempt to `Drop` it would recurse infinitely. For more
+information, read [the `Drop` docs](../std/ops/trait.Drop.html).
+
+It is not possible to define a type with recursive drop-check rules. All such
+recursion must be removed.
+
+[`Drop`]: ../std/ops/trait.Drop.html
diff --git a/compiler/rustc_error_codes/src/error_codes/E0377.md b/compiler/rustc_error_codes/src/error_codes/E0377.md
new file mode 100644 (file)
index 0000000..b1d3640
--- /dev/null
@@ -0,0 +1,29 @@
+The trait `CoerceUnsized` may only be implemented for a coercion between
+structures with the same definition.
+
+Example of erroneous code:
+
+```compile_fail,E0377
+#![feature(coerce_unsized)]
+use std::ops::CoerceUnsized;
+
+pub struct Foo<T: ?Sized> {
+    field_with_unsized_type: T,
+}
+
+pub struct Bar<T: ?Sized> {
+    field_with_unsized_type: T,
+}
+
+// error: the trait `CoerceUnsized` may only be implemented for a coercion
+//        between structures with the same definition
+impl<T, U> CoerceUnsized<Bar<U>> for Foo<T> where T: CoerceUnsized<U> {}
+```
+
+When attempting to implement `CoerceUnsized`, the `impl` signature must look
+like: `impl CoerceUnsized<Type<U>> for Type<T> where T: CoerceUnsized<U>`;
+the *implementer* and *`CoerceUnsized` type parameter* must be the same
+type. In this example, `Bar` and `Foo` (even though structurally identical)
+are *not* the same type and are rejected. Learn more about the `CoerceUnsized`
+trait and DST coercion in
+[the `CoerceUnsized` docs](../std/ops/trait.CoerceUnsized.html).
diff --git a/compiler/rustc_error_codes/src/error_codes/E0457.md b/compiler/rustc_error_codes/src/error_codes/E0457.md
new file mode 100644 (file)
index 0000000..53d384d
--- /dev/null
@@ -0,0 +1,36 @@
+Plugin `..` only found in rlib format, but must be available in dylib format.
+
+Erroronous code example:
+
+`rlib-plugin.rs`
+```ignore (needs-linkage-with-other-tests)
+#![crate_type = "rlib"]
+#![feature(rustc_private)]
+
+extern crate rustc_middle;
+extern crate rustc_driver;
+
+use rustc_driver::plugin::Registry;
+
+#[no_mangle]
+fn __rustc_plugin_registrar(_: &mut Registry) {}
+```
+
+`main.rs`
+```ignore (needs-linkage-with-other-tests)
+#![feature(plugin)]
+#![plugin(rlib_plugin)] // error: plugin `rlib_plugin` only found in rlib
+                        //        format, but must be available in dylib
+
+fn main() {}
+```
+
+The compiler exposes a plugin interface to allow altering the compile process
+(adding lints, etc). Plugins must be defined in their own crates (similar to
+[proc-macro](../reference/procedural-macros.html) isolation) and then compiled
+and linked to another crate. Plugin crates *must* be compiled to the
+dynamically-linked dylib format, and not the statically-linked rlib format.
+Learn more about different output types in
+[this section](../reference/linkage.html) of the Rust reference.
+
+This error is easily fixed by recompiling the plugin crate in the dylib format.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0460.md b/compiler/rustc_error_codes/src/error_codes/E0460.md
new file mode 100644 (file)
index 0000000..001678a
--- /dev/null
@@ -0,0 +1,71 @@
+Found possibly newer version of crate `..` which `..` depends on.
+
+Consider these erroneous files:
+
+`a1.rs`
+```ignore (needs-linkage-with-other-tests)
+#![crate_name = "a"]
+
+pub fn foo<T>() {}
+```
+
+`a2.rs`
+```ignore (needs-linkage-with-other-tests)
+#![crate_name = "a"]
+
+pub fn foo<T>() {
+    println!("foo<T>()");
+}
+```
+
+`b.rs`
+```ignore (needs-linkage-with-other-tests)
+#![crate_name = "b"]
+
+extern crate a; // linked with `a1.rs`
+
+pub fn foo() {
+    a::foo::<isize>();
+}
+```
+
+`main.rs`
+```ignore (needs-linkage-with-other-tests)
+extern crate a; // linked with `a2.rs`
+extern crate b; // error: found possibly newer version of crate `a` which `b`
+                //        depends on
+
+fn main() {}
+```
+
+The dependency graph of this program can be represented as follows:
+```text
+    crate `main`
+         |
+         +-------------+
+         |             |
+         |             v
+depends: |         crate `b`
+ `a` v1  |             |
+         |             | depends:
+         |             |  `a` v2
+         v             |
+      crate `a` <------+
+```
+
+Crate `main` depends on crate `a` (version 1) and crate `b` which in turn
+depends on crate `a` (version 2); this discrepancy in versions cannot be
+reconciled. This difference in versions typically occurs when one crate is
+compiled and linked, then updated and linked to another crate. The crate
+"version" is a SVH (Strict Version Hash) of the crate in an
+implementation-specific way. Note that this error can *only* occur when
+directly compiling and linking with `rustc`; [Cargo] automatically resolves
+dependencies, without using the compiler's own dependency management that
+causes this issue.
+
+This error can be fixed by:
+ * Using [Cargo], the Rust package manager, automatically fixing this issue.
+ * Recompiling crate `a` so that both crate `b` and `main` have a uniform
+   version to depend on.
+
+[Cargo]: ../cargo/index.html
diff --git a/compiler/rustc_error_codes/src/error_codes/E0472.md b/compiler/rustc_error_codes/src/error_codes/E0472.md
new file mode 100644 (file)
index 0000000..0005cd4
--- /dev/null
@@ -0,0 +1,31 @@
+Inline assembly (`asm!`) is not supported on this target.
+
+Example of erroneous code:
+
+```ignore (cannot-change-target)
+// compile-flags: --target sparc64-unknown-linux-gnu
+#![no_std]
+
+use core::arch::asm;
+
+fn main() {
+    unsafe {
+        asm!(""); // error: inline assembly is not supported on this target
+    }
+}
+```
+
+The Rust compiler does not support inline assembly, with the `asm!` macro
+(previously `llvm_asm!`), for all targets. All Tier 1 targets do support this
+macro but support among Tier 2 and 3 targets is not guaranteed (even when they
+have `std` support). Note that this error is related to
+`error[E0658]: inline assembly is not stable yet on this architecture`, but
+distinct in that with `E0472` support is not planned or in progress.
+
+There is no way to easily fix this issue, however:
+ * Consider if you really need inline assembly, is there some other way to
+   achieve your goal (intrinsics, etc)?
+ * Consider writing your assembly externally, linking with it and calling it
+   from Rust.
+ * Consider contributing to <https://github.com/rust-lang/rust> and help
+   integrate support for your target!
index 97198cb4be2c827def75802a49b4af95bc5adaf0..860212b051f39c4a8739110e9bf1edf220aa23cf 100644 (file)
@@ -17,9 +17,6 @@ codegen_llvm_instrument_coverage_requires_llvm_12 =
 codegen_llvm_symbol_already_defined =
     symbol `{$symbol_name}` is already defined
 
-codegen_llvm_branch_protection_requires_aarch64 =
-    -Zbranch-protection is only supported on aarch64
-
 codegen_llvm_invalid_minimum_alignment =
     invalid minimum global alignment: {$err}
 
index d1e1fd54db9bf22bcacc11f105c8b56be3dc5c36..b3ca540417da79876f17449c5a2d4aa82d767861 100644 (file)
@@ -166,12 +166,6 @@ metadata_conflicting_alloc_error_handler =
 metadata_global_alloc_required =
     no global memory allocator found but one is required; link to std or add `#[global_allocator]` to a static item that implements the GlobalAlloc trait
 
-metadata_alloc_func_required =
-    `#[alloc_error_handler]` function required, but not found
-
-metadata_missing_alloc_error_handler =
-    use `#![feature(default_alloc_error_handler)]` for a default error handler
-
 metadata_no_transitive_needs_dep =
     the crate `{$crate_name}` cannot depend on a crate that needs {$needs_crate_name}, but it depends on `{$deps_crate_name}`
 
diff --git a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
new file mode 100644 (file)
index 0000000..60d3d3e
--- /dev/null
@@ -0,0 +1,301 @@
+mir_build_unconditional_recursion = function cannot return without recursing
+    .label = cannot return without recursing
+    .help = a `loop` may express intention better if this is on purpose
+
+mir_build_unconditional_recursion_call_site_label = recursive call site
+
+mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe =
+    call to unsafe function `{$function}` is unsafe and requires unsafe block (error E0133)
+    .note = consult the function's documentation for information on how to avoid undefined behavior
+    .label = call to unsafe function
+
+mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe_nameless =
+    call to unsafe function is unsafe and requires unsafe block (error E0133)
+    .note = consult the function's documentation for information on how to avoid undefined behavior
+    .label = call to unsafe function
+
+mir_build_unsafe_op_in_unsafe_fn_inline_assembly_requires_unsafe =
+    use of inline assembly is unsafe and requires unsafe block (error E0133)
+    .note = inline assembly is entirely unchecked and can cause undefined behavior
+    .label = use of inline assembly
+
+mir_build_unsafe_op_in_unsafe_fn_initializing_type_with_requires_unsafe =
+    initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe
+    block (error E0133)
+    .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
+    .label = initializing type with `rustc_layout_scalar_valid_range` attr
+
+mir_build_unsafe_op_in_unsafe_fn_mutable_static_requires_unsafe =
+    use of mutable static is unsafe and requires unsafe block (error E0133)
+    .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+    .label = use of mutable static
+
+mir_build_unsafe_op_in_unsafe_fn_extern_static_requires_unsafe =
+    use of extern static is unsafe and requires unsafe block (error E0133)
+    .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+    .label = use of extern static
+
+mir_build_unsafe_op_in_unsafe_fn_deref_raw_pointer_requires_unsafe =
+    dereference of raw pointer is unsafe and requires unsafe block (error E0133)
+    .note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+    .label = dereference of raw pointer
+
+mir_build_unsafe_op_in_unsafe_fn_union_field_requires_unsafe =
+    access to union field is unsafe and requires unsafe block (error E0133)
+    .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
+    .label = access to union field
+
+mir_build_unsafe_op_in_unsafe_fn_mutation_of_layout_constrained_field_requires_unsafe =
+    mutation of layout constrained field is unsafe and requires unsafe block (error E0133)
+    .note = mutating layout constrained fields cannot statically be checked for valid values
+    .label = mutation of layout constrained field
+
+mir_build_unsafe_op_in_unsafe_fn_borrow_of_layout_constrained_field_requires_unsafe =
+    borrow of layout constrained field with interior mutability is unsafe and requires unsafe block (error E0133)
+    .note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values
+    .label = borrow of layout constrained field with interior mutability
+
+mir_build_unsafe_op_in_unsafe_fn_call_to_fn_with_requires_unsafe =
+    call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block (error E0133)
+    .note = can only be called if the required target features are available
+    .label = call to function with `#[target_feature]`
+
+mir_build_call_to_unsafe_fn_requires_unsafe =
+    call to unsafe function `{$function}` is unsafe and requires unsafe block
+    .note = consult the function's documentation for information on how to avoid undefined behavior
+    .label = call to unsafe function
+
+mir_build_call_to_unsafe_fn_requires_unsafe_nameless =
+    call to unsafe function is unsafe and requires unsafe block
+    .note = consult the function's documentation for information on how to avoid undefined behavior
+    .label = call to unsafe function
+
+mir_build_call_to_unsafe_fn_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+    call to unsafe function `{$function}` is unsafe and requires unsafe function or block
+    .note = consult the function's documentation for information on how to avoid undefined behavior
+    .label = call to unsafe function
+
+mir_build_call_to_unsafe_fn_requires_unsafe_nameless_unsafe_op_in_unsafe_fn_allowed =
+    call to unsafe function is unsafe and requires unsafe function or block
+    .note = consult the function's documentation for information on how to avoid undefined behavior
+    .label = call to unsafe function
+
+mir_build_inline_assembly_requires_unsafe =
+    use of inline assembly is unsafe and requires unsafe block
+    .note = inline assembly is entirely unchecked and can cause undefined behavior
+    .label = use of inline assembly
+
+mir_build_inline_assembly_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+    use of inline assembly is unsafe and requires unsafe function or block
+    .note = inline assembly is entirely unchecked and can cause undefined behavior
+    .label = use of inline assembly
+
+mir_build_initializing_type_with_requires_unsafe =
+    initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe block
+    .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
+    .label = initializing type with `rustc_layout_scalar_valid_range` attr
+
+mir_build_initializing_type_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+    initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe function or block
+    .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
+    .label = initializing type with `rustc_layout_scalar_valid_range` attr
+
+mir_build_mutable_static_requires_unsafe =
+    use of mutable static is unsafe and requires unsafe block
+    .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+    .label = use of mutable static
+
+mir_build_mutable_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+    use of mutable static is unsafe and requires unsafe function or block
+    .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+    .label = use of mutable static
+
+mir_build_extern_static_requires_unsafe =
+    use of extern static is unsafe and requires unsafe block
+    .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+    .label = use of extern static
+
+mir_build_extern_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+    use of extern static is unsafe and requires unsafe function or block
+    .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+    .label = use of extern static
+
+mir_build_deref_raw_pointer_requires_unsafe =
+    dereference of raw pointer is unsafe and requires unsafe block
+    .note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+    .label = dereference of raw pointer
+
+mir_build_deref_raw_pointer_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+    dereference of raw pointer is unsafe and requires unsafe function or block
+    .note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+    .label = dereference of raw pointer
+
+mir_build_union_field_requires_unsafe =
+    access to union field is unsafe and requires unsafe block
+    .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
+    .label = access to union field
+
+mir_build_union_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+    access to union field is unsafe and requires unsafe function or block
+    .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
+    .label = access to union field
+
+mir_build_mutation_of_layout_constrained_field_requires_unsafe =
+    mutation of layout constrained field is unsafe and requires unsafe block
+    .note = mutating layout constrained fields cannot statically be checked for valid values
+    .label = mutation of layout constrained field
+
+mir_build_mutation_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+    mutation of layout constrained field is unsafe and requires unsafe function or block
+    .note = mutating layout constrained fields cannot statically be checked for valid values
+    .label = mutation of layout constrained field
+
+mir_build_borrow_of_layout_constrained_field_requires_unsafe =
+    borrow of layout constrained field with interior mutability is unsafe and requires unsafe block
+    .note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values
+    .label = borrow of layout constrained field with interior mutability
+
+mir_build_borrow_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+    borrow of layout constrained field with interior mutability is unsafe and requires unsafe function or block
+    .note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values
+    .label = borrow of layout constrained field with interior mutability
+
+mir_build_call_to_fn_with_requires_unsafe =
+    call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block
+    .note = can only be called if the required target features are available
+    .label = call to function with `#[target_feature]`
+
+mir_build_call_to_fn_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+    call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe function or block
+    .note = can only be called if the required target features are available
+    .label = call to function with `#[target_feature]`
+
+mir_build_unused_unsafe = unnecessary `unsafe` block
+    .label = unnecessary `unsafe` block
+
+mir_build_unused_unsafe_enclosing_block_label = because it's nested under this `unsafe` block
+mir_build_unused_unsafe_enclosing_fn_label = because it's nested under this `unsafe` fn
+
+mir_build_non_exhaustive_patterns_type_not_empty = non-exhaustive patterns: type `{$ty}` is non-empty
+    .def_note = `{$peeled_ty}` defined here
+    .type_note = the matched value is of type `{$ty}`
+    .non_exhaustive_type_note = the matched value is of type `{$ty}`, which is marked as non-exhaustive
+    .reference_note = references are always considered inhabited
+    .suggestion = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+    .help = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
+
+mir_build_static_in_pattern = statics cannot be referenced in patterns
+
+mir_build_assoc_const_in_pattern = associated consts cannot be referenced in patterns
+
+mir_build_const_param_in_pattern = const parameters cannot be referenced in patterns
+
+mir_build_non_const_path = runtime values cannot be referenced in patterns
+
+mir_build_unreachable_pattern = unreachable pattern
+    .label = unreachable pattern
+    .catchall_label = matches any value
+
+mir_build_const_pattern_depends_on_generic_parameter =
+    constant pattern depends on a generic parameter
+
+mir_build_could_not_eval_const_pattern = could not evaluate constant pattern
+
+mir_build_lower_range_bound_must_be_less_than_or_equal_to_upper =
+    lower range bound must be less than or equal to upper
+    .label = lower bound larger than upper bound
+    .teach_note = When matching against a range, the compiler verifies that the range is non-empty. Range patterns include both end-points, so this is equivalent to requiring the start of the range to be less than or equal to the end of the range.
+
+mir_build_lower_range_bound_must_be_less_than_upper = lower range bound must be less than upper
+
+mir_build_leading_irrefutable_let_patterns = leading irrefutable {$count ->
+        [one] pattern
+        *[other] patterns
+    } in let chain
+    .note = {$count ->
+        [one] this pattern
+        *[other] these patterns
+    } will always match
+    .help = consider moving {$count ->
+        [one] it
+        *[other] them
+    } outside of the construct
+
+mir_build_trailing_irrefutable_let_patterns = trailing irrefutable {$count ->
+        [one] pattern
+        *[other] patterns
+    } in let chain
+    .note = {$count ->
+        [one] this pattern
+        *[other] these patterns
+    } will always match
+    .help = consider moving {$count ->
+        [one] it
+        *[other] them
+    } into the body
+
+mir_build_bindings_with_variant_name =
+    pattern binding `{$ident}` is named the same as one of the variants of the type `{$ty_path}`
+    .suggestion = to match on the variant, qualify the path
+
+mir_build_irrefutable_let_patterns_generic_let = irrefutable `let` {$count ->
+        [one] pattern
+        *[other] patterns
+    }
+    .note = {$count ->
+        [one] this pattern
+        *[other] these patterns
+    } will always match, so the `let` is useless
+    .help = consider removing `let`
+
+mir_build_irrefutable_let_patterns_if_let = irrefutable `if let` {$count ->
+        [one] pattern
+        *[other] patterns
+    }
+    .note = {$count ->
+        [one] this pattern
+        *[other] these patterns
+    } will always match, so the `if let` is useless
+    .help = consider replacing the `if let` with a `let`
+
+mir_build_irrefutable_let_patterns_if_let_guard = irrefutable `if let` guard {$count ->
+        [one] pattern
+        *[other] patterns
+    }
+    .note = {$count ->
+        [one] this pattern
+        *[other] these patterns
+    } will always match, so the guard is useless
+    .help = consider removing the guard and adding a `let` inside the match arm
+
+mir_build_irrefutable_let_patterns_let_else = irrefutable `let...else` {$count ->
+        [one] pattern
+        *[other] patterns
+    }
+    .note = {$count ->
+        [one] this pattern
+        *[other] these patterns
+    } will always match, so the `else` clause is useless
+    .help = consider removing the `else` clause
+
+mir_build_irrefutable_let_patterns_while_let = irrefutable `while let` {$count ->
+        [one] pattern
+        *[other] patterns
+    }
+    .note = {$count ->
+        [one] this pattern
+        *[other] these patterns
+    } will always match, so the loop will never exit
+    .help = consider instead using a `loop {"{"} ... {"}"}` with a `let` inside it
+
+mir_build_borrow_of_moved_value = borrow of moved value
+    .label = value moved into `{$name}` here
+    .occurs_because_label = move occurs because `{$name}` has type `{$ty}` which does not implement the `Copy` trait
+    .value_borrowed_label = value borrowed here after move
+    .suggestion = borrow this binding in the pattern to avoid moving the value
+
+mir_build_multiple_mut_borrows = cannot borrow value as mutable more than once at a time
+    .label = first mutable borrow, by `{$name}`, occurs here
+    .mutable_borrow = another mutable borrow, by `{$name_mut}`, occurs here
+    .immutable_borrow = also borrowed as immutable, by `{$name_immut}`, here
+    .moved = also moved into `{$name_moved}` here
index 48ddb54b79e795eb3c67f96b69bb5dda24e32f01..243d10bfa062150bf9bda530541b8f235d35ceae 100644 (file)
@@ -21,3 +21,6 @@ monomorphize_large_assignments =
     moving {$size} bytes
     .label = value moved from here
     .note = The current maximum size is {$limit}, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
+
+monomorphize_couldnt_dump_mono_stats =
+    unexpected error occurred while dumping monomorphization stats: {$error}
index 983eb926213ea587946629576a3c1b78fbf202e5..ab9e8b6baae6ad4a3e30bbd92ff4bafe18e66e4c 100644 (file)
@@ -41,6 +41,8 @@ session_unsupported_dwarf_version = requested DWARF version {$dwarf_version} is
 
 session_target_stack_protector_not_supported = `-Z stack-protector={$stack_protector}` is not supported for target {$target_triple} and will be ignored
 
+session_branch_protection_requires_aarch64 = `-Zbranch-protection` is only supported on aarch64
+
 session_split_debuginfo_unstable_platform = `-Csplit-debuginfo={$debuginfo}` is unstable on this platform
 
 session_file_is_not_writeable = output file {$file} is not writeable -- check its permissions
index 418ba3c74d7761cb574d8ad0840fd0dd09c93249..25d0e736e599f5ee4d66e501bb62bff8617a2102 100644 (file)
@@ -57,6 +57,7 @@
     lint => "../locales/en-US/lint.ftl",
     metadata => "../locales/en-US/metadata.ftl",
     middle => "../locales/en-US/middle.ftl",
+    mir_build => "../locales/en-US/mir_build.ftl",
     mir_dataflow => "../locales/en-US/mir_dataflow.ftl",
     monomorphize => "../locales/en-US/monomorphize.ftl",
     parse => "../locales/en-US/parse.ftl",
index 8994a2f78919f046bdad82d253460101ebb2cdbf..0b8847f827df1aa6ad9b8a056ccadba7d03ed9aa 100644 (file)
@@ -468,7 +468,7 @@ fn check_nested_occurrences(
                 // We check that the meta-variable is correctly used.
                 check_occurrences(sess, node_id, tt, macros, binders, ops, valid);
             }
-            (NestedMacroState::MacroName, &TokenTree::Delimited(_, ref del))
+            (NestedMacroState::MacroName, TokenTree::Delimited(_, del))
                 if del.delim == Delimiter::Parenthesis =>
             {
                 state = NestedMacroState::MacroNameParen;
@@ -483,7 +483,7 @@ fn check_nested_occurrences(
                     valid,
                 );
             }
-            (NestedMacroState::MacroNameParen, &TokenTree::Delimited(_, ref del))
+            (NestedMacroState::MacroNameParen, TokenTree::Delimited(_, del))
                 if del.delim == Delimiter::Brace =>
             {
                 state = NestedMacroState::Empty;
index 2dbb90e2190f0db42004859a03b5455d9995f19a..320c533a66e5d0bfc1b47367765394d928277d10 100644 (file)
@@ -792,7 +792,7 @@ fn first(&self, tts: &'tt [mbe::TokenTree]) -> TokenSet<'tt> {
                 TokenTree::Sequence(sp, ref seq_rep) => {
                     let subfirst_owned;
                     let subfirst = match self.first.get(&sp.entire()) {
-                        Some(&Some(ref subfirst)) => subfirst,
+                        Some(Some(subfirst)) => subfirst,
                         Some(&None) => {
                             subfirst_owned = self.first(&seq_rep.tts);
                             &subfirst_owned
index 7678ce323dfbc04fb0f254e47e214ca9ed833e68..e5348039edd62c396847e0f581e14846566ce648 100644 (file)
@@ -126,6 +126,8 @@ macro_rules! declare_features {
     (accepted, copy_closures, "1.26.0", Some(44490), None),
     /// Allows `crate` in paths.
     (accepted, crate_in_paths, "1.30.0", Some(45477), None),
+    /// Allows rustc to inject a default alloc_error_handler
+    (accepted, default_alloc_error_handler, "CURRENT_RUSTC_VERSION", Some(66741), None),
     /// Allows using assigning a default type to type parameters in algebraic data type definitions.
     (accepted, default_type_params, "1.0.0", None, None),
     /// Allows `#[deprecated]` attribute.
index 69c5297bf6b82564395b902052c9ce01ec38e3fa..a616dd70f8e6ddb2e216ce73a9e97dde707f75a4 100644 (file)
@@ -368,8 +368,6 @@ pub fn set(&self, features: &mut Features, span: Span) {
     (active, debugger_visualizer, "1.62.0", Some(95939), None),
     /// Allows declarative macros 2.0 (`macro`).
     (active, decl_macro, "1.17.0", Some(39412), None),
-    /// Allows rustc to inject a default alloc_error_handler
-    (active, default_alloc_error_handler, "1.48.0", Some(66741), None),
     /// Allows default type parameters to influence type inference.
     (active, default_type_parameter_fallback, "1.3.0", Some(27336), None),
     /// Allows using `#[deprecated_safe]` to deprecate the safeness of a function or trait
index 060f40919f5c8d16fd4490d5aab593aa5b4e8452..03bcaa6946825baac7073958262ddd75f7bd3bf2 100644 (file)
@@ -138,7 +138,7 @@ fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
     /// an "item-like" to something else can be implemented by a `Vec` instead of a
     /// tree or hash map.
     #[derive(HashStable_Generic)]
-    pub struct ItemLocalId { .. }
+    pub struct ItemLocalId {}
 }
 
 impl ItemLocalId {
index b51257df713ea37a273bc14fc579d3ac38eb7e9f..038509031b180a3cd42417a23846ff36c00ea7c0 100644 (file)
@@ -286,9 +286,10 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
 
     // FIXME(swatinem): the following lang items are used for async lowering and
     // should become obsolete eventually.
+    ResumeTy,                sym::ResumeTy,            resume_ty,                  Target::Struct,         GenericRequirement::None;
     IdentityFuture,          sym::identity_future,     identity_future_fn,         Target::Fn,             GenericRequirement::None;
+    GetContext,              sym::get_context,         get_context_fn,             Target::Fn,             GenericRequirement::None;
 
-    Context,                 sym::Context,             context,                    Target::Struct,         GenericRequirement::None;
     FuturePoll,              sym::poll,                future_poll_fn,             Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
 
     FromFrom,                sym::from,                from_fn,                    Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
index 71f26eb60c9628e880f5f5b71ca4274e4fed5598..c29a3afd7fba876896d006e2b0fb45407d1a3f8c 100644 (file)
 use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin};
 use rustc_middle::middle::stability::AllowUnstable;
 use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef};
-use rustc_middle::ty::DynKind;
 use rustc_middle::ty::GenericParamDefKind;
-use rustc_middle::ty::{
-    self, Const, DefIdTree, EarlyBinder, IsSuggestable, Ty, TyCtxt, TypeVisitable,
-};
+use rustc_middle::ty::{self, Const, DefIdTree, IsSuggestable, Ty, TyCtxt, TypeVisitable};
+use rustc_middle::ty::{DynKind, EarlyBinder};
 use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECTS};
 use rustc_span::edition::Edition;
 use rustc_span::lev_distance::find_best_match_for_name;
@@ -490,7 +488,8 @@ fn inferred_kind(
                             self.astconv
                                 .normalize_ty(
                                     self.span,
-                                    EarlyBinder(tcx.at(self.span).type_of(param.def_id))
+                                    tcx.at(self.span)
+                                        .bound_type_of(param.def_id)
                                         .subst(tcx, substs),
                                 )
                                 .into()
@@ -1255,10 +1254,7 @@ fn ast_path_to_ty(
         item_segment: &hir::PathSegment<'_>,
     ) -> Ty<'tcx> {
         let substs = self.ast_path_substs_for_ty(span, did, item_segment);
-        self.normalize_ty(
-            span,
-            EarlyBinder(self.tcx().at(span).type_of(did)).subst(self.tcx(), substs),
-        )
+        self.normalize_ty(span, self.tcx().at(span).bound_type_of(did).subst(self.tcx(), substs))
     }
 
     fn conv_object_ty_poly_trait_ref(
@@ -2240,7 +2236,7 @@ pub fn prohibit_generics<'a>(
                     ),
                     "s",
                 ),
-                [only] => (format!("{only}"), ""),
+                [only] => (only.to_string(), ""),
                 [] => unreachable!(),
             };
             let last_span = *arg_spans.last().unwrap();
index aa01feb3a1ea4d686e5b84401d4100913088ae76..eee0ba2e5ed2740961b4eeabec9b747a96752e41 100644 (file)
@@ -99,18 +99,17 @@ fn allowed_union_field<'tcx>(
             ty: Ty<'tcx>,
             tcx: TyCtxt<'tcx>,
             param_env: ty::ParamEnv<'tcx>,
-            span: Span,
         ) -> bool {
             // We don't just accept all !needs_drop fields, due to semver concerns.
             match ty.kind() {
                 ty::Ref(..) => true, // references never drop (even mutable refs, which are non-Copy and hence fail the later check)
                 ty::Tuple(tys) => {
                     // allow tuples of allowed types
-                    tys.iter().all(|ty| allowed_union_field(ty, tcx, param_env, span))
+                    tys.iter().all(|ty| allowed_union_field(ty, tcx, param_env))
                 }
                 ty::Array(elem, _len) => {
                     // Like `Copy`, we do *not* special-case length 0.
-                    allowed_union_field(*elem, tcx, param_env, span)
+                    allowed_union_field(*elem, tcx, param_env)
                 }
                 _ => {
                     // Fallback case: allow `ManuallyDrop` and things that are `Copy`.
@@ -124,7 +123,7 @@ fn allowed_union_field<'tcx>(
         for field in &def.non_enum_variant().fields {
             let field_ty = field.ty(tcx, substs);
 
-            if !allowed_union_field(field_ty, tcx, param_env, span) {
+            if !allowed_union_field(field_ty, tcx, param_env) {
                 let (field_span, ty_span) = match tcx.hir().get_if_local(field.did) {
                     // We are currently checking the type this field came from, so it must be local.
                     Some(Node::Field(field)) => (field.span, field.ty.span),
index 6b9ce9a4599e2ce45ddd8e8479ec41f32d73d6b7..cddd307c13dbbe72d07c7259a8f41770ac83bef2 100644 (file)
@@ -71,8 +71,14 @@ pub(crate) fn compare_impl_method<'tcx>(
         return;
     }
 
-    if let Err(_) = compare_predicate_entailment(tcx, impl_m, impl_m_span, trait_m, impl_trait_ref)
-    {
+    if let Err(_) = compare_predicate_entailment(
+        tcx,
+        impl_m,
+        impl_m_span,
+        trait_m,
+        impl_trait_ref,
+        CheckImpliedWfMode::Check,
+    ) {
         return;
     }
 }
@@ -150,6 +156,7 @@ fn compare_predicate_entailment<'tcx>(
     impl_m_span: Span,
     trait_m: &ty::AssocItem,
     impl_trait_ref: ty::TraitRef<'tcx>,
+    check_implied_wf: CheckImpliedWfMode,
 ) -> Result<(), ErrorGuaranteed> {
     let trait_to_impl_substs = impl_trait_ref.substs;
 
@@ -255,15 +262,15 @@ fn compare_predicate_entailment<'tcx>(
 
     let mut wf_tys = FxIndexSet::default();
 
-    let impl_sig = infcx.replace_bound_vars_with_fresh_vars(
+    let unnormalized_impl_sig = infcx.replace_bound_vars_with_fresh_vars(
         impl_m_span,
         infer::HigherRankedType,
         tcx.fn_sig(impl_m.def_id),
     );
+    let unnormalized_impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(unnormalized_impl_sig));
 
     let norm_cause = ObligationCause::misc(impl_m_span, impl_m_hir_id);
-    let impl_sig = ocx.normalize(&norm_cause, param_env, impl_sig);
-    let impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(impl_sig));
+    let impl_fty = ocx.normalize(&norm_cause, param_env, unnormalized_impl_fty);
     debug!("compare_impl_method: impl_fty={:?}", impl_fty);
 
     let trait_sig = tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs);
@@ -304,29 +311,108 @@ fn compare_predicate_entailment<'tcx>(
         return Err(emitted);
     }
 
+    if check_implied_wf == CheckImpliedWfMode::Check {
+        // We need to check that the impl's args are well-formed given
+        // the hybrid param-env (impl + trait method where-clauses).
+        ocx.register_obligation(traits::Obligation::new(
+            infcx.tcx,
+            ObligationCause::dummy(),
+            param_env,
+            ty::Binder::dummy(ty::PredicateKind::WellFormed(unnormalized_impl_fty.into())),
+        ));
+    }
+    let emit_implied_wf_lint = || {
+        infcx.tcx.struct_span_lint_hir(
+            rustc_session::lint::builtin::IMPLIED_BOUNDS_ENTAILMENT,
+            impl_m_hir_id,
+            infcx.tcx.def_span(impl_m.def_id),
+            "impl method assumes more implied bounds than the corresponding trait method",
+            |lint| lint,
+        );
+    };
+
     // Check that all obligations are satisfied by the implementation's
     // version.
     let errors = ocx.select_all_or_error();
     if !errors.is_empty() {
-        let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
-        return Err(reported);
+        match check_implied_wf {
+            CheckImpliedWfMode::Check => {
+                return compare_predicate_entailment(
+                    tcx,
+                    impl_m,
+                    impl_m_span,
+                    trait_m,
+                    impl_trait_ref,
+                    CheckImpliedWfMode::Skip,
+                )
+                .map(|()| {
+                    // If the skip-mode was successful, emit a lint.
+                    emit_implied_wf_lint();
+                });
+            }
+            CheckImpliedWfMode::Skip => {
+                let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
+                return Err(reported);
+            }
+        }
     }
 
     // Finally, resolve all regions. This catches wily misuses of
     // lifetime parameters.
-    let outlives_environment = OutlivesEnvironment::with_bounds(
+    let outlives_env = OutlivesEnvironment::with_bounds(
         param_env,
         Some(infcx),
-        infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys),
+        infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys.clone()),
     );
-    infcx.check_region_obligations_and_report_errors(
-        impl_m.def_id.expect_local(),
-        &outlives_environment,
+    infcx.process_registered_region_obligations(
+        outlives_env.region_bound_pairs(),
+        outlives_env.param_env,
     );
+    let errors = infcx.resolve_regions(&outlives_env);
+    if !errors.is_empty() {
+        // FIXME(compiler-errors): This can be simplified when IMPLIED_BOUNDS_ENTAILMENT
+        // becomes a hard error (i.e. ideally we'd just call `resolve_regions_and_report_errors`
+        match check_implied_wf {
+            CheckImpliedWfMode::Check => {
+                return compare_predicate_entailment(
+                    tcx,
+                    impl_m,
+                    impl_m_span,
+                    trait_m,
+                    impl_trait_ref,
+                    CheckImpliedWfMode::Skip,
+                )
+                .map(|()| {
+                    // If the skip-mode was successful, emit a lint.
+                    emit_implied_wf_lint();
+                });
+            }
+            CheckImpliedWfMode::Skip => {
+                if infcx.tainted_by_errors().is_none() {
+                    infcx.err_ctxt().report_region_errors(impl_m.def_id.expect_local(), &errors);
+                }
+                return Err(tcx
+                    .sess
+                    .delay_span_bug(rustc_span::DUMMY_SP, "error should have been emitted"));
+            }
+        }
+    }
 
     Ok(())
 }
 
+#[derive(Debug, PartialEq, Eq)]
+enum CheckImpliedWfMode {
+    /// Checks implied well-formedness of the impl method. If it fails, we will
+    /// re-check with `Skip`, and emit a lint if it succeeds.
+    Check,
+    /// Skips checking implied well-formedness of the impl method, but will emit
+    /// a lint if the `compare_predicate_entailment` succeeded. This means that
+    /// the reason that we had failed earlier during `Check` was due to the impl
+    /// having stronger requirements than the trait.
+    Skip,
+}
+
 fn compare_asyncness<'tcx>(
     tcx: TyCtxt<'tcx>,
     impl_m: &ty::AssocItem,
@@ -405,6 +491,7 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
             tcx.fn_sig(impl_m.def_id),
         ),
     );
+    impl_sig.error_reported()?;
     let impl_return_ty = impl_sig.output();
 
     // Normalize the trait signature with liberated bound vars, passing it through
@@ -419,6 +506,7 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
         )
         .fold_with(&mut collector);
     let trait_sig = ocx.normalize(&norm_cause, param_env, unnormalized_trait_sig);
+    trait_sig.error_reported()?;
     let trait_return_ty = trait_sig.output();
 
     let wf_tys = FxIndexSet::from_iter(
index 972769eb1970735f7736ddf7168f94ac51072fa8..a9331af4eab32f622d7ccec1340604df7faa32b9 100644 (file)
@@ -198,10 +198,10 @@ fn check_item(&mut self, id: hir::ItemId) {
             // entire graph when there are many connected regions.
 
             rustc_index::newtype_index! {
-                pub struct RegionId {
-                    ENCODABLE = custom
-                }
+                #[custom_encodable]
+                pub struct RegionId {}
             }
+
             struct ConnectedRegion {
                 idents: SmallVec<[Symbol; 8]>,
                 impl_blocks: FxHashSet<usize>,
index 1eeaaf55e63af0f43a8e84884140294fe0e3f846..0c4649cea14edda97552e175a99e877201d87690 100644 (file)
@@ -489,7 +489,7 @@ fn projected_ty_from_poly_trait_ref(
                         format!(
                             "{}::",
                             // Erase named lt, we want `<A as B<'_>::C`, not `<A as B<'a>::C`.
-                            self.tcx.anonymize_late_bound_regions(poly_trait_ref).skip_binder(),
+                            self.tcx.anonymize_bound_vars(poly_trait_ref).skip_binder(),
                         ),
                         Applicability::MaybeIncorrect,
                     );
index 7a5191b77f1d45759a88ce6f7c6740f1b257df6d..4ec71a78a003146d8a8da6c45b9eddcfea4608d3 100644 (file)
@@ -4,7 +4,7 @@
 
 use crate::type_error_struct;
 use rustc_ast::util::parser::PREC_POSTFIX;
-use rustc_errors::{struct_span_err, Applicability, Diagnostic, StashKey};
+use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed, StashKey};
 use rustc_hir as hir;
 use rustc_hir::def::{self, CtorKind, Namespace, Res};
 use rustc_hir::def_id::DefId;
@@ -424,21 +424,9 @@ fn confirm_builtin_call(
                     }
                 }
 
-                self.report_invalid_callee(call_expr, callee_expr, callee_ty, arg_exprs);
-
-                // This is the "default" function signature, used in case of error.
-                // In that case, we check each argument against "error" in order to
-                // set up all the node type bindings.
-                (
-                    ty::Binder::dummy(self.tcx.mk_fn_sig(
-                        self.err_args(arg_exprs.len()).into_iter(),
-                        self.tcx.ty_error(),
-                        false,
-                        hir::Unsafety::Normal,
-                        abi::Abi::Rust,
-                    )),
-                    None,
-                )
+                let err = self.report_invalid_callee(call_expr, callee_expr, callee_ty, arg_exprs);
+
+                return self.tcx.ty_error_with_guaranteed(err);
             }
         };
 
@@ -591,7 +579,7 @@ fn report_invalid_callee(
         callee_expr: &'tcx hir::Expr<'tcx>,
         callee_ty: Ty<'tcx>,
         arg_exprs: &'tcx [hir::Expr<'tcx>],
-    ) {
+    ) -> ErrorGuaranteed {
         let mut unit_variant = None;
         if let hir::ExprKind::Path(qpath) = &callee_expr.kind
             && let Res::Def(def::DefKind::Ctor(kind, CtorKind::Const), _)
@@ -720,7 +708,7 @@ fn report_invalid_callee(
                 err.span_label(span, label);
             }
         }
-        err.emit();
+        err.emit()
     }
 
     fn confirm_deferred_closure_call(
index b050ad20afbdbcca92547e224feda97a9d8af8b8..042a50f2fd42eb89906167fde85ed9b0e4eb1622 100644 (file)
@@ -847,13 +847,15 @@ pub fn do_check(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<CastKind, CastError> {
 
             (Int(_) | Float, Int(_) | Float) => Ok(CastKind::NumericCast),
 
-            (_, DynStar) | (DynStar, _) => {
+            (_, DynStar) => {
                 if fcx.tcx.features().dyn_star {
                     bug!("should be handled by `try_coerce`")
                 } else {
                     Err(CastError::IllegalCast)
                 }
             }
+
+            (DynStar, _) => Err(CastError::IllegalCast),
         }
     }
 
index 72d8a936ab39db2adcc5b8f4970fcdc705b638ba..5bd02dff73bfc1f033318eff0d0568c9e382d9cb 100644 (file)
@@ -426,7 +426,7 @@ fn sig_of_closure_with_expectation(
         // `deduce_expectations_from_expected_type` introduces
         // late-bound lifetimes defined elsewhere, which we now
         // anonymize away, so as not to confuse the user.
-        let bound_sig = self.tcx.anonymize_late_bound_regions(bound_sig);
+        let bound_sig = self.tcx.anonymize_bound_vars(bound_sig);
 
         let closure_sigs = self.closure_sigs(expr_def_id, body, bound_sig);
 
index 36cf4791492dd1c8c8b36d1125289dc008cb3fed..8cdd12e4e347abfae0b9b5fb6347d98459187d28 100644 (file)
@@ -1548,7 +1548,7 @@ pub(crate) fn coerce_inner<'a>(
                             cause,
                             expected,
                             found,
-                            coercion_error.clone(),
+                            coercion_error,
                             fcx,
                             parent_id,
                             expression,
@@ -1567,7 +1567,7 @@ pub(crate) fn coerce_inner<'a>(
                             cause,
                             expected,
                             found,
-                            coercion_error.clone(),
+                            coercion_error,
                             fcx,
                             id,
                             expression,
@@ -1583,7 +1583,7 @@ pub(crate) fn coerce_inner<'a>(
                             cause,
                             expected,
                             found,
-                            coercion_error.clone(),
+                            coercion_error,
                         );
                     }
                 }
index 6763e06c0cfeed38a2a5c83f7fecb58c47beb825..479aaf2e1a7b5cc778f3623f86b90e332bb3ecfe 100644 (file)
@@ -163,7 +163,7 @@ pub fn demand_coerce_diag(
         let expr = expr.peel_drop_temps();
         let cause = self.misc(expr.span);
         let expr_ty = self.resolve_vars_with_obligations(checked_ty);
-        let mut err = self.err_ctxt().report_mismatched_types(&cause, expected, expr_ty, e.clone());
+        let mut err = self.err_ctxt().report_mismatched_types(&cause, expected, expr_ty, e);
 
         let is_insufficiently_polymorphic =
             matches!(e, TypeError::RegionsInsufficientlyPolymorphic(..));
@@ -406,7 +406,7 @@ fn suggest_compatible_variants(
                     }
 
                     let note_about_variant_field_privacy = (field_is_local && !field_is_accessible)
-                        .then(|| format!(" (its field is private, but it's local to this crate and its privacy can be changed)"));
+                        .then(|| " (its field is private, but it's local to this crate and its privacy can be changed)".to_string());
 
                     let sole_field_ty = sole_field.ty(self.tcx, substs);
                     if self.can_coerce(expr_ty, sole_field_ty) {
@@ -1275,7 +1275,7 @@ pub fn check_for_cast(
             };
 
         match (&expected_ty.kind(), &checked_ty.kind()) {
-            (&ty::Int(ref exp), &ty::Int(ref found)) => {
+            (ty::Int(exp), ty::Int(found)) => {
                 let (f2e_is_fallible, e2f_is_fallible) = match (exp.bit_width(), found.bit_width())
                 {
                     (Some(exp), Some(found)) if exp < found => (true, false),
@@ -1288,7 +1288,7 @@ pub fn check_for_cast(
                 suggest_to_change_suffix_or_into(err, f2e_is_fallible, e2f_is_fallible);
                 true
             }
-            (&ty::Uint(ref exp), &ty::Uint(ref found)) => {
+            (ty::Uint(exp), ty::Uint(found)) => {
                 let (f2e_is_fallible, e2f_is_fallible) = match (exp.bit_width(), found.bit_width())
                 {
                     (Some(exp), Some(found)) if exp < found => (true, false),
@@ -1321,7 +1321,7 @@ pub fn check_for_cast(
                 suggest_to_change_suffix_or_into(err, f2e_is_fallible, e2f_is_fallible);
                 true
             }
-            (&ty::Float(ref exp), &ty::Float(ref found)) => {
+            (ty::Float(exp), ty::Float(found)) => {
                 if found.bit_width() < exp.bit_width() {
                     suggest_to_change_suffix_or_into(err, false, true);
                 } else if literal_is_ty_suffixed(expr) {
@@ -1357,7 +1357,7 @@ pub fn check_for_cast(
                 }
                 true
             }
-            (&ty::Float(ref exp), &ty::Uint(ref found)) => {
+            (ty::Float(exp), ty::Uint(found)) => {
                 // if `found` is `None` (meaning found is `usize`), don't suggest `.into()`
                 if exp.bit_width() > found.bit_width().unwrap_or(256) {
                     err.multipart_suggestion_verbose(
@@ -1386,7 +1386,7 @@ pub fn check_for_cast(
                 }
                 true
             }
-            (&ty::Float(ref exp), &ty::Int(ref found)) => {
+            (ty::Float(exp), ty::Int(found)) => {
                 // if `found` is `None` (meaning found is `isize`), don't suggest `.into()`
                 if exp.bit_width() > found.bit_width().unwrap_or(256) {
                     err.multipart_suggestion_verbose(
index 866090260b2723dad6ef078f500805ab69b7d46c..edbbb7272ac77d899b02d2aa3116a2decf497c04 100644 (file)
@@ -1874,7 +1874,7 @@ fn suggest_fru_from_range(
         // I don't use 'is_range_literal' because only double-sided, half-open ranges count.
         if let ExprKind::Struct(
                 QPath::LangItem(LangItem::Range, ..),
-                &[ref range_start, ref range_end],
+                [range_start, range_end],
                 _,
             ) = last_expr_field.expr.kind
             && let variant_field =
index 1a4e6bf763821b05ee33737dc392ef35d145eb8a..150e917c73988bef7126b16ede746d8a60b20eec 100644 (file)
@@ -22,7 +22,7 @@
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::visit::TypeVisitable;
 use rustc_middle::ty::{
-    self, AdtKind, CanonicalUserType, DefIdTree, EarlyBinder, GenericParamDefKind, Ty, UserType,
+    self, AdtKind, CanonicalUserType, DefIdTree, GenericParamDefKind, Ty, UserType,
 };
 use rustc_middle::ty::{GenericArgKind, InternalSubsts, SubstsRef, UserSelfTy, UserSubsts};
 use rustc_session::lint;
@@ -333,22 +333,7 @@ pub fn apply_adjustments(&self, expr: &hir::Expr<'_>, adj: Vec<Adjustment<'tcx>>
         }
     }
 
-    /// Basically whenever we are converting from a type scheme into
-    /// the fn body space, we always want to normalize associated
-    /// types as well. This function combines the two.
-    fn instantiate_type_scheme<T>(&self, span: Span, substs: SubstsRef<'tcx>, value: T) -> T
-    where
-        T: TypeFoldable<'tcx>,
-    {
-        debug!("instantiate_type_scheme(value={:?}, substs={:?})", value, substs);
-        let value = EarlyBinder(value).subst(self.tcx, substs);
-        let result = self.normalize(span, value);
-        debug!("instantiate_type_scheme = {:?}", result);
-        result
-    }
-
-    /// As `instantiate_type_scheme`, but for the bounds found in a
-    /// generic type scheme.
+    /// Instantiates and normalizes the bounds for a given item
     pub(in super::super) fn instantiate_bounds(
         &self,
         span: Span,
@@ -1160,10 +1145,6 @@ pub fn instantiate_value_path(
         };
         let def_id = res.def_id();
 
-        // The things we are substituting into the type should not contain
-        // escaping late-bound regions, and nor should the base type scheme.
-        let ty = tcx.type_of(def_id);
-
         let arg_count = GenericArgCountResult {
             explicit_late_bound,
             correct: if infer_args_for_err.is_empty() {
@@ -1286,8 +1267,6 @@ fn inferred_kind(
                 },
             )
         });
-        assert!(!substs.has_escaping_bound_vars());
-        assert!(!ty.has_escaping_bound_vars());
 
         // First, store the "user substs" for later.
         self.write_user_type_annotation_from_substs(hir_id, def_id, substs, user_self_ty);
@@ -1296,7 +1275,10 @@ fn inferred_kind(
 
         // Substitute the values for the type parameters into the type of
         // the referenced item.
-        let ty_substituted = self.instantiate_type_scheme(span, &substs, ty);
+        let ty = tcx.bound_type_of(def_id);
+        assert!(!substs.has_escaping_bound_vars());
+        assert!(!ty.0.has_escaping_bound_vars());
+        let ty_substituted = self.normalize(span, ty.subst(tcx, substs));
 
         if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty {
             // In the case of `Foo<T>::method` and `<Foo<T>>::method`, if `method`
@@ -1304,9 +1286,7 @@ fn inferred_kind(
             // type parameters, which we can infer by unifying the provided `Self`
             // with the substituted impl type.
             // This also occurs for an enum variant on a type alias.
-            let ty = tcx.type_of(impl_def_id);
-
-            let impl_ty = self.instantiate_type_scheme(span, &substs, ty);
+            let impl_ty = self.normalize(span, tcx.bound_type_of(impl_def_id).subst(tcx, substs));
             match self.at(&self.misc(span), self.param_env).eq(impl_ty, self_ty) {
                 Ok(ok) => self.register_infer_ok_obligations(ok),
                 Err(_) => {
index fc83994caf53966aff1ba74745ca44856349f233..6f26afcaf1680abfd0bc4c4a4e80dd4a86be7023 100644 (file)
@@ -4,15 +4,13 @@
 use rustc_middle::ty::error::TypeError;
 
 rustc_index::newtype_index! {
-    pub(crate) struct ExpectedIdx {
-        DEBUG_FORMAT = "ExpectedIdx({})",
-    }
+    #[debug_format = "ExpectedIdx({})"]
+    pub(crate) struct ExpectedIdx {}
 }
 
 rustc_index::newtype_index! {
-    pub(crate) struct ProvidedIdx {
-        DEBUG_FORMAT = "ProvidedIdx({})",
-    }
+    #[debug_format = "ProvidedIdx({})"]
+    pub(crate) struct ProvidedIdx {}
 }
 
 impl ExpectedIdx {
index 8e520e563ff630ecdeb62b0e4a1b046feb7dbe14..d1e0964112bc5ae64bf6eeef1be27f2543e13fb1 100644 (file)
@@ -28,7 +28,7 @@
 use rustc_middle::ty::visit::TypeVisitable;
 use rustc_middle::ty::{self, DefIdTree, IsSuggestable, Ty, TypeSuperVisitable, TypeVisitor};
 use rustc_session::Session;
-use rustc_span::symbol::Ident;
+use rustc_span::symbol::{kw, Ident};
 use rustc_span::{self, sym, Span};
 use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext};
 
@@ -1013,7 +1013,7 @@ enum SuggestionText {
                             } else {
                                 args_span
                             };
-                            labels.push((span, format!("multiple arguments are missing")));
+                            labels.push((span, "multiple arguments are missing".to_string()));
                             suggestion_text = match suggestion_text {
                                 SuggestionText::None | SuggestionText::Provide(_) => {
                                     SuggestionText::Provide(true)
@@ -1141,6 +1141,13 @@ enum SuggestionText {
                         "()".to_string()
                     } else if expected_ty.is_suggestable(tcx, false) {
                         format!("/* {} */", expected_ty)
+                    } else if let Some(fn_def_id) = fn_def_id
+                        && self.tcx.def_kind(fn_def_id).is_fn_like()
+                        && let self_implicit = matches!(call_expr.kind, hir::ExprKind::MethodCall(..)) as usize
+                        && let Some(arg) = self.tcx.fn_arg_names(fn_def_id).get(expected_idx.as_usize() + self_implicit)
+                        && arg.name != kw::SelfLower
+                    {
+                        format!("/* {} */", arg.name)
                     } else {
                         "/* value */".to_string()
                     }
index 719f44f9f665ab063aec4f2d5f066acf30ecd2d6..c9d179de39f391adecb9a14de7a98021d8e0347b 100644 (file)
@@ -13,7 +13,9 @@
 use rustc_infer::infer;
 use rustc_infer::traits::{self, StatementAsExpression};
 use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::{self, Binder, DefIdTree, IsSuggestable, Ty};
+use rustc_middle::ty::{
+    self, suggest_constraining_type_params, Binder, DefIdTree, IsSuggestable, ToPredicate, Ty,
+};
 use rustc_session::errors::ExprParenthesesNeeded;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
@@ -317,11 +319,7 @@ pub fn suggest_two_fn_call(
                 }
             }
 
-            err.multipart_suggestion_verbose(
-                format!("use parentheses to call these"),
-                sugg,
-                applicability,
-            );
+            err.multipart_suggestion_verbose("use parentheses to call these", sugg, applicability);
 
             true
         } else {
@@ -752,7 +750,7 @@ pub(in super::super) fn suggest_missing_return_type(
                     return true
                 }
             }
-            &hir::FnRetTy::Return(ref ty) => {
+            hir::FnRetTy::Return(ty) => {
                 // Only point to return type if the expected type is the return type, as if they
                 // are not, the expectation must have been caused by something else.
                 debug!("suggest_missing_return_type: return type {:?} node {:?}", ty, ty.kind);
@@ -1126,9 +1124,9 @@ pub(crate) fn suggest_option_to_bool(
         }
 
         let hir = self.tcx.hir();
-        let cond_parent = hir.parent_iter(expr.hir_id).skip_while(|(_, node)| {
-            matches!(node, hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Binary(op, _, _), .. }) if op.node == hir::BinOpKind::And)
-        }).next();
+        let cond_parent = hir.parent_iter(expr.hir_id).find(|(_, node)| {
+            !matches!(node, hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Binary(op, _, _), .. }) if op.node == hir::BinOpKind::And)
+        });
         // Don't suggest:
         //     `let Some(_) = a.is_some() && b`
         //                     ++++++++++
@@ -1276,15 +1274,13 @@ pub(crate) fn note_type_is_not_clone(
             && !results.expr_adjustments(callee_expr).iter().any(|adj| matches!(adj.kind, ty::adjustment::Adjust::Deref(..)))
             // Check that we're in fact trying to clone into the expected type
             && self.can_coerce(*pointee_ty, expected_ty)
+            && let trait_ref = ty::Binder::dummy(self.tcx.mk_trait_ref(clone_trait_did, [expected_ty]))
             // And the expected type doesn't implement `Clone`
             && !self.predicate_must_hold_considering_regions(&traits::Obligation::new(
                 self.tcx,
                 traits::ObligationCause::dummy(),
                 self.param_env,
-                ty::Binder::dummy(self.tcx.mk_trait_ref(
-                    clone_trait_did,
-                    [expected_ty],
-                )),
+                trait_ref,
             ))
         {
             diag.span_note(
@@ -1293,6 +1289,19 @@ pub(crate) fn note_type_is_not_clone(
                     "`{expected_ty}` does not implement `Clone`, so `{found_ty}` was cloned instead"
                 ),
             );
+            let owner = self.tcx.hir().enclosing_body_owner(expr.hir_id);
+            if let ty::Param(param) = expected_ty.kind()
+                && let Some(generics) = self.tcx.hir().get_generics(owner)
+            {
+                suggest_constraining_type_params(
+                    self.tcx,
+                    generics,
+                    diag,
+                    vec![(param.name.as_str(), "Clone", Some(clone_trait_did))].into_iter(),
+                );
+            } else {
+                self.suggest_derive(diag, &[(trait_ref.to_predicate(self.tcx), None, None)]);
+            }
         }
     }
 
index 2abcadcc9ce7de4f6335daf6c9febc0ca8d3a6c4..2f55ea939fc0b2bcff4edfe08ac44de843f2efe1 100644 (file)
@@ -96,15 +96,13 @@ fn for_each_consumable<'tcx>(hir: Map<'tcx>, place: TrackedValue, mut f: impl Fn
 }
 
 rustc_index::newtype_index! {
-    pub struct PostOrderId {
-        DEBUG_FORMAT = "id({})",
-    }
+    #[debug_format = "id({})"]
+    pub struct PostOrderId {}
 }
 
 rustc_index::newtype_index! {
-    pub struct TrackedValueIndex {
-        DEBUG_FORMAT = "hidx({})",
-    }
+    #[debug_format = "hidx({})"]
+    pub struct TrackedValueIndex {}
 }
 
 /// Identifies a value whose drop state we need to track.
index 3f3af53d199b12918512a1597a9f7b1eb34532a5..fddb8a458a7d5f0716a6ba25f7339849a1196eb4 100644 (file)
@@ -456,9 +456,9 @@ fn construct_obligation_for_trait(
         // Instantiate late-bound regions and substitute the trait
         // parameters into the method type to get the actual method type.
         //
-        // N.B., instantiate late-bound regions first so that
-        // `instantiate_type_scheme` can normalize associated types that
-        // may reference those regions.
+        // N.B., instantiate late-bound regions before normalizing the
+        // function signature so that normalization does not need to deal
+        // with bound regions.
         let fn_sig = tcx.bound_fn_sig(def_id);
         let fn_sig = fn_sig.subst(self.tcx, substs);
         let fn_sig = self.replace_bound_vars_with_fresh_vars(span, infer::FnCall, fn_sig);
index 5c0d5f32f0fd0c47e4d298af105e6a8dbd1ffa85..7c5a9a333feba56da059e18d4b90b1cf1563db56 100644 (file)
@@ -25,7 +25,7 @@
 use rustc_middle::traits::util::supertraits;
 use rustc_middle::ty::fast_reject::DeepRejectCtxt;
 use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
-use rustc_middle::ty::print::with_crate_prefix;
+use rustc_middle::ty::print::{with_crate_prefix, with_forced_trimmed_paths};
 use rustc_middle::ty::{self, DefIdTree, GenericArgKind, Ty, TyCtxt, TypeVisitable};
 use rustc_middle::ty::{IsSuggestable, ToPolyTraitRef};
 use rustc_span::symbol::{kw, sym, Ident};
@@ -270,7 +270,7 @@ pub fn report_method_error(
                 let tcx = self.tcx;
 
                 let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty);
-                let ty_str = self.ty_to_string(rcvr_ty);
+                let ty_str = with_forced_trimmed_paths!(self.ty_to_string(rcvr_ty));
                 let is_method = mode == Mode::MethodCall;
                 let item_kind = if is_method {
                     "method"
@@ -563,7 +563,10 @@ pub fn report_method_error(
                                 let term = pred.skip_binder().term;
 
                                 let obligation = format!("{} = {}", projection_ty, term);
-                                let quiet = format!("{} = {}", quiet_projection_ty, term);
+                                let quiet = with_forced_trimmed_paths!(format!(
+                                    "{} = {}",
+                                    quiet_projection_ty, term
+                                ));
 
                                 bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
                                 Some((obligation, projection_ty.self_ty()))
@@ -573,7 +576,7 @@ pub fn report_method_error(
                                 let self_ty = p.self_ty();
                                 let path = p.print_only_trait_path();
                                 let obligation = format!("{}: {}", self_ty, path);
-                                let quiet = format!("_: {}", path);
+                                let quiet = with_forced_trimmed_paths!(format!("_: {}", path));
                                 bound_span_label(self_ty, &obligation, &quiet);
                                 Some((obligation, self_ty))
                             }
@@ -686,6 +689,16 @@ pub fn report_method_error(
                                 let entry = spanned_predicates.entry(spans);
                                 entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
                             }
+                            Some(Node::Item(hir::Item {
+                                kind: hir::ItemKind::Trait(rustc_ast::ast::IsAuto::Yes, ..),
+                                span: item_span,
+                                ..
+                            })) => {
+                                tcx.sess.delay_span_bug(
+                                        *item_span,
+                                        "auto trait is invoked with no method error, but no error reported?",
+                                    );
+                            }
                             Some(_) => unreachable!(),
                             None => (),
                         }
@@ -796,7 +809,8 @@ trait bound{s}",
                                 (None, None)
                             };
                         let primary_message = primary_message.unwrap_or_else(|| format!(
-                            "the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, but its trait bounds were not satisfied"
+                            "the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, \
+                             but its trait bounds were not satisfied"
                         ));
                         err.set_primary_message(&primary_message);
                         if let Some(label) = label {
@@ -993,7 +1007,7 @@ trait bound{s}",
                         if def_kind == DefKind::AssocFn && lev_candidate.fn_has_self_parameter {
                             err.span_suggestion(
                                 span,
-                                &format!("there is a method with a similar name",),
+                                "there is a method with a similar name",
                                 lev_candidate.name,
                                 Applicability::MaybeIncorrect,
                             );
@@ -1848,7 +1862,7 @@ pub(crate) fn note_unmet_impls_on_type(
         self.suggest_derive(err, &preds);
     }
 
-    fn suggest_derive(
+    pub fn suggest_derive(
         &self,
         err: &mut Diagnostic,
         unsatisfied_predicates: &[(
index 6810353f9e778bc992e43c6ee94111cdcca39aca..d3e88b1b80ae29a30aec1856320059b54bdbf793 100644 (file)
@@ -2130,7 +2130,7 @@ fn error_expected_array_or_slice(&self, span: Span, expected_ty: Ty<'tcx>, ti: T
             && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
         {
             let ty = self.resolve_vars_if_possible(ti.expected);
-            let is_slice_or_array_or_vector = self.is_slice_or_array_or_vector(&mut err, snippet.clone(), ty);
+            let is_slice_or_array_or_vector = self.is_slice_or_array_or_vector(ty);
             match is_slice_or_array_or_vector.1.kind() {
                 ty::Adt(adt_def, _)
                     if self.tcx.is_diagnostic_item(sym::Option, adt_def.did())
@@ -2159,17 +2159,12 @@ fn error_expected_array_or_slice(&self, span: Span, expected_ty: Ty<'tcx>, ti: T
         err.emit();
     }
 
-    fn is_slice_or_array_or_vector(
-        &self,
-        err: &mut Diagnostic,
-        snippet: String,
-        ty: Ty<'tcx>,
-    ) -> (bool, Ty<'tcx>) {
+    fn is_slice_or_array_or_vector(&self, ty: Ty<'tcx>) -> (bool, Ty<'tcx>) {
         match ty.kind() {
             ty::Adt(adt_def, _) if self.tcx.is_diagnostic_item(sym::Vec, adt_def.did()) => {
                 (true, ty)
             }
-            ty::Ref(_, ty, _) => self.is_slice_or_array_or_vector(err, snippet, *ty),
+            ty::Ref(_, ty, _) => self.is_slice_or_array_or_vector(*ty),
             ty::Slice(..) | ty::Array(..) => (true, ty),
             _ => (false, ty),
         }
index 69e482ce854c063a2b300c7c7068531c9aca0ff1..b4bf9f4bcc767a3688f7a9b2965cf399c46d718e 100644 (file)
@@ -249,7 +249,7 @@ fn dump_graph(query: &DepGraphQuery) {
         // dump a .txt file with just the edges:
         let txt_path = format!("{}.txt", path);
         let mut file = BufWriter::new(File::create(&txt_path).unwrap());
-        for &(ref source, ref target) in &edges {
+        for (source, target) in &edges {
             write!(file, "{:?} -> {:?}\n", source, target).unwrap();
         }
     }
index 915d2e8bcb3ff74b1e031aa3aa13ba239f8fa105..cb0f0db220d97b6505b46030d497787eb6f53a81 100644 (file)
@@ -3,7 +3,10 @@
 // Allows the macro invocation below to work
 use crate as rustc_index;
 
-rustc_macros::newtype_index!(struct MyIdx { MAX = 0xFFFF_FFFA });
+rustc_macros::newtype_index! {
+    #[max = 0xFFFF_FFFA]
+    struct MyIdx {}
+}
 
 #[test]
 fn index_size_is_optimized() {
index 397fa43175f732b3d87e566678388b0fbcd342d8..269fc95420adef2dda18ea8e0ffd0051b7d393d6 100644 (file)
@@ -184,7 +184,7 @@ fn msg_span_from_early_bound_and_free_regions<'tcx>(
             let text = if br.has_name() {
                 format!("the lifetime `{}` as defined here", br.name)
             } else {
-                format!("the anonymous lifetime as defined here")
+                "the anonymous lifetime as defined here".to_string()
             };
             (text, sp)
         }
@@ -203,7 +203,7 @@ fn msg_span_from_early_bound_and_free_regions<'tcx>(
                             sp = param.span;
                         }
                         let text = if name == kw::UnderscoreLifetime {
-                            format!("the anonymous lifetime as defined here")
+                            "the anonymous lifetime as defined here".to_string()
                         } else {
                             format!("the lifetime `{}` as defined here", name)
                         };
index c42240f21724f77bf9a798b948b06e6368744809..9534bce54ef0e7217fff7b76ba8337eb886093dc 100644 (file)
@@ -44,7 +44,7 @@ pub(super) fn try_report_placeholder_relation(
                         );
                     }
                     (Some(sub_span), Some(sup_span), _, Some(sup_symbol)) => {
-                        err.span_note(sub_span, format!("the lifetime defined here..."));
+                        err.span_note(sub_span, "the lifetime defined here...");
                         err.span_note(
                             sup_span,
                             format!("...must outlive the lifetime `{sup_symbol}` defined here"),
@@ -55,17 +55,11 @@ pub(super) fn try_report_placeholder_relation(
                             sub_span,
                             format!("the lifetime `{sub_symbol}` defined here..."),
                         );
-                        err.span_note(
-                            sup_span,
-                            format!("...must outlive the lifetime defined here"),
-                        );
+                        err.span_note(sup_span, "...must outlive the lifetime defined here");
                     }
                     (Some(sub_span), Some(sup_span), _, _) => {
-                        err.span_note(sub_span, format!("the lifetime defined here..."));
-                        err.span_note(
-                            sup_span,
-                            format!("...must outlive the lifetime defined here"),
-                        );
+                        err.span_note(sub_span, "the lifetime defined here...");
+                        err.span_note(sup_span, "...must outlive the lifetime defined here");
                     }
                     _ => {}
                 }
index ba990acfe6fc4a5991bfcba2d65c7355f25a971b..da2c6fbc05f576f2a76128878891e828f51c546a 100644 (file)
@@ -488,7 +488,7 @@ fn sub_region_values(&self, a: VarValue<'tcx>, b: VarValue<'tcx>) -> bool {
                         // If this empty region is from a universe that can
                         // name the placeholder, then the placeholder is
                         // larger; otherwise, the only ancestor is `'static`.
-                        if a_ui.can_name(placeholder.universe) { true } else { false }
+                        return a_ui.can_name(placeholder.universe);
                     }
                 }
             }
index 996148a709087161775337d9945aa262c7888749..a9ef91db059a1ccf381749b61b61b92407559152 100644 (file)
@@ -1693,7 +1693,7 @@ pub fn resolve_regions_and_report_errors(
         &self,
         generic_param_scope: LocalDefId,
         outlives_env: &OutlivesEnvironment<'tcx>,
-    ) {
+    ) -> Option<ErrorGuaranteed> {
         let errors = self.resolve_regions(outlives_env);
 
         if let None = self.tainted_by_errors() {
@@ -1704,6 +1704,10 @@ pub fn resolve_regions_and_report_errors(
             // errors from silly ones.
             self.report_region_errors(generic_param_scope, &errors);
         }
+
+        (!errors.is_empty()).then(|| {
+            self.tcx.sess.delay_span_bug(rustc_span::DUMMY_SP, "error should have been emitted")
+        })
     }
 
     // [Note-Type-error-reporting]
@@ -1920,7 +1924,7 @@ pub fn poly_trait_refs(
     ) -> TypeTrace<'tcx> {
         TypeTrace {
             cause: cause.clone(),
-            values: PolyTraitRefs(ExpectedFound::new(a_is_expected, a.into(), b.into())),
+            values: PolyTraitRefs(ExpectedFound::new(a_is_expected, a, b)),
         }
     }
 
index ccae7165d80d2fac9d859c26b64031742bcbd244..47bd1564f0828ab1a36cb97f74d81b3f05143128 100644 (file)
@@ -68,6 +68,7 @@
 };
 use crate::traits::{ObligationCause, ObligationCauseCode};
 use rustc_data_structures::undo_log::UndoLogs;
+use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def_id::DefId;
 use rustc_hir::def_id::LocalDefId;
 use rustc_middle::mir::ConstraintCategory;
@@ -177,7 +178,7 @@ pub fn check_region_obligations_and_report_errors(
         &self,
         generic_param_scope: LocalDefId,
         outlives_env: &OutlivesEnvironment<'tcx>,
-    ) {
+    ) -> Option<ErrorGuaranteed> {
         self.process_registered_region_obligations(
             outlives_env.region_bound_pairs(),
             outlives_env.param_env,
index 136da4a3cb12a110eaaffd96606370628219f855..40bbec8ddd091da396b17dcb866004b4b10cab20 100644 (file)
@@ -5,7 +5,7 @@
 use rustc_data_structures::sso::SsoHashSet;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::GenericArg;
-use rustc_middle::ty::{self, EarlyBinder, OutlivesPredicate, SubstsRef, Ty, TyCtxt};
+use rustc_middle::ty::{self, OutlivesPredicate, SubstsRef, Ty, TyCtxt};
 
 use smallvec::smallvec;
 
@@ -304,14 +304,13 @@ pub fn declared_region_bounds(
         substs: SubstsRef<'tcx>,
     ) -> impl Iterator<Item = ty::Region<'tcx>> {
         let tcx = self.tcx;
-        let bounds = tcx.item_bounds(def_id);
-        trace!("{:#?}", bounds);
+        let bounds = tcx.bound_item_bounds(def_id);
+        trace!("{:#?}", bounds.0);
         bounds
-            .into_iter()
+            .subst_iter(tcx, substs)
             .filter_map(|p| p.to_opt_type_outlives())
             .filter_map(|p| p.no_bound_vars())
-            .map(|b| b.1)
-            .map(move |r| EarlyBinder(r).subst(tcx, substs))
+            .map(|OutlivesPredicate(_, r)| r)
     }
 
     /// Searches through a predicate list for a predicate `T: 'a`.
index 22b4bbb17d47fd3e38948d6dd51e545588d39ade..c46edc33ff40ccd13ac18c7fbc43a15a49a6de96 100644 (file)
@@ -357,15 +357,13 @@ fn take_min(&mut self, universe: ty::UniverseIndex, region: ty::Region<'tcx>) {
 }
 
 rustc_index::newtype_index! {
-    struct LeakCheckNode {
-        DEBUG_FORMAT = "LeakCheckNode({})"
-    }
+    #[debug_format = "LeakCheckNode({})"]
+    struct LeakCheckNode {}
 }
 
 rustc_index::newtype_index! {
-    struct LeakCheckScc {
-        DEBUG_FORMAT = "LeakCheckScc({})"
-    }
+    #[debug_format = "LeakCheckScc({})"]
+    struct LeakCheckScc {}
 }
 
 /// Represents the graph of constraints. For each `R1: R2` constraint we create
index 611961ab1cc94afb98501fb1b205e4502af4199a..955c54e85157eb9279ab9f788701fb531a27ccbb 100644 (file)
@@ -87,18 +87,12 @@ fn reverse(&mut self, undo: UndoLog<'tcx>) {
 
 /// The combined undo log for all the various unification tables. For each change to the storage
 /// for any kind of inference variable, we record an UndoLog entry in the vector here.
-#[derive(Clone)]
+#[derive(Clone, Default)]
 pub(crate) struct InferCtxtUndoLogs<'tcx> {
     logs: Vec<UndoLog<'tcx>>,
     num_open_snapshots: usize,
 }
 
-impl Default for InferCtxtUndoLogs<'_> {
-    fn default() -> Self {
-        Self { logs: Default::default(), num_open_snapshots: Default::default() }
-    }
-}
-
 /// The UndoLogs trait defines how we undo a particular kind of action (of type T). We can undo any
 /// action that is convertible into an UndoLog (per the From impls above).
 impl<'tcx, T> UndoLogs<T> for InferCtxtUndoLogs<'tcx>
index aade57be9fe6ef1f17389df22b23518193a1a243..ac455055b430375ce8aa245d092498ed9a67e199 100644 (file)
@@ -200,7 +200,7 @@ pub fn insert_term(
     pub fn complete(&mut self, key: ProjectionCacheKey<'tcx>, result: EvaluationResult) {
         let mut map = self.map();
         match map.get(&key) {
-            Some(&ProjectionCacheEntry::NormalizedTy { ref ty, complete: _ }) => {
+            Some(ProjectionCacheEntry::NormalizedTy { ty, complete: _ }) => {
                 info!("ProjectionCacheEntry::complete({:?}) - completing {:?}", key, ty);
                 let mut ty = ty.clone();
                 if result.must_apply_considering_regions() {
index 39e1f2204b002010176277dadfb531098f096730..1d0c7f5b7a388fab828bc2cfddffcb74da82bda9 100644 (file)
@@ -127,7 +127,7 @@ pub fn parse(&self) -> Result<&Query<ast::Crate>> {
 
     pub fn register_plugins(&self) -> Result<&Query<(ast::Crate, Lrc<LintStore>)>> {
         self.register_plugins.compute(|| {
-            let crate_name = self.crate_name()?.peek().clone();
+            let crate_name = *self.crate_name()?.peek();
             let krate = self.parse()?.take();
 
             let empty: &(dyn Fn(&Session, &mut LintStore) + Sync + Send) = &|_, _| {};
index e903cb86dd20438a9264fcdf67bfedf6f3783cb4..ff2196d58577c817557e23d497733fbbc7c00f2e 100644 (file)
@@ -754,6 +754,7 @@ macro_rules! tracked {
     tracked!(move_size_limit, Some(4096));
     tracked!(mutable_noalias, Some(true));
     tracked!(no_generate_arange_section, true);
+    tracked!(no_jump_tables, true);
     tracked!(no_link, true);
     tracked!(no_profiler_runtime, true);
     tracked!(no_unique_section_names, true);
index 43862570e80954aa8c11dbd80e4aa4e060e66ed9..cd19e65b6fc3275d5b608569ec9e08136c579c36 100644 (file)
@@ -270,7 +270,7 @@ fn check_pat(&mut self, cx: &LateContext<'_>, pat: &hir::Pat<'_>) {
                             |lint| {
                                 let suggested_ident =
                                     format!("{}{}", binding_annot.prefix_str(), ident);
-                                lint.set_arg("ident", ident.clone()).span_suggestion(
+                                lint.set_arg("ident", ident).span_suggestion(
                                     fieldpat.span,
                                     fluent::suggestion,
                                     suggested_ident,
@@ -2052,7 +2052,7 @@ fn check_ident_token(
             ident.span,
             fluent::lint_builtin_keyword_idents,
             |lint| {
-                lint.set_arg("kw", ident.clone()).set_arg("next", next_edition).span_suggestion(
+                lint.set_arg("kw", ident).set_arg("next", next_edition).span_suggestion(
                     ident.span,
                     fluent::suggestion,
                     format!("r#{}", ident),
index 40b2588388d66886353297cc50a5070b0bdd6069..0417f375588cc8a0500e17307b1878efa69ff603 100644 (file)
@@ -438,18 +438,18 @@ pub fn check_lint_name(
                         return CheckLintNameResult::Tool(Ok(&lint_ids));
                     }
                 },
-                Some(&Id(ref id)) => return CheckLintNameResult::Tool(Ok(slice::from_ref(id))),
+                Some(Id(id)) => return CheckLintNameResult::Tool(Ok(slice::from_ref(id))),
                 // If the lint was registered as removed or renamed by the lint tool, we don't need
                 // to treat tool_lints and rustc lints different and can use the code below.
                 _ => {}
             }
         }
         match self.by_name.get(&complete_name) {
-            Some(&Renamed(ref new_name, _)) => CheckLintNameResult::Warning(
+            Some(Renamed(new_name, _)) => CheckLintNameResult::Warning(
                 format!("lint `{}` has been renamed to `{}`", complete_name, new_name),
                 Some(new_name.to_owned()),
             ),
-            Some(&Removed(ref reason)) => CheckLintNameResult::Warning(
+            Some(Removed(reason)) => CheckLintNameResult::Warning(
                 format!("lint `{}` has been removed: {}", complete_name, reason),
                 None,
             ),
@@ -470,7 +470,7 @@ pub fn check_lint_name(
                     CheckLintNameResult::Ok(&lint_ids)
                 }
             },
-            Some(&Id(ref id)) => CheckLintNameResult::Ok(slice::from_ref(id)),
+            Some(Id(id)) => CheckLintNameResult::Ok(slice::from_ref(id)),
             Some(&Ignored) => CheckLintNameResult::Ok(&[]),
         }
     }
@@ -513,7 +513,7 @@ fn check_tool_name_for_backwards_compat(
                     CheckLintNameResult::Tool(Err((Some(&lint_ids), complete_name)))
                 }
             },
-            Some(&Id(ref id)) => {
+            Some(Id(id)) => {
                 CheckLintNameResult::Tool(Err((Some(slice::from_ref(id)), complete_name)))
             }
             Some(other) => {
index 4187850153ccd001c22f3659f4803a0f5b1ea75c..182734fa9fc8fc72970117c5c32e7746de87e62e 100644 (file)
@@ -71,11 +71,11 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                 );
             } else {
                 lint.multipart_suggestion_verbose(
-                    format!("to check pattern in a loop use `while let`"),
+                    "to check pattern in a loop use `while let`",
                     vec![
                         // NB can't use `until` here because `expr.span` and `pat.span` have different syntax contexts
                         (expr.span.with_hi(pat.span.lo()), format!("while let {var}(")),
-                        (pat.span.between(arg.span), format!(") = ")),
+                        (pat.span.between(arg.span), ") = ".to_string()),
                     ],
                     Applicability::MaybeIncorrect
                 );
@@ -95,7 +95,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                 vec![
                     // NB can't use `until` here because `expr.span` and `pat.span` have different syntax contexts
                     (expr.span.with_hi(pat.span.lo()), format!("if let {var}(")),
-                    (pat.span.between(arg.span), format!(") = ")),
+                    (pat.span.between(arg.span), ") = ".to_string()),
                 ],
                 Applicability::MaybeIncorrect,
             )
index 847c356b83c0b3c5519771560e2b1f9a7d0d8e4a..e9d3d44a3f9f9f6e6fede79abd3d00190aa2bd1d 100644 (file)
@@ -39,9 +39,9 @@ struct LintLevelSets {
 }
 
 rustc_index::newtype_index! {
+    #[custom_encodable] // we don't need encoding
     struct LintStackIndex {
-        ENCODABLE = custom, // we don't need encoding
-        const COMMAND_LINE = 0,
+        const COMMAND_LINE = 0;
     }
 }
 
index 7e50801f80c7bbbf6797b8aa84224ff84dc61b18..91fcd6d690ee7a52c819546eccc065dca1baf64c 100644 (file)
@@ -175,13 +175,23 @@ fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) {
             return;
         }
 
-        match it.kind {
+        match &it.kind {
             ast::ItemKind::TyAlias(..)
             | ast::ItemKind::Enum(..)
             | ast::ItemKind::Struct(..)
             | ast::ItemKind::Union(..) => self.check_case(cx, "type", &it.ident),
             ast::ItemKind::Trait(..) => self.check_case(cx, "trait", &it.ident),
             ast::ItemKind::TraitAlias(..) => self.check_case(cx, "trait alias", &it.ident),
+
+            // N.B. This check is only for inherent associated types, so that we don't lint against
+            // trait impls where we should have warned for the trait definition already.
+            ast::ItemKind::Impl(box ast::Impl { of_trait: None, items, .. }) => {
+                for it in items {
+                    if let ast::AssocItemKind::Type(..) = it.kind {
+                        self.check_case(cx, "associated type", &it.ident);
+                    }
+                }
+            }
             _ => (),
         }
     }
index d628a18dd01c5875c36e5ad8bebb8940b8f89cc6..3b8df61a0eab771a704f9ed9006bbd1807b612fa 100644 (file)
@@ -1279,7 +1279,7 @@ impl UnusedImportBraces {
     fn check_use_tree(&self, cx: &EarlyContext<'_>, use_tree: &ast::UseTree, item: &ast::Item) {
         if let ast::UseTreeKind::Nested(ref items) = use_tree.kind {
             // Recursively check nested UseTrees
-            for &(ref tree, _) in items {
+            for (tree, _) in items {
                 self.check_use_tree(cx, tree, item);
             }
 
index a3008e9e321c8b00736aa4a9636bae292dce5ba3..f7a4103f4d5c1a06a4b6e4e7cd050684b926b31f 100644 (file)
     };
 }
 
+declare_lint! {
+    /// The `invalid_alignment` lint detects dereferences of misaligned pointers during
+    /// constant evluation.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![feature(const_ptr_read)]
+    /// const FOO: () = unsafe {
+    ///     let x = &[0_u8; 4];
+    ///     let y = x.as_ptr().cast::<u32>();
+    ///     y.read(); // the address of a `u8` array is unknown and thus we don't know if
+    ///     // it is aligned enough for reading a `u32`.
+    /// };
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The compiler allowed dereferencing raw pointers irrespective of alignment
+    /// during const eval due to the const evaluator at the time not making it easy
+    /// or cheap to check. Now that it is both, this is not accepted anymore.
+    ///
+    /// Since it was undefined behaviour to begin with, this breakage does not violate
+    /// Rust's stability guarantees. Using undefined behaviour can cause arbitrary
+    /// behaviour, including failure to build.
+    ///
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
+    pub INVALID_ALIGNMENT,
+    Deny,
+    "raw pointers must be aligned before dereferencing",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #68585 <https://github.com/rust-lang/rust/issues/104616>",
+        reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
+    };
+}
+
 declare_lint! {
     /// The `exported_private_dependencies` lint detects private dependencies
     /// that are exposed in a public interface.
         FFI_UNWIND_CALLS,
         REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
         NAMED_ARGUMENTS_USED_POSITIONALLY,
+        IMPLIED_BOUNDS_ENTAILMENT,
     ]
 }
 
     Warn,
     "named arguments in format used positionally"
 }
+
+declare_lint! {
+    /// The `implied_bounds_entailment` lint detects cases where the arguments of an impl method
+    /// have stronger implied bounds than those from the trait method it's implementing.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(implied_bounds_entailment)]
+    ///
+    /// trait Trait {
+    ///     fn get<'s>(s: &'s str, _: &'static &'static ()) -> &'static str;
+    /// }
+    ///
+    /// impl Trait for () {
+    ///     fn get<'s>(s: &'s str, _: &'static &'s ()) -> &'static str {
+    ///         s
+    ///     }
+    /// }
+    ///
+    /// let val = <() as Trait>::get(&String::from("blah blah blah"), &&());
+    /// println!("{}", val);
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Neither the trait method, which provides no implied bounds about `'s`, nor the impl,
+    /// requires the main function to prove that 's: 'static, but the impl method is allowed
+    /// to assume that `'s: 'static` within its own body.
+    ///
+    /// This can be used to implement an unsound API if used incorrectly.
+    pub IMPLIED_BOUNDS_ENTAILMENT,
+    Warn,
+    "impl method assumes more implied bounds than its corresponding trait method",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #105572 <https://github.com/rust-lang/rust/issues/105572>",
+        reason: FutureIncompatibilityReason::FutureReleaseError,
+    };
+}
index 13f06fe747349d8084b9b53d1a303c75f9b0278b..9ff944864047753173598cdbe56778f022e2e919 100644 (file)
@@ -39,10 +39,8 @@ pub(crate) fn into_tokens(self) -> TokenStream {
             let init = match builder.slug.value_ref() {
                 None => {
                     span_err(builder.span, "diagnostic slug not specified")
-                        .help(format!(
-                            "specify the slug as the first argument to the `#[diag(...)]` \
-                            attribute, such as `#[diag(hir_analysis_example_error)]`",
-                        ))
+                        .help("specify the slug as the first argument to the `#[diag(...)]` \
+                            attribute, such as `#[diag(hir_analysis_example_error)]`")
                         .emit();
                     return DiagnosticDeriveError::ErrorHandled.to_compile_error();
                 }
@@ -133,10 +131,8 @@ pub(crate) fn into_tokens(self) -> TokenStream {
             match builder.slug.value_ref() {
                 None => {
                     span_err(builder.span, "diagnostic slug not specified")
-                        .help(format!(
-                            "specify the slug as the first argument to the attribute, such as \
-                            `#[diag(compiletest_example)]`",
-                        ))
+                        .help("specify the slug as the first argument to the attribute, such as \
+                            `#[diag(compiletest_example)]`")
                         .emit();
                     DiagnosticDeriveError::ErrorHandled.to_compile_error()
                 }
index fd3f5225155508d23f7d184bd93210fc863b709a..153473de6244952770385d1f5233ac4106a17168 100644 (file)
@@ -1,35 +1,15 @@
 use proc_macro2::{Span, TokenStream};
 use quote::quote;
 use syn::parse::*;
-use syn::punctuated::Punctuated;
 use syn::*;
 
-mod kw {
-    syn::custom_keyword!(derive);
-    syn::custom_keyword!(DEBUG_FORMAT);
-    syn::custom_keyword!(MAX);
-    syn::custom_keyword!(ENCODABLE);
-    syn::custom_keyword!(custom);
-    syn::custom_keyword!(ORD_IMPL);
-}
-
-#[derive(Debug)]
-enum DebugFormat {
-    // The user will provide a custom `Debug` impl, so we shouldn't generate
-    // one
-    Custom,
-    // Use the specified format string in the generated `Debug` impl
-    // By default, this is "{}"
-    Format(String),
-}
-
 // We parse the input and emit the output in a single step.
 // This field stores the final macro output
 struct Newtype(TokenStream);
 
 impl Parse for Newtype {
     fn parse(input: ParseStream<'_>) -> Result<Self> {
-        let attrs = input.call(Attribute::parse_outer)?;
+        let mut attrs = input.call(Attribute::parse_outer)?;
         let vis: Visibility = input.parse()?;
         input.parse::<Token![struct]>()?;
         let name: Ident = input.parse()?;
@@ -39,93 +19,68 @@ fn parse(input: ParseStream<'_>) -> Result<Self> {
 
         // Any additional `#[derive]` macro paths to apply
         let mut derive_paths: Vec<Path> = Vec::new();
-        let mut debug_format: Option<DebugFormat> = None;
+        let mut debug_format: Option<Lit> = None;
         let mut max = None;
         let mut consts = Vec::new();
         let mut encodable = true;
         let mut ord = true;
 
-        // Parse an optional trailing comma
-        let try_comma = || -> Result<()> {
-            if body.lookahead1().peek(Token![,]) {
-                body.parse::<Token![,]>()?;
-            }
-            Ok(())
-        };
-
-        if body.lookahead1().peek(Token![..]) {
-            body.parse::<Token![..]>()?;
-        } else {
-            loop {
-                if body.lookahead1().peek(kw::derive) {
-                    body.parse::<kw::derive>()?;
-                    let derives;
-                    bracketed!(derives in body);
-                    let derives: Punctuated<Path, Token![,]> =
-                        derives.parse_terminated(Path::parse)?;
-                    try_comma()?;
-                    derive_paths.extend(derives);
-                    continue;
-                }
-                if body.lookahead1().peek(kw::DEBUG_FORMAT) {
-                    body.parse::<kw::DEBUG_FORMAT>()?;
-                    body.parse::<Token![=]>()?;
-                    let new_debug_format = if body.lookahead1().peek(kw::custom) {
-                        body.parse::<kw::custom>()?;
-                        DebugFormat::Custom
-                    } else {
-                        let format_str: LitStr = body.parse()?;
-                        DebugFormat::Format(format_str.value())
-                    };
-                    try_comma()?;
-                    if let Some(old) = debug_format.replace(new_debug_format) {
-                        panic!("Specified multiple debug format options: {:?}", old);
-                    }
-                    continue;
-                }
-                if body.lookahead1().peek(kw::MAX) {
-                    body.parse::<kw::MAX>()?;
-                    body.parse::<Token![=]>()?;
-                    let val: Lit = body.parse()?;
-                    try_comma()?;
-                    if let Some(old) = max.replace(val) {
-                        panic!("Specified multiple MAX: {:?}", old);
-                    }
-                    continue;
-                }
-                if body.lookahead1().peek(kw::ENCODABLE) {
-                    body.parse::<kw::ENCODABLE>()?;
-                    body.parse::<Token![=]>()?;
-                    body.parse::<kw::custom>()?;
-                    try_comma()?;
+        attrs.retain(|attr| match attr.path.get_ident() {
+            Some(ident) => match &*ident.to_string() {
+                "custom_encodable" => {
                     encodable = false;
-                    continue;
+                    false
                 }
-                if body.lookahead1().peek(kw::ORD_IMPL) {
-                    body.parse::<kw::ORD_IMPL>()?;
-                    body.parse::<Token![=]>()?;
-                    body.parse::<kw::custom>()?;
+                "no_ord_impl" => {
                     ord = false;
-                    continue;
+                    false
                 }
+                "max" => {
+                    let Ok(Meta::NameValue(literal) )= attr.parse_meta() else {
+                        panic!("#[max = NUMBER] attribute requires max value");
+                    };
+
+                    if let Some(old) = max.replace(literal.lit) {
+                        panic!("Specified multiple max: {:?}", old);
+                    }
 
-                // We've parsed everything that the user provided, so we're done
-                if body.is_empty() {
-                    break;
+                    false
                 }
+                "debug_format" => {
+                    let Ok(Meta::NameValue(literal) )= attr.parse_meta() else {
+                        panic!("#[debug_format = FMT] attribute requires a format");
+                    };
+
+                    if let Some(old) = debug_format.replace(literal.lit) {
+                        panic!("Specified multiple debug format options: {:?}", old);
+                    }
 
-                // Otherwise, we are parsing a user-defined constant
-                let const_attrs = body.call(Attribute::parse_outer)?;
-                body.parse::<Token![const]>()?;
-                let const_name: Ident = body.parse()?;
-                body.parse::<Token![=]>()?;
-                let const_val: Expr = body.parse()?;
-                try_comma()?;
-                consts.push(quote! { #(#const_attrs)* #vis const #const_name: #name = #name::from_u32(#const_val); });
+                    false
+                }
+                _ => true,
+            },
+            _ => true,
+        });
+
+        loop {
+            // We've parsed everything that the user provided, so we're done
+            if body.is_empty() {
+                break;
             }
+
+            // Otherwise, we are parsing a user-defined constant
+            let const_attrs = body.call(Attribute::parse_outer)?;
+            body.parse::<Token![const]>()?;
+            let const_name: Ident = body.parse()?;
+            body.parse::<Token![=]>()?;
+            let const_val: Expr = body.parse()?;
+            body.parse::<Token![;]>()?;
+            consts.push(quote! { #(#const_attrs)* #vis const #const_name: #name = #name::from_u32(#const_val); });
         }
 
-        let debug_format = debug_format.unwrap_or(DebugFormat::Format("{}".to_string()));
+        let debug_format =
+            debug_format.unwrap_or_else(|| Lit::Str(LitStr::new("{}", Span::call_site())));
+
         // shave off 256 indices at the end to allow space for packing these indices into enums
         let max = max.unwrap_or_else(|| Lit::Int(LitInt::new("0xFFFF_FF00", Span::call_site())));
 
@@ -180,18 +135,14 @@ unsafe impl ::std::iter::TrustedStep for #name {}
             quote! {}
         };
 
-        let debug_impl = match debug_format {
-            DebugFormat::Custom => quote! {},
-            DebugFormat::Format(format) => {
-                quote! {
-                    impl ::std::fmt::Debug for #name {
-                        fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
-                            write!(fmt, #format, self.as_u32())
-                        }
-                    }
+        let debug_impl = quote! {
+            impl ::std::fmt::Debug for #name {
+                fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
+                    write!(fmt, #debug_format, self.as_u32())
                 }
             }
         };
+
         let spec_partial_eq_impl = if let Lit::Int(max) = &max {
             if let Ok(max_val) = max.base10_parse::<u32>() {
                 quote! {
index 01d7f3e03c50a5520d5c4d5f3efe1bd8a7d67d9d..9ce3ff98ba985bac96973926e662e8b693280688 100644 (file)
@@ -1,10 +1,9 @@
 //! Validates all used crates and extern libraries and loads their metadata
 
 use crate::errors::{
-    AllocFuncRequired, ConflictingAllocErrorHandler, ConflictingGlobalAlloc, CrateNotPanicRuntime,
-    GlobalAllocRequired, MissingAllocErrorHandler, NoMultipleAllocErrorHandler,
-    NoMultipleGlobalAlloc, NoPanicStrategy, NoTransitiveNeedsDep, NotProfilerRuntime,
-    ProfilerBuiltinsNeedsCore,
+    ConflictingAllocErrorHandler, ConflictingGlobalAlloc, CrateNotPanicRuntime,
+    GlobalAllocRequired, NoMultipleAllocErrorHandler, NoMultipleGlobalAlloc, NoPanicStrategy,
+    NoTransitiveNeedsDep, NotProfilerRuntime, ProfilerBuiltinsNeedsCore,
 };
 use crate::locator::{CrateError, CrateLocator, CratePaths};
 use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob};
@@ -895,10 +894,6 @@ fn inject_allocator_crate(&mut self, krate: &ast::Crate) {
         } else {
             // The alloc crate provides a default allocation error handler if
             // one isn't specified.
-            if !self.sess.features_untracked().default_alloc_error_handler {
-                self.sess.emit_err(AllocFuncRequired);
-                self.sess.emit_note(MissingAllocErrorHandler);
-            }
             self.cstore.alloc_error_handler_kind = Some(AllocatorKind::Default);
         }
     }
index 6f7e6e09ca5eddfabcf7ff0c908c7ce2a9de72d9..de2a879f1d73769c59f4dda5661f1abc93e1b5cf 100644 (file)
@@ -371,14 +371,6 @@ pub struct ConflictingAllocErrorHandler {
 #[diag(metadata_global_alloc_required)]
 pub struct GlobalAllocRequired;
 
-#[derive(Diagnostic)]
-#[diag(metadata_alloc_func_required)]
-pub struct AllocFuncRequired;
-
-#[derive(Diagnostic)]
-#[diag(metadata_missing_alloc_error_handler)]
-pub struct MissingAllocErrorHandler;
-
 #[derive(Diagnostic)]
 #[diag(metadata_no_transitive_needs_dep)]
 pub struct NoTransitiveNeedsDep<'a> {
index 856f5bc4645fdd34d691e7ab3a824ef603da15d1..4af423f2a22e4be1f1c886882f57acad83ac6a6e 100644 (file)
@@ -332,7 +332,7 @@ fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) {
                     s.emit_str(self.as_str());
                 }
                 Entry::Occupied(o) => {
-                    let x = o.get().clone();
+                    let x = *o.get();
                     s.emit_u8(SYMBOL_OFFSET);
                     s.emit_usize(x);
                 }
@@ -1849,7 +1849,7 @@ fn encode_crate_deps(&mut self) -> LazyArray<CrateDep> {
         // the assumption that they are numbered 1 to n.
         // FIXME (#2166): This is not nearly enough to support correct versioning
         // but is enough to get transitive crate dependencies working.
-        self.lazy_array(deps.iter().map(|&(_, ref dep)| dep))
+        self.lazy_array(deps.iter().map(|(_, dep)| dep))
     }
 
     fn encode_lib_features(&mut self) -> LazyArray<(Symbol, Option<Symbol>)> {
@@ -1986,7 +1986,7 @@ fn encode_exported_symbols(
         self.lazy_array(
             exported_symbols
                 .iter()
-                .filter(|&&(ref exported_symbol, _)| match *exported_symbol {
+                .filter(|&(exported_symbol, _)| match *exported_symbol {
                     ExportedSymbol::NoDefId(symbol_name) => symbol_name != metadata_symbol_name,
                     _ => true,
                 })
index 6de68841fe91f41fa84faa97f77ce3448350d9e9..75282f958b53b3b738c6498f16600f59209f2698 100644 (file)
@@ -93,7 +93,7 @@ macro_rules! arena_types {
             // Interned types
             [] tys: rustc_type_ir::WithCachedTypeInfo<rustc_middle::ty::TyKind<'tcx>>,
             [] predicates: rustc_type_ir::WithCachedTypeInfo<rustc_middle::ty::PredicateKind<'tcx>>,
-            [] consts: rustc_middle::ty::ConstS<'tcx>,
+            [] consts: rustc_middle::ty::ConstData<'tcx>,
 
             // Note that this deliberately duplicates items in the `rustc_hir::arena`,
             // since we need to allocate this type on both the `rustc_hir` arena
index fc08d58cc40687765dbf33fa580b95a17dcbe1fc..0e18ba73d7129da3bd04fc6b0852ec90f493de53 100644 (file)
@@ -103,12 +103,7 @@ pub fn is_directly_public(&self, id: LocalDefId) -> bool {
 
     pub fn public_at_level(&self, id: LocalDefId) -> Option<Level> {
         self.effective_vis(id).and_then(|effective_vis| {
-            for level in Level::all_levels() {
-                if effective_vis.is_public_at_level(level) {
-                    return Some(level);
-                }
-            }
-            None
+            Level::all_levels().into_iter().find(|&level| effective_vis.is_public_at_level(level))
         })
     }
 
index c886175c6ea0e2ddf25aad35f42de2fcbe97333a..94ca38c0e758ff2bf9615572b552e2f7b85d10eb 100644 (file)
@@ -147,9 +147,8 @@ pub enum ScopeData {
     ///
     /// * The subscope with `first_statement_index == 1` is scope of `c`,
     ///   and thus does not include EXPR_2, but covers the `...`.
-    pub struct FirstStatementIndex {
-        derive [HashStable]
-    }
+    #[derive(HashStable)]
+    pub struct FirstStatementIndex {}
 }
 
 // compilation error if size of `ScopeData` is not the same as a `u32`
index 0b55757eb038298d32ee3598e9a07fe5732e0d15..e7bb3ab0bc352d6016fb83389c9df33aa0c14553 100644 (file)
     /// CounterValueReference.as_u32() (which ascend from 1) or an ExpressionOperandId.as_u32()
     /// (which _*descend*_ from u32::MAX). Id value `0` (zero) represents a virtual counter with a
     /// constant value of `0`.
+    #[derive(HashStable)]
+    #[max = 0xFFFF_FFFF]
+    #[debug_format = "ExpressionOperandId({})"]
     pub struct ExpressionOperandId {
-        derive [HashStable]
-        DEBUG_FORMAT = "ExpressionOperandId({})",
-        MAX = 0xFFFF_FFFF,
     }
 }
 
@@ -32,11 +32,10 @@ impl ExpressionOperandId {
 }
 
 rustc_index::newtype_index! {
-    pub struct CounterValueReference {
-        derive [HashStable]
-        DEBUG_FORMAT = "CounterValueReference({})",
-        MAX = 0xFFFF_FFFF,
-    }
+    #[derive(HashStable)]
+    #[max = 0xFFFF_FFFF]
+    #[debug_format = "CounterValueReference({})"]
+    pub struct CounterValueReference {}
 }
 
 impl CounterValueReference {
@@ -56,33 +55,30 @@ pub fn zero_based_index(self) -> u32 {
     /// InjectedExpressionId.as_u32() converts to ExpressionOperandId.as_u32()
     ///
     /// Values descend from u32::MAX.
-    pub struct InjectedExpressionId {
-        derive [HashStable]
-        DEBUG_FORMAT = "InjectedExpressionId({})",
-        MAX = 0xFFFF_FFFF,
-    }
+    #[derive(HashStable)]
+    #[max = 0xFFFF_FFFF]
+    #[debug_format = "InjectedExpressionId({})"]
+    pub struct InjectedExpressionId {}
 }
 
 rustc_index::newtype_index! {
     /// InjectedExpressionIndex.as_u32() translates to u32::MAX - ExpressionOperandId.as_u32()
     ///
     /// Values ascend from 0.
-    pub struct InjectedExpressionIndex {
-        derive [HashStable]
-        DEBUG_FORMAT = "InjectedExpressionIndex({})",
-        MAX = 0xFFFF_FFFF,
-    }
+    #[derive(HashStable)]
+    #[max = 0xFFFF_FFFF]
+    #[debug_format = "InjectedExpressionIndex({})"]
+    pub struct InjectedExpressionIndex {}
 }
 
 rustc_index::newtype_index! {
     /// MappedExpressionIndex values ascend from zero, and are recalculated indexes based on their
     /// array position in the LLVM coverage map "Expressions" array, which is assembled during the
     /// "mapgen" process. They cannot be computed algorithmically, from the other `newtype_index`s.
-    pub struct MappedExpressionIndex {
-        derive [HashStable]
-        DEBUG_FORMAT = "MappedExpressionIndex({})",
-        MAX = 0xFFFF_FFFF,
-    }
+    #[derive(HashStable)]
+    #[max = 0xFFFF_FFFF]
+    #[debug_format = "MappedExpressionIndex({})"]
+    pub struct MappedExpressionIndex {}
 }
 
 impl From<CounterValueReference> for ExpressionOperandId {
index 3bc331e19c1ccddb0e8ee8b7f5cb282f3ad934cc..ffdf61d424422a5b19010a98bc599873a52a1c72 100644 (file)
@@ -533,6 +533,11 @@ pub fn should_skip(&self) -> bool {
         };
         injection_phase > self.phase
     }
+
+    #[inline]
+    pub fn is_custom_mir(&self) -> bool {
+        self.injection_phase.is_some()
+    }
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, Debug, TyEncodable, TyDecodable, HashStable)]
@@ -649,10 +654,10 @@ pub fn outermost(span: Span) -> Self {
 // Variables and temps
 
 rustc_index::newtype_index! {
+    #[derive(HashStable)]
+    #[debug_format = "_{}"]
     pub struct Local {
-        derive [HashStable]
-        DEBUG_FORMAT = "_{}",
-        const RETURN_PLACE = 0,
+        const RETURN_PLACE = 0;
     }
 }
 
@@ -1141,10 +1146,10 @@ pub struct VarDebugInfo<'tcx> {
     ///     https://rustc-dev-guide.rust-lang.org/appendix/background.html#what-is-a-dataflow-analysis
     /// [`CriticalCallEdges`]: ../../rustc_const_eval/transform/add_call_guards/enum.AddCallGuards.html#variant.CriticalCallEdges
     /// [guide-mir]: https://rustc-dev-guide.rust-lang.org/mir/
+    #[derive(HashStable)]
+    #[debug_format = "bb{}"]
     pub struct BasicBlock {
-        derive [HashStable]
-        DEBUG_FORMAT = "bb{}",
-        const START_BLOCK = 0,
+        const START_BLOCK = 0;
     }
 }
 
@@ -1525,10 +1530,9 @@ pub fn is_field_to(&self, f: Field) -> bool {
     /// [wrapper]: https://rustc-dev-guide.rust-lang.org/appendix/glossary.html#newtype
     /// [CFG]: https://rustc-dev-guide.rust-lang.org/appendix/background.html#cfg
     /// [mir-datatypes]: https://rustc-dev-guide.rust-lang.org/mir/index.html#mir-data-types
-    pub struct Field {
-        derive [HashStable]
-        DEBUG_FORMAT = "field[{}]"
-    }
+    #[derive(HashStable)]
+    #[debug_format = "field[{}]"]
+    pub struct Field {}
 }
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
@@ -1752,10 +1756,10 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
 // Scopes
 
 rustc_index::newtype_index! {
+    #[derive(HashStable)]
+    #[debug_format = "scope[{}]"]
     pub struct SourceScope {
-        derive [HashStable]
-        DEBUG_FORMAT = "scope[{}]",
-        const OUTERMOST_SOURCE_SCOPE = 0,
+        const OUTERMOST_SOURCE_SCOPE = 0;
     }
 }
 
@@ -2750,10 +2754,9 @@ fn visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> ControlFlow<Vs:
 }
 
 rustc_index::newtype_index! {
-    pub struct Promoted {
-        derive [HashStable]
-        DEBUG_FORMAT = "promoted[{}]"
-    }
+    #[derive(HashStable)]
+    #[debug_format = "promoted[{}]"]
+    pub struct Promoted {}
 }
 
 impl<'tcx> Debug for Constant<'tcx> {
index 15a24aa4ace512f1b453902ddca2e34d2033abab..1e8d5f7eae87a8881edadb729794f43e43fc9a9e 100644 (file)
@@ -200,6 +200,15 @@ pub fn krate(&self) -> CrateNum {
             MonoItem::GlobalAsm(..) => LOCAL_CRATE,
         }
     }
+
+    /// Returns the item's `DefId`
+    pub fn def_id(&self) -> DefId {
+        match *self {
+            MonoItem::Fn(Instance { def, .. }) => def.def_id(),
+            MonoItem::Static(def_id) => def_id,
+            MonoItem::GlobalAsm(item_id) => item_id.owner_id.to_def_id(),
+        }
+    }
 }
 
 impl<'tcx> fmt::Display for MonoItem<'tcx> {
index 2a4ff4b8810dbc513171e07fb969e8f299e033f3..1ebfdbbd6ef000b61ba2f04c191247b10f7999e7 100644 (file)
@@ -448,15 +448,15 @@ fn visit_constant(&mut self, constant: &Constant<'tcx>, _location: Location) {
 
             // FIXME: this is a poor version of `pretty_print_const_value`.
             let fmt_val = |val: &ConstValue<'tcx>| match val {
-                ConstValue::ZeroSized => format!("<ZST>"),
+                ConstValue::ZeroSized => "<ZST>".to_string(),
                 ConstValue::Scalar(s) => format!("Scalar({:?})", s),
-                ConstValue::Slice { .. } => format!("Slice(..)"),
-                ConstValue::ByRef { .. } => format!("ByRef(..)"),
+                ConstValue::Slice { .. } => "Slice(..)".to_string(),
+                ConstValue::ByRef { .. } => "ByRef(..)".to_string(),
             };
 
             let fmt_valtree = |valtree: &ty::ValTree<'tcx>| match valtree {
                 ty::ValTree::Leaf(leaf) => format!("ValTree::Leaf({:?})", leaf),
-                ty::ValTree::Branch(_) => format!("ValTree::Branch(..)"),
+                ty::ValTree::Branch(_) => "ValTree::Branch(..)".to_string(),
             };
 
             let val = match literal {
index efd7357afc46c98f1b886a42e3b0b9217137ccce..a8a4532223c2d901a47e1cf1f18cb21a718538e7 100644 (file)
@@ -130,10 +130,9 @@ pub struct UnsafetyCheckResult {
 }
 
 rustc_index::newtype_index! {
-    pub struct GeneratorSavedLocal {
-        derive [HashStable]
-        DEBUG_FORMAT = "_{}",
-    }
+    #[derive(HashStable)]
+    #[debug_format = "_{}"]
+    pub struct GeneratorSavedLocal {}
 }
 
 /// The layout of generator state.
index fa3adafd4b85f385c884f5b5c155234dbfce021a..599f0b9d3fab4de99f30f25ba9fd1bf6774ed3ab 100644 (file)
@@ -32,8 +32,9 @@ pub fn from_ty(ty: Ty<'tcx>) -> PlaceTy<'tcx> {
     /// not carry a `Ty` for `T`.)
     ///
     /// Note that the resulting type has not been normalized.
+    #[instrument(level = "debug", skip(tcx), ret)]
     pub fn field_ty(self, tcx: TyCtxt<'tcx>, f: Field) -> Ty<'tcx> {
-        let answer = match self.ty.kind() {
+        match self.ty.kind() {
             ty::Adt(adt_def, substs) => {
                 let variant_def = match self.variant_index {
                     None => adt_def.non_enum_variant(),
@@ -47,9 +48,7 @@ pub fn field_ty(self, tcx: TyCtxt<'tcx>, f: Field) -> Ty<'tcx> {
             }
             ty::Tuple(tys) => tys[f.index()],
             _ => bug!("extracting field of non-tuple non-adt: {:?}", self),
-        };
-        debug!("field_ty self: {:?} f: {:?} yields: {:?}", self, f, answer);
-        answer
+        }
     }
 
     /// Convenience wrapper around `projection_ty_core` for
@@ -234,7 +233,7 @@ pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx>
     {
         match self {
             &Operand::Copy(ref l) | &Operand::Move(ref l) => l.ty(local_decls, tcx).ty,
-            &Operand::Constant(ref c) => c.literal.ty(),
+            Operand::Constant(c) => c.literal.ty(),
         }
     }
 }
index 880632561b9e8e2ba75ee46aac677f9932f879f2..e4bb3ce3d5a99b32793e8f0a9f1467d5b47f76f7 100644 (file)
 /// The `Key` trait controls what types can legally be used as the key
 /// for a query.
 pub trait Key: Sized {
-    type CacheSelector = DefaultCacheSelector<Self>;
+    // N.B. Most of the keys down below have `type CacheSelector = DefaultCacheSelector<Self>;`,
+    //      it would be reasonable to use associated type defaults, to remove the duplication...
+    //
+    //      ...But r-a doesn't support them yet and using a default here causes r-a to not infer
+    //      return types of queries which is very annoying. Thus, until r-a support associated
+    //      type defaults, plese restrain from using them here <3
+    //
+    //      r-a issue: <https://github.com/rust-lang/rust-analyzer/issues/13693>
+    type CacheSelector;
 
     /// Given an instance of this key, what crate is it referring to?
     /// This is used to find the provider.
@@ -37,6 +45,8 @@ fn ty_adt_id(&self) -> Option<DefId> {
 }
 
 impl Key for () {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         true
@@ -48,6 +58,8 @@ fn default_span(&self, _: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for ty::InstanceDef<'tcx> {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         true
@@ -59,6 +71,8 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for ty::Instance<'tcx> {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         true
@@ -70,6 +84,8 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for mir::interpret::GlobalId<'tcx> {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         true
@@ -81,6 +97,8 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>) {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         true
@@ -92,6 +110,8 @@ fn default_span(&self, _: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for mir::interpret::LitToConstInput<'tcx> {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         true
@@ -145,6 +165,8 @@ fn key_as_def_id(&self) -> Option<DefId> {
 }
 
 impl Key for DefId {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         self.krate == LOCAL_CRATE
@@ -159,6 +181,8 @@ fn key_as_def_id(&self) -> Option<DefId> {
 }
 
 impl Key for ty::WithOptConstParam<LocalDefId> {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         true
@@ -169,6 +193,8 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
 }
 
 impl Key for SimplifiedType {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         true
@@ -179,6 +205,8 @@ fn default_span(&self, _: TyCtxt<'_>) -> Span {
 }
 
 impl Key for (DefId, DefId) {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         self.0.krate == LOCAL_CRATE
@@ -189,6 +217,8 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for (ty::Instance<'tcx>, LocalDefId) {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         true
@@ -199,6 +229,8 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
 }
 
 impl Key for (DefId, LocalDefId) {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         self.0.krate == LOCAL_CRATE
@@ -209,6 +241,8 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
 }
 
 impl Key for (LocalDefId, DefId) {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         true
@@ -219,6 +253,8 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
 }
 
 impl Key for (LocalDefId, LocalDefId) {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         true
@@ -229,6 +265,8 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
 }
 
 impl Key for (DefId, Option<Ident>) {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         self.0.krate == LOCAL_CRATE
@@ -243,6 +281,8 @@ fn key_as_def_id(&self) -> Option<DefId> {
 }
 
 impl Key for (DefId, LocalDefId, Ident) {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         self.0.krate == LOCAL_CRATE
@@ -253,6 +293,8 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
 }
 
 impl Key for (CrateNum, DefId) {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         self.0 == LOCAL_CRATE
@@ -263,6 +305,8 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
 }
 
 impl Key for (CrateNum, SimplifiedType) {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         self.0 == LOCAL_CRATE
@@ -273,6 +317,8 @@ fn default_span(&self, _: TyCtxt<'_>) -> Span {
 }
 
 impl Key for (DefId, SimplifiedType) {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         self.0.krate == LOCAL_CRATE
@@ -283,6 +329,8 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for SubstsRef<'tcx> {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         true
@@ -293,6 +341,8 @@ fn default_span(&self, _: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for (DefId, SubstsRef<'tcx>) {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         self.0.krate == LOCAL_CRATE
@@ -303,6 +353,8 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for (ty::UnevaluatedConst<'tcx>, ty::UnevaluatedConst<'tcx>) {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         (self.0).def.did.krate == LOCAL_CRATE
@@ -313,6 +365,8 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for (LocalDefId, DefId, SubstsRef<'tcx>) {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         true
@@ -323,6 +377,8 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         self.1.def_id().krate == LOCAL_CRATE
@@ -333,6 +389,8 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for (ty::Const<'tcx>, mir::Field) {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         true
@@ -343,6 +401,8 @@ fn default_span(&self, _: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for mir::interpret::ConstAlloc<'tcx> {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         true
@@ -353,6 +413,8 @@ fn default_span(&self, _: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for ty::PolyTraitRef<'tcx> {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         self.def_id().krate == LOCAL_CRATE
@@ -363,6 +425,8 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for ty::PolyExistentialTraitRef<'tcx> {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         self.def_id().krate == LOCAL_CRATE
@@ -373,6 +437,8 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for (ty::PolyTraitRef<'tcx>, ty::PolyTraitRef<'tcx>) {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         self.0.def_id().krate == LOCAL_CRATE
@@ -383,6 +449,8 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for GenericArg<'tcx> {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         true
@@ -393,6 +461,8 @@ fn default_span(&self, _: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for mir::ConstantKind<'tcx> {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         true
@@ -403,6 +473,8 @@ fn default_span(&self, _: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for ty::Const<'tcx> {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         true
@@ -413,6 +485,8 @@ fn default_span(&self, _: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for Ty<'tcx> {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         true
@@ -429,6 +503,8 @@ fn ty_adt_id(&self) -> Option<DefId> {
 }
 
 impl<'tcx> Key for TyAndLayout<'tcx> {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         true
@@ -439,6 +515,8 @@ fn default_span(&self, _: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for (Ty<'tcx>, Ty<'tcx>) {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         true
@@ -449,6 +527,8 @@ fn default_span(&self, _: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for &'tcx ty::List<ty::Predicate<'tcx>> {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         true
@@ -459,6 +539,8 @@ fn default_span(&self, _: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for ty::ParamEnv<'tcx> {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         true
@@ -469,6 +551,8 @@ fn default_span(&self, _: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         self.value.query_crate_is_local()
@@ -479,6 +563,8 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
 }
 
 impl Key for Symbol {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         true
@@ -489,6 +575,8 @@ fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
 }
 
 impl Key for Option<Symbol> {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         true
@@ -501,6 +589,8 @@ fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
 /// Canonical query goals correspond to abstract trait operations that
 /// are not tied to any crate in particular.
 impl<'tcx, T> Key for Canonical<'tcx, T> {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         true
@@ -512,6 +602,8 @@ fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
 }
 
 impl Key for (Symbol, u32, u32) {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         true
@@ -523,6 +615,8 @@ fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for (DefId, Ty<'tcx>, SubstsRef<'tcx>, ty::ParamEnv<'tcx>) {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         true
@@ -534,6 +628,8 @@ fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for (ty::Predicate<'tcx>, traits::WellFormedLoc) {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         true
@@ -545,6 +641,8 @@ fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>) {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         true
@@ -556,6 +654,8 @@ fn default_span(&self, _: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>) {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         true
@@ -567,6 +667,8 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for (Ty<'tcx>, ty::ValTree<'tcx>) {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         true
@@ -578,6 +680,8 @@ fn default_span(&self, _: TyCtxt<'_>) -> Span {
 }
 
 impl Key for HirId {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         true
index 8bef9dfe099b9e2a5838a2a7339395723a2c51c7..ac903010c8d31bba0e158db5016516709d3b5b38 100644 (file)
@@ -35,9 +35,8 @@ macro_rules! thir_with_elements {
         $(
             newtype_index! {
                 #[derive(HashStable)]
-                pub struct $id {
-                    DEBUG_FORMAT = $format
-                }
+                #[debug_format = $format]
+                pub struct $id {}
             }
         )*
 
index 75f2d45eadb81dbdea74246cedd6188b6002b6eb..8cc8286c1dbe67ea25fba051aab058f27ba18d2b 100644 (file)
@@ -310,7 +310,7 @@ fn decode(decoder: &mut D) -> &'tcx Self {
 
 impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Const<'tcx> {
     fn decode(decoder: &mut D) -> Self {
-        let consts: ty::ConstS<'tcx> = Decodable::decode(decoder);
+        let consts: ty::ConstData<'tcx> = Decodable::decode(decoder);
         decoder.interner().mk_const(consts.kind, consts.ty)
     }
 }
index c2be08e497e5bf85bc9174c7a05daf806eb91b51..e5abc38046ced9003709e43ee04b419ba6f1f63a 100644 (file)
 pub use kind::*;
 pub use valtree::*;
 
-/// Use this rather than `ConstS`, whenever possible.
+/// Use this rather than `ConstData, whenever possible.
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)]
 #[rustc_pass_by_value]
-pub struct Const<'tcx>(pub Interned<'tcx, ConstS<'tcx>>);
+pub struct Const<'tcx>(pub(super) Interned<'tcx, ConstData<'tcx>>);
 
 impl<'tcx> fmt::Debug for Const<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -30,13 +30,13 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 
 /// Typed constant value.
 #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, HashStable, TyEncodable, TyDecodable)]
-pub struct ConstS<'tcx> {
+pub struct ConstData<'tcx> {
     pub ty: Ty<'tcx>,
     pub kind: ConstKind<'tcx>,
 }
 
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(ConstS<'_>, 40);
+static_assert_size!(ConstData<'_>, 40);
 
 impl<'tcx> Const<'tcx> {
     #[inline]
index 70ac5acb40eadd03751730e161d4f35a0e0cb508..8f4d56c65b98575a3161cd4ef73f01f56e6c4585 100644 (file)
@@ -4,8 +4,7 @@
 
 use crate::arena::Arena;
 use crate::dep_graph::{DepGraph, DepKindStruct};
-use crate::hir::place::Place as HirPlace;
-use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
+use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
 use crate::lint::struct_lint_level;
 use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
 use crate::middle::resolve_lifetime;
 use crate::traits;
 use crate::ty::query::{self, TyCtxtAt};
 use crate::ty::{
-    self, AdtDef, AdtDefData, AdtKind, Binder, BindingMode, BoundVar, CanonicalPolyFnSig,
-    ClosureSizeProfileData, Const, ConstS, DefIdTree, FloatTy, FloatVar, FloatVid,
-    GenericParamDefKind, InferTy, IntTy, IntVar, IntVid, List, ParamConst, ParamTy,
-    PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, Region, RegionKind, ReprOptions,
-    TraitObjectVisitor, Ty, TyKind, TyVar, TyVid, TypeAndMut, UintTy, Visibility,
+    self, AdtDef, AdtDefData, AdtKind, Binder, Const, ConstData, DefIdTree, FloatTy, FloatVar,
+    FloatVid, GenericParamDefKind, ImplPolarity, InferTy, IntTy, IntVar, IntVid, List, ParamConst,
+    ParamTy, PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, Region, RegionKind,
+    ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVar, TyVid, TypeAndMut, TypeckResults, UintTy,
+    Visibility,
 };
-use crate::ty::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef, UserSubsts};
+use crate::ty::{GenericArg, InternalSubsts, SubstsRef};
 use rustc_ast as ast;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::steal::Steal;
 use rustc_data_structures::sync::{self, Lock, Lrc, ReadGuard, WorkerLocal};
-use rustc_data_structures::unord::UnordSet;
-use rustc_data_structures::vec_map::VecMap;
 use rustc_errors::{
     DecorateLint, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, MultiSpan,
 };
 use rustc_hir as hir;
-use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap, LOCAL_CRATE};
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
 use rustc_hir::definitions::Definitions;
-use rustc_hir::hir_id::OwnerId;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{
-    Constness, ExprKind, HirId, ImplItemKind, ItemKind, ItemLocalId, ItemLocalMap, ItemLocalSet,
-    Node, TraitCandidate, TraitItemKind,
+    Constness, ExprKind, HirId, ImplItemKind, ItemKind, Node, TraitCandidate, TraitItemKind,
 };
-use rustc_index::vec::{Idx, IndexVec};
+use rustc_index::vec::IndexVec;
 use rustc_macros::HashStable;
-use rustc_middle::mir::FakeReadCause;
 use rustc_query_system::dep_graph::DepNodeIndex;
 use rustc_query_system::ich::StableHashingContext;
 use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
@@ -75,7 +69,6 @@
 use std::any::Any;
 use std::borrow::Borrow;
 use std::cmp::Ordering;
-use std::collections::hash_map::{self, Entry};
 use std::fmt;
 use std::hash::{Hash, Hasher};
 use std::iter;
@@ -83,8 +76,6 @@
 use std::ops::{Bound, Deref};
 use std::sync::Arc;
 
-use super::{ImplPolarity, RvalueScopes};
-
 pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync {
     /// Creates a new `OnDiskCache` instance from the serialized data in `data`.
     fn new(sess: &'tcx Session, data: Mmap, start_pos: usize) -> Self
@@ -149,7 +140,7 @@ pub struct CtxtInterners<'tcx> {
     predicates: InternedSet<'tcx, List<Predicate<'tcx>>>,
     projs: InternedSet<'tcx, List<ProjectionKind>>,
     place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>,
-    const_: InternedSet<'tcx, ConstS<'tcx>>,
+    const_: InternedSet<'tcx, ConstData<'tcx>>,
     const_allocation: InternedSet<'tcx, Allocation>,
     bound_variable_kinds: InternedSet<'tcx, List<ty::BoundVariableKind>>,
     layout: InternedSet<'tcx, LayoutS<VariantIdx>>,
@@ -284,666 +275,6 @@ pub struct CommonConsts<'tcx> {
     pub unit: Const<'tcx>,
 }
 
-pub struct LocalTableInContext<'a, V> {
-    hir_owner: OwnerId,
-    data: &'a ItemLocalMap<V>,
-}
-
-/// Validate that the given HirId (respectively its `local_id` part) can be
-/// safely used as a key in the maps of a TypeckResults. For that to be
-/// the case, the HirId must have the same `owner` as all the other IDs in
-/// this table (signified by `hir_owner`). Otherwise the HirId
-/// would be in a different frame of reference and using its `local_id`
-/// would result in lookup errors, or worse, in silently wrong data being
-/// stored/returned.
-#[inline]
-fn validate_hir_id_for_typeck_results(hir_owner: OwnerId, hir_id: hir::HirId) {
-    if hir_id.owner != hir_owner {
-        invalid_hir_id_for_typeck_results(hir_owner, hir_id);
-    }
-}
-
-#[cold]
-#[inline(never)]
-fn invalid_hir_id_for_typeck_results(hir_owner: OwnerId, hir_id: hir::HirId) {
-    ty::tls::with(|tcx| {
-        bug!(
-            "node {} with HirId::owner {:?} cannot be placed in TypeckResults with hir_owner {:?}",
-            tcx.hir().node_to_string(hir_id),
-            hir_id.owner,
-            hir_owner
-        )
-    });
-}
-
-impl<'a, V> LocalTableInContext<'a, V> {
-    pub fn contains_key(&self, id: hir::HirId) -> bool {
-        validate_hir_id_for_typeck_results(self.hir_owner, id);
-        self.data.contains_key(&id.local_id)
-    }
-
-    pub fn get(&self, id: hir::HirId) -> Option<&V> {
-        validate_hir_id_for_typeck_results(self.hir_owner, id);
-        self.data.get(&id.local_id)
-    }
-
-    pub fn iter(&self) -> hash_map::Iter<'_, hir::ItemLocalId, V> {
-        self.data.iter()
-    }
-}
-
-impl<'a, V> ::std::ops::Index<hir::HirId> for LocalTableInContext<'a, V> {
-    type Output = V;
-
-    fn index(&self, key: hir::HirId) -> &V {
-        self.get(key).expect("LocalTableInContext: key not found")
-    }
-}
-
-pub struct LocalTableInContextMut<'a, V> {
-    hir_owner: OwnerId,
-    data: &'a mut ItemLocalMap<V>,
-}
-
-impl<'a, V> LocalTableInContextMut<'a, V> {
-    pub fn get_mut(&mut self, id: hir::HirId) -> Option<&mut V> {
-        validate_hir_id_for_typeck_results(self.hir_owner, id);
-        self.data.get_mut(&id.local_id)
-    }
-
-    pub fn entry(&mut self, id: hir::HirId) -> Entry<'_, hir::ItemLocalId, V> {
-        validate_hir_id_for_typeck_results(self.hir_owner, id);
-        self.data.entry(id.local_id)
-    }
-
-    pub fn insert(&mut self, id: hir::HirId, val: V) -> Option<V> {
-        validate_hir_id_for_typeck_results(self.hir_owner, id);
-        self.data.insert(id.local_id, val)
-    }
-
-    pub fn remove(&mut self, id: hir::HirId) -> Option<V> {
-        validate_hir_id_for_typeck_results(self.hir_owner, id);
-        self.data.remove(&id.local_id)
-    }
-}
-
-/// Whenever a value may be live across a generator yield, the type of that value winds up in the
-/// `GeneratorInteriorTypeCause` struct. This struct adds additional information about such
-/// captured types that can be useful for diagnostics. In particular, it stores the span that
-/// caused a given type to be recorded, along with the scope that enclosed the value (which can
-/// be used to find the await that the value is live across).
-///
-/// For example:
-///
-/// ```ignore (pseudo-Rust)
-/// async move {
-///     let x: T = expr;
-///     foo.await
-///     ...
-/// }
-/// ```
-///
-/// Here, we would store the type `T`, the span of the value `x`, the "scope-span" for
-/// the scope that contains `x`, the expr `T` evaluated from, and the span of `foo.await`.
-#[derive(TyEncodable, TyDecodable, Clone, Debug, Eq, Hash, PartialEq, HashStable)]
-#[derive(TypeFoldable, TypeVisitable)]
-pub struct GeneratorInteriorTypeCause<'tcx> {
-    /// Type of the captured binding.
-    pub ty: Ty<'tcx>,
-    /// Span of the binding that was captured.
-    pub span: Span,
-    /// Span of the scope of the captured binding.
-    pub scope_span: Option<Span>,
-    /// Span of `.await` or `yield` expression.
-    pub yield_span: Span,
-    /// Expr which the type evaluated from.
-    pub expr: Option<hir::HirId>,
-}
-
-// This type holds diagnostic information on generators and async functions across crate boundaries
-// and is used to provide better error messages
-#[derive(TyEncodable, TyDecodable, Clone, Debug, HashStable)]
-pub struct GeneratorDiagnosticData<'tcx> {
-    pub generator_interior_types: ty::Binder<'tcx, Vec<GeneratorInteriorTypeCause<'tcx>>>,
-    pub hir_owner: DefId,
-    pub nodes_types: ItemLocalMap<Ty<'tcx>>,
-    pub adjustments: ItemLocalMap<Vec<ty::adjustment::Adjustment<'tcx>>>,
-}
-
-#[derive(TyEncodable, TyDecodable, Debug, HashStable)]
-pub struct TypeckResults<'tcx> {
-    /// The `HirId::owner` all `ItemLocalId`s in this table are relative to.
-    pub hir_owner: OwnerId,
-
-    /// Resolved definitions for `<T>::X` associated paths and
-    /// method calls, including those of overloaded operators.
-    type_dependent_defs: ItemLocalMap<Result<(DefKind, DefId), ErrorGuaranteed>>,
-
-    /// Resolved field indices for field accesses in expressions (`S { field }`, `obj.field`)
-    /// or patterns (`S { field }`). The index is often useful by itself, but to learn more
-    /// about the field you also need definition of the variant to which the field
-    /// belongs, but it may not exist if it's a tuple field (`tuple.0`).
-    field_indices: ItemLocalMap<usize>,
-
-    /// Stores the types for various nodes in the AST. Note that this table
-    /// is not guaranteed to be populated outside inference. See
-    /// typeck::check::fn_ctxt for details.
-    node_types: ItemLocalMap<Ty<'tcx>>,
-
-    /// Stores the type parameters which were substituted to obtain the type
-    /// of this node. This only applies to nodes that refer to entities
-    /// parameterized by type parameters, such as generic fns, types, or
-    /// other items.
-    node_substs: ItemLocalMap<SubstsRef<'tcx>>,
-
-    /// This will either store the canonicalized types provided by the user
-    /// or the substitutions that the user explicitly gave (if any) attached
-    /// to `id`. These will not include any inferred values. The canonical form
-    /// is used to capture things like `_` or other unspecified values.
-    ///
-    /// For example, if the user wrote `foo.collect::<Vec<_>>()`, then the
-    /// canonical substitutions would include only `for<X> { Vec<X> }`.
-    ///
-    /// See also `AscribeUserType` statement in MIR.
-    user_provided_types: ItemLocalMap<CanonicalUserType<'tcx>>,
-
-    /// Stores the canonicalized types provided by the user. See also
-    /// `AscribeUserType` statement in MIR.
-    pub user_provided_sigs: LocalDefIdMap<CanonicalPolyFnSig<'tcx>>,
-
-    adjustments: ItemLocalMap<Vec<ty::adjustment::Adjustment<'tcx>>>,
-
-    /// Stores the actual binding mode for all instances of hir::BindingAnnotation.
-    pat_binding_modes: ItemLocalMap<BindingMode>,
-
-    /// Stores the types which were implicitly dereferenced in pattern binding modes
-    /// for later usage in THIR lowering. For example,
-    ///
-    /// ```
-    /// match &&Some(5i32) {
-    ///     Some(n) => {},
-    ///     _ => {},
-    /// }
-    /// ```
-    /// leads to a `vec![&&Option<i32>, &Option<i32>]`. Empty vectors are not stored.
-    ///
-    /// See:
-    /// <https://github.com/rust-lang/rfcs/blob/master/text/2005-match-ergonomics.md#definitions>
-    pat_adjustments: ItemLocalMap<Vec<Ty<'tcx>>>,
-
-    /// Records the reasons that we picked the kind of each closure;
-    /// not all closures are present in the map.
-    closure_kind_origins: ItemLocalMap<(Span, HirPlace<'tcx>)>,
-
-    /// For each fn, records the "liberated" types of its arguments
-    /// and return type. Liberated means that all bound regions
-    /// (including late-bound regions) are replaced with free
-    /// equivalents. This table is not used in codegen (since regions
-    /// are erased there) and hence is not serialized to metadata.
-    ///
-    /// This table also contains the "revealed" values for any `impl Trait`
-    /// that appear in the signature and whose values are being inferred
-    /// by this function.
-    ///
-    /// # Example
-    ///
-    /// ```rust
-    /// # use std::fmt::Debug;
-    /// fn foo(x: &u32) -> impl Debug { *x }
-    /// ```
-    ///
-    /// The function signature here would be:
-    ///
-    /// ```ignore (illustrative)
-    /// for<'a> fn(&'a u32) -> Foo
-    /// ```
-    ///
-    /// where `Foo` is an opaque type created for this function.
-    ///
-    ///
-    /// The *liberated* form of this would be
-    ///
-    /// ```ignore (illustrative)
-    /// fn(&'a u32) -> u32
-    /// ```
-    ///
-    /// Note that `'a` is not bound (it would be an `ReFree`) and
-    /// that the `Foo` opaque type is replaced by its hidden type.
-    liberated_fn_sigs: ItemLocalMap<ty::FnSig<'tcx>>,
-
-    /// For each FRU expression, record the normalized types of the fields
-    /// of the struct - this is needed because it is non-trivial to
-    /// normalize while preserving regions. This table is used only in
-    /// MIR construction and hence is not serialized to metadata.
-    fru_field_types: ItemLocalMap<Vec<Ty<'tcx>>>,
-
-    /// For every coercion cast we add the HIR node ID of the cast
-    /// expression to this set.
-    coercion_casts: ItemLocalSet,
-
-    /// Set of trait imports actually used in the method resolution.
-    /// This is used for warning unused imports. During type
-    /// checking, this `Lrc` should not be cloned: it must have a ref-count
-    /// of 1 so that we can insert things into the set mutably.
-    pub used_trait_imports: Lrc<UnordSet<LocalDefId>>,
-
-    /// If any errors occurred while type-checking this body,
-    /// this field will be set to `Some(ErrorGuaranteed)`.
-    pub tainted_by_errors: Option<ErrorGuaranteed>,
-
-    /// All the opaque types that have hidden types set
-    /// by this function. We also store the
-    /// type here, so that mir-borrowck can use it as a hint for figuring out hidden types,
-    /// even if they are only set in dead code (which doesn't show up in MIR).
-    pub concrete_opaque_types: VecMap<LocalDefId, ty::OpaqueHiddenType<'tcx>>,
-
-    /// Tracks the minimum captures required for a closure;
-    /// see `MinCaptureInformationMap` for more details.
-    pub closure_min_captures: ty::MinCaptureInformationMap<'tcx>,
-
-    /// Tracks the fake reads required for a closure and the reason for the fake read.
-    /// When performing pattern matching for closures, there are times we don't end up
-    /// reading places that are mentioned in a closure (because of _ patterns). However,
-    /// to ensure the places are initialized, we introduce fake reads.
-    /// Consider these two examples:
-    /// ``` (discriminant matching with only wildcard arm)
-    /// let x: u8;
-    /// let c = || match x { _ => () };
-    /// ```
-    /// In this example, we don't need to actually read/borrow `x` in `c`, and so we don't
-    /// want to capture it. However, we do still want an error here, because `x` should have
-    /// to be initialized at the point where c is created. Therefore, we add a "fake read"
-    /// instead.
-    /// ``` (destructured assignments)
-    /// let c = || {
-    ///     let (t1, t2) = t;
-    /// }
-    /// ```
-    /// In the second example, we capture the disjoint fields of `t` (`t.0` & `t.1`), but
-    /// we never capture `t`. This becomes an issue when we build MIR as we require
-    /// information on `t` in order to create place `t.0` and `t.1`. We can solve this
-    /// issue by fake reading `t`.
-    pub closure_fake_reads: FxHashMap<LocalDefId, Vec<(HirPlace<'tcx>, FakeReadCause, hir::HirId)>>,
-
-    /// Tracks the rvalue scoping rules which defines finer scoping for rvalue expressions
-    /// by applying extended parameter rules.
-    /// Details may be find in `rustc_hir_analysis::check::rvalue_scopes`.
-    pub rvalue_scopes: RvalueScopes,
-
-    /// Stores the type, expression, span and optional scope span of all types
-    /// that are live across the yield of this generator (if a generator).
-    pub generator_interior_types: ty::Binder<'tcx, Vec<GeneratorInteriorTypeCause<'tcx>>>,
-
-    /// We sometimes treat byte string literals (which are of type `&[u8; N]`)
-    /// as `&[u8]`, depending on the pattern  in which they are used.
-    /// This hashset records all instances where we behave
-    /// like this to allow `const_to_pat` to reliably handle this situation.
-    pub treat_byte_string_as_slice: ItemLocalSet,
-
-    /// Contains the data for evaluating the effect of feature `capture_disjoint_fields`
-    /// on closure size.
-    pub closure_size_eval: FxHashMap<LocalDefId, ClosureSizeProfileData<'tcx>>,
-}
-
-impl<'tcx> TypeckResults<'tcx> {
-    pub fn new(hir_owner: OwnerId) -> TypeckResults<'tcx> {
-        TypeckResults {
-            hir_owner,
-            type_dependent_defs: Default::default(),
-            field_indices: Default::default(),
-            user_provided_types: Default::default(),
-            user_provided_sigs: Default::default(),
-            node_types: Default::default(),
-            node_substs: Default::default(),
-            adjustments: Default::default(),
-            pat_binding_modes: Default::default(),
-            pat_adjustments: Default::default(),
-            closure_kind_origins: Default::default(),
-            liberated_fn_sigs: Default::default(),
-            fru_field_types: Default::default(),
-            coercion_casts: Default::default(),
-            used_trait_imports: Lrc::new(Default::default()),
-            tainted_by_errors: None,
-            concrete_opaque_types: Default::default(),
-            closure_min_captures: Default::default(),
-            closure_fake_reads: Default::default(),
-            rvalue_scopes: Default::default(),
-            generator_interior_types: ty::Binder::dummy(Default::default()),
-            treat_byte_string_as_slice: Default::default(),
-            closure_size_eval: Default::default(),
-        }
-    }
-
-    /// Returns the final resolution of a `QPath` in an `Expr` or `Pat` node.
-    pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res {
-        match *qpath {
-            hir::QPath::Resolved(_, ref path) => path.res,
-            hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self
-                .type_dependent_def(id)
-                .map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)),
-        }
-    }
-
-    pub fn type_dependent_defs(
-        &self,
-    ) -> LocalTableInContext<'_, Result<(DefKind, DefId), ErrorGuaranteed>> {
-        LocalTableInContext { hir_owner: self.hir_owner, data: &self.type_dependent_defs }
-    }
-
-    pub fn type_dependent_def(&self, id: HirId) -> Option<(DefKind, DefId)> {
-        validate_hir_id_for_typeck_results(self.hir_owner, id);
-        self.type_dependent_defs.get(&id.local_id).cloned().and_then(|r| r.ok())
-    }
-
-    pub fn type_dependent_def_id(&self, id: HirId) -> Option<DefId> {
-        self.type_dependent_def(id).map(|(_, def_id)| def_id)
-    }
-
-    pub fn type_dependent_defs_mut(
-        &mut self,
-    ) -> LocalTableInContextMut<'_, Result<(DefKind, DefId), ErrorGuaranteed>> {
-        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.type_dependent_defs }
-    }
-
-    pub fn field_indices(&self) -> LocalTableInContext<'_, usize> {
-        LocalTableInContext { hir_owner: self.hir_owner, data: &self.field_indices }
-    }
-
-    pub fn field_indices_mut(&mut self) -> LocalTableInContextMut<'_, usize> {
-        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.field_indices }
-    }
-
-    pub fn field_index(&self, id: hir::HirId) -> usize {
-        self.field_indices().get(id).cloned().expect("no index for a field")
-    }
-
-    pub fn opt_field_index(&self, id: hir::HirId) -> Option<usize> {
-        self.field_indices().get(id).cloned()
-    }
-
-    pub fn user_provided_types(&self) -> LocalTableInContext<'_, CanonicalUserType<'tcx>> {
-        LocalTableInContext { hir_owner: self.hir_owner, data: &self.user_provided_types }
-    }
-
-    pub fn user_provided_types_mut(
-        &mut self,
-    ) -> LocalTableInContextMut<'_, CanonicalUserType<'tcx>> {
-        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.user_provided_types }
-    }
-
-    pub fn node_types(&self) -> LocalTableInContext<'_, Ty<'tcx>> {
-        LocalTableInContext { hir_owner: self.hir_owner, data: &self.node_types }
-    }
-
-    pub fn node_types_mut(&mut self) -> LocalTableInContextMut<'_, Ty<'tcx>> {
-        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.node_types }
-    }
-
-    pub fn get_generator_diagnostic_data(&self) -> GeneratorDiagnosticData<'tcx> {
-        let generator_interior_type = self.generator_interior_types.map_bound_ref(|vec| {
-            vec.iter()
-                .map(|item| {
-                    GeneratorInteriorTypeCause {
-                        ty: item.ty,
-                        span: item.span,
-                        scope_span: item.scope_span,
-                        yield_span: item.yield_span,
-                        expr: None, //FIXME: Passing expression over crate boundaries is impossible at the moment
-                    }
-                })
-                .collect::<Vec<_>>()
-        });
-        GeneratorDiagnosticData {
-            generator_interior_types: generator_interior_type,
-            hir_owner: self.hir_owner.to_def_id(),
-            nodes_types: self.node_types.clone(),
-            adjustments: self.adjustments.clone(),
-        }
-    }
-
-    pub fn node_type(&self, id: hir::HirId) -> Ty<'tcx> {
-        self.node_type_opt(id).unwrap_or_else(|| {
-            bug!("node_type: no type for node `{}`", tls::with(|tcx| tcx.hir().node_to_string(id)))
-        })
-    }
-
-    pub fn node_type_opt(&self, id: hir::HirId) -> Option<Ty<'tcx>> {
-        validate_hir_id_for_typeck_results(self.hir_owner, id);
-        self.node_types.get(&id.local_id).cloned()
-    }
-
-    pub fn node_substs_mut(&mut self) -> LocalTableInContextMut<'_, SubstsRef<'tcx>> {
-        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.node_substs }
-    }
-
-    pub fn node_substs(&self, id: hir::HirId) -> SubstsRef<'tcx> {
-        validate_hir_id_for_typeck_results(self.hir_owner, id);
-        self.node_substs.get(&id.local_id).cloned().unwrap_or_else(|| InternalSubsts::empty())
-    }
-
-    pub fn node_substs_opt(&self, id: hir::HirId) -> Option<SubstsRef<'tcx>> {
-        validate_hir_id_for_typeck_results(self.hir_owner, id);
-        self.node_substs.get(&id.local_id).cloned()
-    }
-
-    /// Returns the type of a pattern as a monotype. Like [`expr_ty`], this function
-    /// doesn't provide type parameter substitutions.
-    ///
-    /// [`expr_ty`]: TypeckResults::expr_ty
-    pub fn pat_ty(&self, pat: &hir::Pat<'_>) -> Ty<'tcx> {
-        self.node_type(pat.hir_id)
-    }
-
-    /// Returns the type of an expression as a monotype.
-    ///
-    /// NB (1): This is the PRE-ADJUSTMENT TYPE for the expression.  That is, in
-    /// some cases, we insert `Adjustment` annotations such as auto-deref or
-    /// auto-ref.  The type returned by this function does not consider such
-    /// adjustments.  See `expr_ty_adjusted()` instead.
-    ///
-    /// NB (2): This type doesn't provide type parameter substitutions; e.g., if you
-    /// ask for the type of `id` in `id(3)`, it will return `fn(&isize) -> isize`
-    /// instead of `fn(ty) -> T with T = isize`.
-    pub fn expr_ty(&self, expr: &hir::Expr<'_>) -> Ty<'tcx> {
-        self.node_type(expr.hir_id)
-    }
-
-    pub fn expr_ty_opt(&self, expr: &hir::Expr<'_>) -> Option<Ty<'tcx>> {
-        self.node_type_opt(expr.hir_id)
-    }
-
-    pub fn adjustments(&self) -> LocalTableInContext<'_, Vec<ty::adjustment::Adjustment<'tcx>>> {
-        LocalTableInContext { hir_owner: self.hir_owner, data: &self.adjustments }
-    }
-
-    pub fn adjustments_mut(
-        &mut self,
-    ) -> LocalTableInContextMut<'_, Vec<ty::adjustment::Adjustment<'tcx>>> {
-        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.adjustments }
-    }
-
-    pub fn expr_adjustments(&self, expr: &hir::Expr<'_>) -> &[ty::adjustment::Adjustment<'tcx>] {
-        validate_hir_id_for_typeck_results(self.hir_owner, expr.hir_id);
-        self.adjustments.get(&expr.hir_id.local_id).map_or(&[], |a| &a[..])
-    }
-
-    /// Returns the type of `expr`, considering any `Adjustment`
-    /// entry recorded for that expression.
-    pub fn expr_ty_adjusted(&self, expr: &hir::Expr<'_>) -> Ty<'tcx> {
-        self.expr_adjustments(expr).last().map_or_else(|| self.expr_ty(expr), |adj| adj.target)
-    }
-
-    pub fn expr_ty_adjusted_opt(&self, expr: &hir::Expr<'_>) -> Option<Ty<'tcx>> {
-        self.expr_adjustments(expr).last().map(|adj| adj.target).or_else(|| self.expr_ty_opt(expr))
-    }
-
-    pub fn is_method_call(&self, expr: &hir::Expr<'_>) -> bool {
-        // Only paths and method calls/overloaded operators have
-        // entries in type_dependent_defs, ignore the former here.
-        if let hir::ExprKind::Path(_) = expr.kind {
-            return false;
-        }
-
-        matches!(self.type_dependent_defs().get(expr.hir_id), Some(Ok((DefKind::AssocFn, _))))
-    }
-
-    pub fn extract_binding_mode(&self, s: &Session, id: HirId, sp: Span) -> Option<BindingMode> {
-        self.pat_binding_modes().get(id).copied().or_else(|| {
-            s.delay_span_bug(sp, "missing binding mode");
-            None
-        })
-    }
-
-    pub fn pat_binding_modes(&self) -> LocalTableInContext<'_, BindingMode> {
-        LocalTableInContext { hir_owner: self.hir_owner, data: &self.pat_binding_modes }
-    }
-
-    pub fn pat_binding_modes_mut(&mut self) -> LocalTableInContextMut<'_, BindingMode> {
-        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_binding_modes }
-    }
-
-    pub fn pat_adjustments(&self) -> LocalTableInContext<'_, Vec<Ty<'tcx>>> {
-        LocalTableInContext { hir_owner: self.hir_owner, data: &self.pat_adjustments }
-    }
-
-    pub fn pat_adjustments_mut(&mut self) -> LocalTableInContextMut<'_, Vec<Ty<'tcx>>> {
-        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments }
-    }
-
-    /// For a given closure, returns the iterator of `ty::CapturedPlace`s that are captured
-    /// by the closure.
-    pub fn closure_min_captures_flattened(
-        &self,
-        closure_def_id: LocalDefId,
-    ) -> impl Iterator<Item = &ty::CapturedPlace<'tcx>> {
-        self.closure_min_captures
-            .get(&closure_def_id)
-            .map(|closure_min_captures| closure_min_captures.values().flat_map(|v| v.iter()))
-            .into_iter()
-            .flatten()
-    }
-
-    pub fn closure_kind_origins(&self) -> LocalTableInContext<'_, (Span, HirPlace<'tcx>)> {
-        LocalTableInContext { hir_owner: self.hir_owner, data: &self.closure_kind_origins }
-    }
-
-    pub fn closure_kind_origins_mut(
-        &mut self,
-    ) -> LocalTableInContextMut<'_, (Span, HirPlace<'tcx>)> {
-        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.closure_kind_origins }
-    }
-
-    pub fn liberated_fn_sigs(&self) -> LocalTableInContext<'_, ty::FnSig<'tcx>> {
-        LocalTableInContext { hir_owner: self.hir_owner, data: &self.liberated_fn_sigs }
-    }
-
-    pub fn liberated_fn_sigs_mut(&mut self) -> LocalTableInContextMut<'_, ty::FnSig<'tcx>> {
-        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.liberated_fn_sigs }
-    }
-
-    pub fn fru_field_types(&self) -> LocalTableInContext<'_, Vec<Ty<'tcx>>> {
-        LocalTableInContext { hir_owner: self.hir_owner, data: &self.fru_field_types }
-    }
-
-    pub fn fru_field_types_mut(&mut self) -> LocalTableInContextMut<'_, Vec<Ty<'tcx>>> {
-        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.fru_field_types }
-    }
-
-    pub fn is_coercion_cast(&self, hir_id: hir::HirId) -> bool {
-        validate_hir_id_for_typeck_results(self.hir_owner, hir_id);
-        self.coercion_casts.contains(&hir_id.local_id)
-    }
-
-    pub fn set_coercion_cast(&mut self, id: ItemLocalId) {
-        self.coercion_casts.insert(id);
-    }
-
-    pub fn coercion_casts(&self) -> &ItemLocalSet {
-        &self.coercion_casts
-    }
-}
-
-rustc_index::newtype_index! {
-    pub struct UserTypeAnnotationIndex {
-        derive [HashStable]
-        DEBUG_FORMAT = "UserType({})",
-        const START_INDEX = 0,
-    }
-}
-
-/// Mapping of type annotation indices to canonical user type annotations.
-pub type CanonicalUserTypeAnnotations<'tcx> =
-    IndexVec<UserTypeAnnotationIndex, CanonicalUserTypeAnnotation<'tcx>>;
-
-#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)]
-pub struct CanonicalUserTypeAnnotation<'tcx> {
-    pub user_ty: Box<CanonicalUserType<'tcx>>,
-    pub span: Span,
-    pub inferred_ty: Ty<'tcx>,
-}
-
-/// Canonicalized user type annotation.
-pub type CanonicalUserType<'tcx> = Canonical<'tcx, UserType<'tcx>>;
-
-impl<'tcx> CanonicalUserType<'tcx> {
-    /// Returns `true` if this represents a substitution of the form `[?0, ?1, ?2]`,
-    /// i.e., each thing is mapped to a canonical variable with the same index.
-    pub fn is_identity(&self) -> bool {
-        match self.value {
-            UserType::Ty(_) => false,
-            UserType::TypeOf(_, user_substs) => {
-                if user_substs.user_self_ty.is_some() {
-                    return false;
-                }
-
-                iter::zip(user_substs.substs, BoundVar::new(0)..).all(|(kind, cvar)| {
-                    match kind.unpack() {
-                        GenericArgKind::Type(ty) => match ty.kind() {
-                            ty::Bound(debruijn, b) => {
-                                // We only allow a `ty::INNERMOST` index in substitutions.
-                                assert_eq!(*debruijn, ty::INNERMOST);
-                                cvar == b.var
-                            }
-                            _ => false,
-                        },
-
-                        GenericArgKind::Lifetime(r) => match *r {
-                            ty::ReLateBound(debruijn, br) => {
-                                // We only allow a `ty::INNERMOST` index in substitutions.
-                                assert_eq!(debruijn, ty::INNERMOST);
-                                cvar == br.var
-                            }
-                            _ => false,
-                        },
-
-                        GenericArgKind::Const(ct) => match ct.kind() {
-                            ty::ConstKind::Bound(debruijn, b) => {
-                                // We only allow a `ty::INNERMOST` index in substitutions.
-                                assert_eq!(debruijn, ty::INNERMOST);
-                                cvar == b
-                            }
-                            _ => false,
-                        },
-                    }
-                })
-            }
-        }
-    }
-}
-
-/// A user-given type annotation attached to a constant. These arise
-/// from constants that are named via paths, like `Foo::<A>::new` and
-/// so forth.
-#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
-pub enum UserType<'tcx> {
-    Ty(Ty<'tcx>),
-
-    /// The canonical type is the result of `type_of(def_id)` with the
-    /// given substitutions applied.
-    TypeOf(DefId, UserSubsts<'tcx>),
-}
-
 impl<'tcx> CommonTypes<'tcx> {
     fn new(
         interners: &CtxtInterners<'tcx>,
@@ -1000,7 +331,7 @@ fn new(interners: &CtxtInterners<'tcx>, types: &CommonTypes<'tcx>) -> CommonCons
         };
 
         CommonConsts {
-            unit: mk_const(ty::ConstS {
+            unit: mk_const(ty::ConstData {
                 kind: ty::ConstKind::Value(ty::ValTree::zst()),
                 ty: types.unit,
             }),
@@ -2270,7 +1601,7 @@ pub fn $method(self, v: $ty) -> $ret_ty {
 
 direct_interners! {
     region: mk_region(RegionKind<'tcx>): Region -> Region<'tcx>,
-    const_: mk_const_internal(ConstS<'tcx>): Const -> Const<'tcx>,
+    const_: mk_const_internal(ConstData<'tcx>): Const -> Const<'tcx>,
     const_allocation: intern_const_alloc(Allocation): ConstAllocation -> ConstAllocation<'tcx>,
     layout: intern_layout(LayoutS<VariantIdx>): Layout -> Layout<'tcx>,
     adt_def: intern_adt_def(AdtDefData): AdtDef -> AdtDef<'tcx>,
@@ -2645,7 +1976,7 @@ pub fn mk_ty_var(self, v: TyVid) -> Ty<'tcx> {
 
     #[inline]
     pub fn mk_const(self, kind: impl Into<ty::ConstKind<'tcx>>, ty: Ty<'tcx>) -> Const<'tcx> {
-        self.mk_const_internal(ty::ConstS { kind: kind.into(), ty })
+        self.mk_const_internal(ty::ConstData { kind: kind.into(), ty })
     }
 
     #[inline]
index 44650827810abf11095901cb7907f433098996b6..f785fb5c4b9be5b5c57f78104e7895b029bcbabf 100644 (file)
@@ -6,28 +6,18 @@
 use std::hash::Hash;
 use std::iter;
 
-use self::SimplifiedTypeGen::*;
+use self::SimplifiedType::*;
 
-pub type SimplifiedType = SimplifiedTypeGen<DefId>;
-
-/// See `simplify_type`
-///
-/// Note that we keep this type generic over the type of identifier it uses
-/// because we sometimes need to use SimplifiedTypeGen values as stable sorting
-/// keys (in which case we use a DefPathHash as id-type) but in the general case
-/// the non-stable but fast to construct DefId-version is the better choice.
+/// See `simplify_type`.
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
-pub enum SimplifiedTypeGen<D>
-where
-    D: Copy + Debug + Eq,
-{
+pub enum SimplifiedType {
     BoolSimplifiedType,
     CharSimplifiedType,
     IntSimplifiedType(ty::IntTy),
     UintSimplifiedType(ty::UintTy),
     FloatSimplifiedType(ty::FloatTy),
-    AdtSimplifiedType(D),
-    ForeignSimplifiedType(D),
+    AdtSimplifiedType(DefId),
+    ForeignSimplifiedType(DefId),
     StrSimplifiedType,
     ArraySimplifiedType,
     SliceSimplifiedType,
@@ -38,9 +28,9 @@ pub enum SimplifiedTypeGen<D>
     /// A trait object, all of whose components are markers
     /// (e.g., `dyn Send + Sync`).
     MarkerTraitObjectSimplifiedType,
-    TraitSimplifiedType(D),
-    ClosureSimplifiedType(D),
-    GeneratorSimplifiedType(D),
+    TraitSimplifiedType(DefId),
+    ClosureSimplifiedType(DefId),
+    GeneratorSimplifiedType(DefId),
     GeneratorWitnessSimplifiedType(usize),
     FunctionSimplifiedType(usize),
     PlaceholderSimplifiedType,
@@ -142,8 +132,8 @@ pub fn simplify_type<'tcx>(
     }
 }
 
-impl<D: Copy + Debug + Eq> SimplifiedTypeGen<D> {
-    pub fn def(self) -> Option<D> {
+impl SimplifiedType {
+    pub fn def(self) -> Option<DefId> {
         match self {
             AdtSimplifiedType(d)
             | ForeignSimplifiedType(d)
@@ -153,36 +143,6 @@ pub fn def(self) -> Option<D> {
             _ => None,
         }
     }
-
-    pub fn map_def<U, F>(self, map: F) -> SimplifiedTypeGen<U>
-    where
-        F: Fn(D) -> U,
-        U: Copy + Debug + Eq,
-    {
-        match self {
-            BoolSimplifiedType => BoolSimplifiedType,
-            CharSimplifiedType => CharSimplifiedType,
-            IntSimplifiedType(t) => IntSimplifiedType(t),
-            UintSimplifiedType(t) => UintSimplifiedType(t),
-            FloatSimplifiedType(t) => FloatSimplifiedType(t),
-            AdtSimplifiedType(d) => AdtSimplifiedType(map(d)),
-            ForeignSimplifiedType(d) => ForeignSimplifiedType(map(d)),
-            StrSimplifiedType => StrSimplifiedType,
-            ArraySimplifiedType => ArraySimplifiedType,
-            SliceSimplifiedType => SliceSimplifiedType,
-            RefSimplifiedType(m) => RefSimplifiedType(m),
-            PtrSimplifiedType(m) => PtrSimplifiedType(m),
-            NeverSimplifiedType => NeverSimplifiedType,
-            MarkerTraitObjectSimplifiedType => MarkerTraitObjectSimplifiedType,
-            TupleSimplifiedType(n) => TupleSimplifiedType(n),
-            TraitSimplifiedType(d) => TraitSimplifiedType(map(d)),
-            ClosureSimplifiedType(d) => ClosureSimplifiedType(map(d)),
-            GeneratorSimplifiedType(d) => GeneratorSimplifiedType(map(d)),
-            GeneratorWitnessSimplifiedType(n) => GeneratorWitnessSimplifiedType(n),
-            FunctionSimplifiedType(n) => FunctionSimplifiedType(n),
-            PlaceholderSimplifiedType => PlaceholderSimplifiedType,
-        }
-    }
 }
 
 /// Given generic arguments from an obligation and an impl,
index d283ccc3ad8a29435035c2c6bc4fc1fe9b0b3454..042b89bc4b01f6b4a5271e9ec4dc5d51611fabcd 100644 (file)
@@ -95,7 +95,7 @@ fn add_kind(&mut self, kind: &ty::TyKind<'_>) {
                 self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
             }
 
-            &ty::Generator(_, ref substs, _) => {
+            ty::Generator(_, substs, _) => {
                 let substs = substs.as_generator();
                 let should_remove_further_specializable =
                     !self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
@@ -186,7 +186,7 @@ fn add_kind(&mut self, kind: &ty::TyKind<'_>) {
 
             &ty::Slice(tt) => self.add_ty(tt),
 
-            &ty::RawPtr(ref m) => {
+            ty::RawPtr(m) => {
                 self.add_ty(m.ty);
             }
 
index d431d008ddf06ed96489dcea92e5a542aa74e537..09fee0c3f7c30819138b4df81f49295aa0a6d031 100644 (file)
@@ -583,36 +583,6 @@ pub fn erase_late_bound_regions<T>(self, value: Binder<'tcx, T>) -> T
         self.replace_late_bound_regions(value, |_| self.lifetimes.re_erased).0
     }
 
-    /// Rewrite any late-bound regions so that they are anonymous. Region numbers are
-    /// assigned starting at 0 and increasing monotonically in the order traversed
-    /// by the fold operation.
-    ///
-    /// The chief purpose of this function is to canonicalize regions so that two
-    /// `FnSig`s or `TraitRef`s which are equivalent up to region naming will become
-    /// structurally identical. For example, `for<'a, 'b> fn(&'a isize, &'b isize)` and
-    /// `for<'a, 'b> fn(&'b isize, &'a isize)` will become identical after anonymization.
-    pub fn anonymize_late_bound_regions<T>(self, sig: Binder<'tcx, T>) -> Binder<'tcx, T>
-    where
-        T: TypeFoldable<'tcx>,
-    {
-        let mut counter = 0;
-        let inner = self
-            .replace_late_bound_regions(sig, |_| {
-                let br = ty::BoundRegion {
-                    var: ty::BoundVar::from_u32(counter),
-                    kind: ty::BrAnon(counter, None),
-                };
-                let r = self.mk_region(ty::ReLateBound(ty::INNERMOST, br));
-                counter += 1;
-                r
-            })
-            .0;
-        let bound_vars = self.mk_bound_variable_kinds(
-            (0..counter).map(|i| ty::BoundVariableKind::Region(ty::BrAnon(i, None))),
-        );
-        Binder::bind_with_vars(inner, bound_vars)
-    }
-
     /// Anonymize all bound variables in `value`, this is mostly used to improve caching.
     pub fn anonymize_bound_vars<T>(self, value: Binder<'tcx, T>) -> Binder<'tcx, T>
     where
index 5232c1e1cc0f83d7333baa4c066c1fd4bcd3a75d..a8e1253e67057bdc504be706707f10cc29f119d5 100644 (file)
     CAPTURE_STRUCT_LOCAL,
 };
 pub use self::consts::{
-    Const, ConstInt, ConstKind, ConstS, Expr, InferConst, ScalarInt, UnevaluatedConst, ValTree,
+    Const, ConstData, ConstInt, ConstKind, Expr, InferConst, ScalarInt, UnevaluatedConst, ValTree,
 };
 pub use self::context::{
-    tls, CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
-    CtxtInterners, DeducedParamAttrs, FreeRegionInfo, GeneratorDiagnosticData,
-    GeneratorInteriorTypeCause, GlobalCtxt, Lift, OnDiskCache, TyCtxt, TyCtxtFeed, TypeckResults,
-    UserType, UserTypeAnnotationIndex,
+    tls, CtxtInterners, DeducedParamAttrs, FreeRegionInfo, GlobalCtxt, Lift, OnDiskCache, TyCtxt,
+    TyCtxtFeed,
 };
 pub use self::instance::{Instance, InstanceDef, ShortInstance};
 pub use self::list::List;
     Region, RegionKind, RegionVid, TraitRef, TyKind, TypeAndMut, UpvarSubsts, VarianceDiagInfo,
 };
 pub use self::trait_def::TraitDef;
+pub use self::typeck_results::{
+    CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
+    GeneratorDiagnosticData, GeneratorInteriorTypeCause, TypeckResults, UserType,
+    UserTypeAnnotationIndex,
+};
 
 pub mod _match;
 pub mod abstract_const;
 mod rvalue_scopes;
 mod structural_impls;
 mod sty;
+mod typeck_results;
 
 // Data types
 
@@ -941,7 +945,7 @@ pub fn unpack(self) -> TermKind<'tcx> {
                     &*((ptr & !TAG_MASK) as *const WithCachedTypeInfo<ty::TyKind<'tcx>>),
                 ))),
                 CONST_TAG => TermKind::Const(ty::Const(Interned::new_unchecked(
-                    &*((ptr & !TAG_MASK) as *const ty::ConstS<'tcx>),
+                    &*((ptr & !TAG_MASK) as *const ty::ConstData<'tcx>),
                 ))),
                 _ => core::intrinsics::unreachable(),
             }
@@ -987,7 +991,7 @@ fn pack(self) -> Term<'tcx> {
             TermKind::Const(ct) => {
                 // Ensure we can use the tag bits.
                 assert_eq!(mem::align_of_val(&*ct.0.0) & TAG_MASK, 0);
-                (CONST_TAG, ct.0.0 as *const ty::ConstS<'tcx> as usize)
+                (CONST_TAG, ct.0.0 as *const ty::ConstData<'tcx> as usize)
             }
         };
 
index c7d6c6abd1c22ebe153c37ae240e8f572058eee3..a21e3961cb627341211579f1a8528bb3a39b34c3 100644 (file)
@@ -1,15 +1,10 @@
 use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::def_id::{DefId, DefIndex};
+use rustc_hir::def_id::DefIndex;
 use rustc_index::vec::{Idx, IndexVec};
 
-use crate::middle::exported_symbols::ExportedSymbol;
-use crate::mir::Body;
-use crate::ty::{
-    self, Clause, Const, FnSig, GeneratorDiagnosticData, GenericPredicates, Predicate, TraitRef, Ty,
-};
+use crate::ty;
 
 pub trait ParameterizedOverTcx: 'static {
-    #[allow(unused_lifetimes)]
     type Value<'tcx>;
 }
 
@@ -67,7 +62,7 @@ impl $crate::ty::ParameterizedOverTcx for $ty {
     ty::TraitDef,
     ty::Visibility<DefIndex>,
     ty::adjustment::CoerceUnsizedInfo,
-    ty::fast_reject::SimplifiedTypeGen<DefId>,
+    ty::fast_reject::SimplifiedType,
     rustc_ast::Attribute,
     rustc_ast::DelimArgs,
     rustc_attr::ConstStability,
@@ -100,29 +95,28 @@ impl $crate::ty::ParameterizedOverTcx for $ty {
     rustc_type_ir::Variance,
 }
 
-// HACK(compiler-errors): This macro rule can only take an ident,
-// not a path, due to parsing ambiguity reasons. That means we gotta
-// import all of these types above.
+// HACK(compiler-errors): This macro rule can only take a fake path,
+// not a real, due to parsing ambiguity reasons.
 #[macro_export]
 macro_rules! parameterized_over_tcx {
-    ($($ident:ident),+ $(,)?) => {
+    ($($($fake_path:ident)::+),+ $(,)?) => {
         $(
-            impl $crate::ty::ParameterizedOverTcx for $ident<'static> {
-                type Value<'tcx> = $ident<'tcx>;
+            impl $crate::ty::ParameterizedOverTcx for $($fake_path)::+<'static> {
+                type Value<'tcx> = $($fake_path)::+<'tcx>;
             }
         )*
     }
 }
 
 parameterized_over_tcx! {
-    Ty,
-    FnSig,
-    GenericPredicates,
-    TraitRef,
-    Const,
-    Predicate,
-    Clause,
-    GeneratorDiagnosticData,
-    Body,
-    ExportedSymbol,
+    crate::middle::exported_symbols::ExportedSymbol,
+    crate::mir::Body,
+    ty::Ty,
+    ty::FnSig,
+    ty::GenericPredicates,
+    ty::TraitRef,
+    ty::Const,
+    ty::Predicate,
+    ty::Clause,
+    ty::GeneratorDiagnosticData,
 }
index b1bc6eb8b81c5351029382a88dec5fe2b4292728..a1d53506707c9a2938749623d087c314bad761a6 100644 (file)
@@ -16,6 +16,7 @@
 use rustc_session::cstore::{ExternCrate, ExternCrateSource};
 use rustc_session::Limit;
 use rustc_span::symbol::{kw, Ident, Symbol};
+use rustc_span::FileNameDisplayPreference;
 use rustc_target::abi::Size;
 use rustc_target::spec::abi::Abi;
 use smallvec::SmallVec;
@@ -818,11 +819,16 @@ fn pretty_print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error>
                             p!("@", print_def_path(did.to_def_id(), substs));
                         } else {
                             let span = self.tcx().def_span(did);
+                            let preference = if FORCE_TRIMMED_PATH.with(|flag| flag.get()) {
+                                FileNameDisplayPreference::Short
+                            } else {
+                                FileNameDisplayPreference::Remapped
+                            };
                             p!(write(
                                 "@{}",
                                 // This may end up in stderr diagnostics but it may also be emitted
                                 // into MIR. Hence we use the remapped path if available
-                                self.tcx().sess.source_map().span_to_embeddable_string(span)
+                                self.tcx().sess.source_map().span_to_string(span, preference)
                             ));
                         }
                     } else {
index c4116558bd27b262b6aebdc3ccdb0ee587213d0c..4d34ca3d66b5fd20b86a7b9fbbec7b0e51f60bdd 100644 (file)
@@ -428,7 +428,7 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>(
             Ok(a)
         }
 
-        (&ty::Param(ref a_p), &ty::Param(ref b_p)) if a_p.index == b_p.index => Ok(a),
+        (ty::Param(a_p), ty::Param(b_p)) if a_p.index == b_p.index => Ok(a),
 
         (ty::Placeholder(p1), ty::Placeholder(p2)) if p1 == p2 => Ok(a),
 
index 3c6800cf293dee25e44b9b807a7c14550330f8cf..30073b541ecbd0e5c09a32e0c91bcd028a6fa770 100644 (file)
@@ -99,12 +99,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
-impl fmt::Debug for ty::RegionVid {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "'_#{}r", self.index())
-    }
-}
-
 impl<'tcx> fmt::Debug for ty::TraitRef<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         with_no_trimmed_paths!(fmt::Display::fmt(self, f))
index 66aeebab88ba017d24bfd90895e1d1f7b58d4d94..e13b68c83b57c140f51b3eeabc290fe1ca2250fb 100644 (file)
@@ -1378,9 +1378,8 @@ pub struct ConstVid<'tcx> {
 rustc_index::newtype_index! {
     /// A **region** (lifetime) **v**ariable **ID**.
     #[derive(HashStable)]
-    pub struct RegionVid {
-        DEBUG_FORMAT = custom,
-    }
+    #[debug_format = "'_#{}r"]
+    pub struct RegionVid {}
 }
 
 impl Atom for RegionVid {
@@ -1391,7 +1390,7 @@ fn index(self) -> usize {
 
 rustc_index::newtype_index! {
     #[derive(HashStable)]
-    pub struct BoundVar { .. }
+    pub struct BoundVar {}
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
index f8385c4701605bcc07841ef86b7bb6d6a36c8122..2071d01027266581542ae273550c10b668235376 100644 (file)
@@ -90,7 +90,7 @@ fn pack(self) -> GenericArg<'tcx> {
             GenericArgKind::Const(ct) => {
                 // Ensure we can use the tag bits.
                 assert_eq!(mem::align_of_val(&*ct.0.0) & TAG_MASK, 0);
-                (CONST_TAG, ct.0.0 as *const ty::ConstS<'tcx> as usize)
+                (CONST_TAG, ct.0.0 as *const ty::ConstData<'tcx> as usize)
             }
         };
 
@@ -166,7 +166,7 @@ pub fn unpack(self) -> GenericArgKind<'tcx> {
                     &*((ptr & !TAG_MASK) as *const WithCachedTypeInfo<ty::TyKind<'tcx>>),
                 ))),
                 CONST_TAG => GenericArgKind::Const(ty::Const(Interned::new_unchecked(
-                    &*((ptr & !TAG_MASK) as *const ty::ConstS<'tcx>),
+                    &*((ptr & !TAG_MASK) as *const ty::ConstData<'tcx>),
                 ))),
                 _ => intrinsics::unreachable(),
             }
@@ -400,6 +400,7 @@ pub fn non_erasable_generics(
     }
 
     #[inline]
+    #[track_caller]
     pub fn type_at(&self, i: usize) -> Ty<'tcx> {
         if let GenericArgKind::Type(ty) = self[i].unpack() {
             ty
@@ -409,6 +410,7 @@ pub fn type_at(&self, i: usize) -> Ty<'tcx> {
     }
 
     #[inline]
+    #[track_caller]
     pub fn region_at(&self, i: usize) -> ty::Region<'tcx> {
         if let GenericArgKind::Lifetime(lt) = self[i].unpack() {
             lt
@@ -418,6 +420,7 @@ pub fn region_at(&self, i: usize) -> ty::Region<'tcx> {
     }
 
     #[inline]
+    #[track_caller]
     pub fn const_at(&self, i: usize) -> ty::Const<'tcx> {
         if let GenericArgKind::Const(ct) = self[i].unpack() {
             ct
@@ -427,6 +430,7 @@ pub fn const_at(&self, i: usize) -> ty::Const<'tcx> {
     }
 
     #[inline]
+    #[track_caller]
     pub fn type_for_def(&self, def: &ty::GenericParamDef) -> GenericArg<'tcx> {
         self.type_at(def.index as usize).into()
     }
diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs
new file mode 100644 (file)
index 0000000..136a490
--- /dev/null
@@ -0,0 +1,689 @@
+use crate::{
+    hir::place::Place as HirPlace,
+    infer::canonical::Canonical,
+    ty::{
+        self, tls, BindingMode, BoundVar, CanonicalPolyFnSig, ClosureSizeProfileData,
+        GenericArgKind, InternalSubsts, SubstsRef, Ty, UserSubsts,
+    },
+};
+use rustc_data_structures::{fx::FxHashMap, sync::Lrc, unord::UnordSet, vec_map::VecMap};
+use rustc_errors::ErrorGuaranteed;
+use rustc_hir as hir;
+use rustc_hir::{
+    def::{DefKind, Res},
+    def_id::{DefId, LocalDefId, LocalDefIdMap},
+    hir_id::OwnerId,
+    HirId, ItemLocalId, ItemLocalMap, ItemLocalSet,
+};
+use rustc_index::vec::{Idx, IndexVec};
+use rustc_macros::HashStable;
+use rustc_middle::mir::FakeReadCause;
+use rustc_session::Session;
+use rustc_span::Span;
+use std::{
+    collections::hash_map::{self, Entry},
+    hash::Hash,
+    iter,
+};
+
+use super::RvalueScopes;
+
+#[derive(TyEncodable, TyDecodable, Debug, HashStable)]
+pub struct TypeckResults<'tcx> {
+    /// The `HirId::owner` all `ItemLocalId`s in this table are relative to.
+    pub hir_owner: OwnerId,
+
+    /// Resolved definitions for `<T>::X` associated paths and
+    /// method calls, including those of overloaded operators.
+    type_dependent_defs: ItemLocalMap<Result<(DefKind, DefId), ErrorGuaranteed>>,
+
+    /// Resolved field indices for field accesses in expressions (`S { field }`, `obj.field`)
+    /// or patterns (`S { field }`). The index is often useful by itself, but to learn more
+    /// about the field you also need definition of the variant to which the field
+    /// belongs, but it may not exist if it's a tuple field (`tuple.0`).
+    field_indices: ItemLocalMap<usize>,
+
+    /// Stores the types for various nodes in the AST. Note that this table
+    /// is not guaranteed to be populated outside inference. See
+    /// typeck::check::fn_ctxt for details.
+    node_types: ItemLocalMap<Ty<'tcx>>,
+
+    /// Stores the type parameters which were substituted to obtain the type
+    /// of this node. This only applies to nodes that refer to entities
+    /// parameterized by type parameters, such as generic fns, types, or
+    /// other items.
+    node_substs: ItemLocalMap<SubstsRef<'tcx>>,
+
+    /// This will either store the canonicalized types provided by the user
+    /// or the substitutions that the user explicitly gave (if any) attached
+    /// to `id`. These will not include any inferred values. The canonical form
+    /// is used to capture things like `_` or other unspecified values.
+    ///
+    /// For example, if the user wrote `foo.collect::<Vec<_>>()`, then the
+    /// canonical substitutions would include only `for<X> { Vec<X> }`.
+    ///
+    /// See also `AscribeUserType` statement in MIR.
+    user_provided_types: ItemLocalMap<CanonicalUserType<'tcx>>,
+
+    /// Stores the canonicalized types provided by the user. See also
+    /// `AscribeUserType` statement in MIR.
+    pub user_provided_sigs: LocalDefIdMap<CanonicalPolyFnSig<'tcx>>,
+
+    adjustments: ItemLocalMap<Vec<ty::adjustment::Adjustment<'tcx>>>,
+
+    /// Stores the actual binding mode for all instances of hir::BindingAnnotation.
+    pat_binding_modes: ItemLocalMap<BindingMode>,
+
+    /// Stores the types which were implicitly dereferenced in pattern binding modes
+    /// for later usage in THIR lowering. For example,
+    ///
+    /// ```
+    /// match &&Some(5i32) {
+    ///     Some(n) => {},
+    ///     _ => {},
+    /// }
+    /// ```
+    /// leads to a `vec![&&Option<i32>, &Option<i32>]`. Empty vectors are not stored.
+    ///
+    /// See:
+    /// <https://github.com/rust-lang/rfcs/blob/master/text/2005-match-ergonomics.md#definitions>
+    pat_adjustments: ItemLocalMap<Vec<Ty<'tcx>>>,
+
+    /// Records the reasons that we picked the kind of each closure;
+    /// not all closures are present in the map.
+    closure_kind_origins: ItemLocalMap<(Span, HirPlace<'tcx>)>,
+
+    /// For each fn, records the "liberated" types of its arguments
+    /// and return type. Liberated means that all bound regions
+    /// (including late-bound regions) are replaced with free
+    /// equivalents. This table is not used in codegen (since regions
+    /// are erased there) and hence is not serialized to metadata.
+    ///
+    /// This table also contains the "revealed" values for any `impl Trait`
+    /// that appear in the signature and whose values are being inferred
+    /// by this function.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// # use std::fmt::Debug;
+    /// fn foo(x: &u32) -> impl Debug { *x }
+    /// ```
+    ///
+    /// The function signature here would be:
+    ///
+    /// ```ignore (illustrative)
+    /// for<'a> fn(&'a u32) -> Foo
+    /// ```
+    ///
+    /// where `Foo` is an opaque type created for this function.
+    ///
+    ///
+    /// The *liberated* form of this would be
+    ///
+    /// ```ignore (illustrative)
+    /// fn(&'a u32) -> u32
+    /// ```
+    ///
+    /// Note that `'a` is not bound (it would be an `ReFree`) and
+    /// that the `Foo` opaque type is replaced by its hidden type.
+    liberated_fn_sigs: ItemLocalMap<ty::FnSig<'tcx>>,
+
+    /// For each FRU expression, record the normalized types of the fields
+    /// of the struct - this is needed because it is non-trivial to
+    /// normalize while preserving regions. This table is used only in
+    /// MIR construction and hence is not serialized to metadata.
+    fru_field_types: ItemLocalMap<Vec<Ty<'tcx>>>,
+
+    /// For every coercion cast we add the HIR node ID of the cast
+    /// expression to this set.
+    coercion_casts: ItemLocalSet,
+
+    /// Set of trait imports actually used in the method resolution.
+    /// This is used for warning unused imports. During type
+    /// checking, this `Lrc` should not be cloned: it must have a ref-count
+    /// of 1 so that we can insert things into the set mutably.
+    pub used_trait_imports: Lrc<UnordSet<LocalDefId>>,
+
+    /// If any errors occurred while type-checking this body,
+    /// this field will be set to `Some(ErrorGuaranteed)`.
+    pub tainted_by_errors: Option<ErrorGuaranteed>,
+
+    /// All the opaque types that have hidden types set
+    /// by this function. We also store the
+    /// type here, so that mir-borrowck can use it as a hint for figuring out hidden types,
+    /// even if they are only set in dead code (which doesn't show up in MIR).
+    pub concrete_opaque_types: VecMap<LocalDefId, ty::OpaqueHiddenType<'tcx>>,
+
+    /// Tracks the minimum captures required for a closure;
+    /// see `MinCaptureInformationMap` for more details.
+    pub closure_min_captures: ty::MinCaptureInformationMap<'tcx>,
+
+    /// Tracks the fake reads required for a closure and the reason for the fake read.
+    /// When performing pattern matching for closures, there are times we don't end up
+    /// reading places that are mentioned in a closure (because of _ patterns). However,
+    /// to ensure the places are initialized, we introduce fake reads.
+    /// Consider these two examples:
+    /// ``` (discriminant matching with only wildcard arm)
+    /// let x: u8;
+    /// let c = || match x { _ => () };
+    /// ```
+    /// In this example, we don't need to actually read/borrow `x` in `c`, and so we don't
+    /// want to capture it. However, we do still want an error here, because `x` should have
+    /// to be initialized at the point where c is created. Therefore, we add a "fake read"
+    /// instead.
+    /// ``` (destructured assignments)
+    /// let c = || {
+    ///     let (t1, t2) = t;
+    /// }
+    /// ```
+    /// In the second example, we capture the disjoint fields of `t` (`t.0` & `t.1`), but
+    /// we never capture `t`. This becomes an issue when we build MIR as we require
+    /// information on `t` in order to create place `t.0` and `t.1`. We can solve this
+    /// issue by fake reading `t`.
+    pub closure_fake_reads: FxHashMap<LocalDefId, Vec<(HirPlace<'tcx>, FakeReadCause, hir::HirId)>>,
+
+    /// Tracks the rvalue scoping rules which defines finer scoping for rvalue expressions
+    /// by applying extended parameter rules.
+    /// Details may be find in `rustc_hir_analysis::check::rvalue_scopes`.
+    pub rvalue_scopes: RvalueScopes,
+
+    /// Stores the type, expression, span and optional scope span of all types
+    /// that are live across the yield of this generator (if a generator).
+    pub generator_interior_types: ty::Binder<'tcx, Vec<GeneratorInteriorTypeCause<'tcx>>>,
+
+    /// We sometimes treat byte string literals (which are of type `&[u8; N]`)
+    /// as `&[u8]`, depending on the pattern  in which they are used.
+    /// This hashset records all instances where we behave
+    /// like this to allow `const_to_pat` to reliably handle this situation.
+    pub treat_byte_string_as_slice: ItemLocalSet,
+
+    /// Contains the data for evaluating the effect of feature `capture_disjoint_fields`
+    /// on closure size.
+    pub closure_size_eval: FxHashMap<LocalDefId, ClosureSizeProfileData<'tcx>>,
+}
+
+/// Whenever a value may be live across a generator yield, the type of that value winds up in the
+/// `GeneratorInteriorTypeCause` struct. This struct adds additional information about such
+/// captured types that can be useful for diagnostics. In particular, it stores the span that
+/// caused a given type to be recorded, along with the scope that enclosed the value (which can
+/// be used to find the await that the value is live across).
+///
+/// For example:
+///
+/// ```ignore (pseudo-Rust)
+/// async move {
+///     let x: T = expr;
+///     foo.await
+///     ...
+/// }
+/// ```
+///
+/// Here, we would store the type `T`, the span of the value `x`, the "scope-span" for
+/// the scope that contains `x`, the expr `T` evaluated from, and the span of `foo.await`.
+#[derive(TyEncodable, TyDecodable, Clone, Debug, Eq, Hash, PartialEq, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub struct GeneratorInteriorTypeCause<'tcx> {
+    /// Type of the captured binding.
+    pub ty: Ty<'tcx>,
+    /// Span of the binding that was captured.
+    pub span: Span,
+    /// Span of the scope of the captured binding.
+    pub scope_span: Option<Span>,
+    /// Span of `.await` or `yield` expression.
+    pub yield_span: Span,
+    /// Expr which the type evaluated from.
+    pub expr: Option<hir::HirId>,
+}
+
+// This type holds diagnostic information on generators and async functions across crate boundaries
+// and is used to provide better error messages
+#[derive(TyEncodable, TyDecodable, Clone, Debug, HashStable)]
+pub struct GeneratorDiagnosticData<'tcx> {
+    pub generator_interior_types: ty::Binder<'tcx, Vec<GeneratorInteriorTypeCause<'tcx>>>,
+    pub hir_owner: DefId,
+    pub nodes_types: ItemLocalMap<Ty<'tcx>>,
+    pub adjustments: ItemLocalMap<Vec<ty::adjustment::Adjustment<'tcx>>>,
+}
+
+impl<'tcx> TypeckResults<'tcx> {
+    pub fn new(hir_owner: OwnerId) -> TypeckResults<'tcx> {
+        TypeckResults {
+            hir_owner,
+            type_dependent_defs: Default::default(),
+            field_indices: Default::default(),
+            user_provided_types: Default::default(),
+            user_provided_sigs: Default::default(),
+            node_types: Default::default(),
+            node_substs: Default::default(),
+            adjustments: Default::default(),
+            pat_binding_modes: Default::default(),
+            pat_adjustments: Default::default(),
+            closure_kind_origins: Default::default(),
+            liberated_fn_sigs: Default::default(),
+            fru_field_types: Default::default(),
+            coercion_casts: Default::default(),
+            used_trait_imports: Lrc::new(Default::default()),
+            tainted_by_errors: None,
+            concrete_opaque_types: Default::default(),
+            closure_min_captures: Default::default(),
+            closure_fake_reads: Default::default(),
+            rvalue_scopes: Default::default(),
+            generator_interior_types: ty::Binder::dummy(Default::default()),
+            treat_byte_string_as_slice: Default::default(),
+            closure_size_eval: Default::default(),
+        }
+    }
+
+    /// Returns the final resolution of a `QPath` in an `Expr` or `Pat` node.
+    pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res {
+        match *qpath {
+            hir::QPath::Resolved(_, ref path) => path.res,
+            hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self
+                .type_dependent_def(id)
+                .map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)),
+        }
+    }
+
+    pub fn type_dependent_defs(
+        &self,
+    ) -> LocalTableInContext<'_, Result<(DefKind, DefId), ErrorGuaranteed>> {
+        LocalTableInContext { hir_owner: self.hir_owner, data: &self.type_dependent_defs }
+    }
+
+    pub fn type_dependent_def(&self, id: HirId) -> Option<(DefKind, DefId)> {
+        validate_hir_id_for_typeck_results(self.hir_owner, id);
+        self.type_dependent_defs.get(&id.local_id).cloned().and_then(|r| r.ok())
+    }
+
+    pub fn type_dependent_def_id(&self, id: HirId) -> Option<DefId> {
+        self.type_dependent_def(id).map(|(_, def_id)| def_id)
+    }
+
+    pub fn type_dependent_defs_mut(
+        &mut self,
+    ) -> LocalTableInContextMut<'_, Result<(DefKind, DefId), ErrorGuaranteed>> {
+        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.type_dependent_defs }
+    }
+
+    pub fn field_indices(&self) -> LocalTableInContext<'_, usize> {
+        LocalTableInContext { hir_owner: self.hir_owner, data: &self.field_indices }
+    }
+
+    pub fn field_indices_mut(&mut self) -> LocalTableInContextMut<'_, usize> {
+        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.field_indices }
+    }
+
+    pub fn field_index(&self, id: hir::HirId) -> usize {
+        self.field_indices().get(id).cloned().expect("no index for a field")
+    }
+
+    pub fn opt_field_index(&self, id: hir::HirId) -> Option<usize> {
+        self.field_indices().get(id).cloned()
+    }
+
+    pub fn user_provided_types(&self) -> LocalTableInContext<'_, CanonicalUserType<'tcx>> {
+        LocalTableInContext { hir_owner: self.hir_owner, data: &self.user_provided_types }
+    }
+
+    pub fn user_provided_types_mut(
+        &mut self,
+    ) -> LocalTableInContextMut<'_, CanonicalUserType<'tcx>> {
+        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.user_provided_types }
+    }
+
+    pub fn node_types(&self) -> LocalTableInContext<'_, Ty<'tcx>> {
+        LocalTableInContext { hir_owner: self.hir_owner, data: &self.node_types }
+    }
+
+    pub fn node_types_mut(&mut self) -> LocalTableInContextMut<'_, Ty<'tcx>> {
+        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.node_types }
+    }
+
+    pub fn get_generator_diagnostic_data(&self) -> GeneratorDiagnosticData<'tcx> {
+        let generator_interior_type = self.generator_interior_types.map_bound_ref(|vec| {
+            vec.iter()
+                .map(|item| {
+                    GeneratorInteriorTypeCause {
+                        ty: item.ty,
+                        span: item.span,
+                        scope_span: item.scope_span,
+                        yield_span: item.yield_span,
+                        expr: None, //FIXME: Passing expression over crate boundaries is impossible at the moment
+                    }
+                })
+                .collect::<Vec<_>>()
+        });
+        GeneratorDiagnosticData {
+            generator_interior_types: generator_interior_type,
+            hir_owner: self.hir_owner.to_def_id(),
+            nodes_types: self.node_types.clone(),
+            adjustments: self.adjustments.clone(),
+        }
+    }
+
+    pub fn node_type(&self, id: hir::HirId) -> Ty<'tcx> {
+        self.node_type_opt(id).unwrap_or_else(|| {
+            bug!("node_type: no type for node `{}`", tls::with(|tcx| tcx.hir().node_to_string(id)))
+        })
+    }
+
+    pub fn node_type_opt(&self, id: hir::HirId) -> Option<Ty<'tcx>> {
+        validate_hir_id_for_typeck_results(self.hir_owner, id);
+        self.node_types.get(&id.local_id).cloned()
+    }
+
+    pub fn node_substs_mut(&mut self) -> LocalTableInContextMut<'_, SubstsRef<'tcx>> {
+        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.node_substs }
+    }
+
+    pub fn node_substs(&self, id: hir::HirId) -> SubstsRef<'tcx> {
+        validate_hir_id_for_typeck_results(self.hir_owner, id);
+        self.node_substs.get(&id.local_id).cloned().unwrap_or_else(|| InternalSubsts::empty())
+    }
+
+    pub fn node_substs_opt(&self, id: hir::HirId) -> Option<SubstsRef<'tcx>> {
+        validate_hir_id_for_typeck_results(self.hir_owner, id);
+        self.node_substs.get(&id.local_id).cloned()
+    }
+
+    /// Returns the type of a pattern as a monotype. Like [`expr_ty`], this function
+    /// doesn't provide type parameter substitutions.
+    ///
+    /// [`expr_ty`]: TypeckResults::expr_ty
+    pub fn pat_ty(&self, pat: &hir::Pat<'_>) -> Ty<'tcx> {
+        self.node_type(pat.hir_id)
+    }
+
+    /// Returns the type of an expression as a monotype.
+    ///
+    /// NB (1): This is the PRE-ADJUSTMENT TYPE for the expression.  That is, in
+    /// some cases, we insert `Adjustment` annotations such as auto-deref or
+    /// auto-ref.  The type returned by this function does not consider such
+    /// adjustments.  See `expr_ty_adjusted()` instead.
+    ///
+    /// NB (2): This type doesn't provide type parameter substitutions; e.g., if you
+    /// ask for the type of `id` in `id(3)`, it will return `fn(&isize) -> isize`
+    /// instead of `fn(ty) -> T with T = isize`.
+    pub fn expr_ty(&self, expr: &hir::Expr<'_>) -> Ty<'tcx> {
+        self.node_type(expr.hir_id)
+    }
+
+    pub fn expr_ty_opt(&self, expr: &hir::Expr<'_>) -> Option<Ty<'tcx>> {
+        self.node_type_opt(expr.hir_id)
+    }
+
+    pub fn adjustments(&self) -> LocalTableInContext<'_, Vec<ty::adjustment::Adjustment<'tcx>>> {
+        LocalTableInContext { hir_owner: self.hir_owner, data: &self.adjustments }
+    }
+
+    pub fn adjustments_mut(
+        &mut self,
+    ) -> LocalTableInContextMut<'_, Vec<ty::adjustment::Adjustment<'tcx>>> {
+        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.adjustments }
+    }
+
+    pub fn expr_adjustments(&self, expr: &hir::Expr<'_>) -> &[ty::adjustment::Adjustment<'tcx>] {
+        validate_hir_id_for_typeck_results(self.hir_owner, expr.hir_id);
+        self.adjustments.get(&expr.hir_id.local_id).map_or(&[], |a| &a[..])
+    }
+
+    /// Returns the type of `expr`, considering any `Adjustment`
+    /// entry recorded for that expression.
+    pub fn expr_ty_adjusted(&self, expr: &hir::Expr<'_>) -> Ty<'tcx> {
+        self.expr_adjustments(expr).last().map_or_else(|| self.expr_ty(expr), |adj| adj.target)
+    }
+
+    pub fn expr_ty_adjusted_opt(&self, expr: &hir::Expr<'_>) -> Option<Ty<'tcx>> {
+        self.expr_adjustments(expr).last().map(|adj| adj.target).or_else(|| self.expr_ty_opt(expr))
+    }
+
+    pub fn is_method_call(&self, expr: &hir::Expr<'_>) -> bool {
+        // Only paths and method calls/overloaded operators have
+        // entries in type_dependent_defs, ignore the former here.
+        if let hir::ExprKind::Path(_) = expr.kind {
+            return false;
+        }
+
+        matches!(self.type_dependent_defs().get(expr.hir_id), Some(Ok((DefKind::AssocFn, _))))
+    }
+
+    pub fn extract_binding_mode(&self, s: &Session, id: HirId, sp: Span) -> Option<BindingMode> {
+        self.pat_binding_modes().get(id).copied().or_else(|| {
+            s.delay_span_bug(sp, "missing binding mode");
+            None
+        })
+    }
+
+    pub fn pat_binding_modes(&self) -> LocalTableInContext<'_, BindingMode> {
+        LocalTableInContext { hir_owner: self.hir_owner, data: &self.pat_binding_modes }
+    }
+
+    pub fn pat_binding_modes_mut(&mut self) -> LocalTableInContextMut<'_, BindingMode> {
+        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_binding_modes }
+    }
+
+    pub fn pat_adjustments(&self) -> LocalTableInContext<'_, Vec<Ty<'tcx>>> {
+        LocalTableInContext { hir_owner: self.hir_owner, data: &self.pat_adjustments }
+    }
+
+    pub fn pat_adjustments_mut(&mut self) -> LocalTableInContextMut<'_, Vec<Ty<'tcx>>> {
+        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments }
+    }
+
+    /// For a given closure, returns the iterator of `ty::CapturedPlace`s that are captured
+    /// by the closure.
+    pub fn closure_min_captures_flattened(
+        &self,
+        closure_def_id: LocalDefId,
+    ) -> impl Iterator<Item = &ty::CapturedPlace<'tcx>> {
+        self.closure_min_captures
+            .get(&closure_def_id)
+            .map(|closure_min_captures| closure_min_captures.values().flat_map(|v| v.iter()))
+            .into_iter()
+            .flatten()
+    }
+
+    pub fn closure_kind_origins(&self) -> LocalTableInContext<'_, (Span, HirPlace<'tcx>)> {
+        LocalTableInContext { hir_owner: self.hir_owner, data: &self.closure_kind_origins }
+    }
+
+    pub fn closure_kind_origins_mut(
+        &mut self,
+    ) -> LocalTableInContextMut<'_, (Span, HirPlace<'tcx>)> {
+        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.closure_kind_origins }
+    }
+
+    pub fn liberated_fn_sigs(&self) -> LocalTableInContext<'_, ty::FnSig<'tcx>> {
+        LocalTableInContext { hir_owner: self.hir_owner, data: &self.liberated_fn_sigs }
+    }
+
+    pub fn liberated_fn_sigs_mut(&mut self) -> LocalTableInContextMut<'_, ty::FnSig<'tcx>> {
+        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.liberated_fn_sigs }
+    }
+
+    pub fn fru_field_types(&self) -> LocalTableInContext<'_, Vec<Ty<'tcx>>> {
+        LocalTableInContext { hir_owner: self.hir_owner, data: &self.fru_field_types }
+    }
+
+    pub fn fru_field_types_mut(&mut self) -> LocalTableInContextMut<'_, Vec<Ty<'tcx>>> {
+        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.fru_field_types }
+    }
+
+    pub fn is_coercion_cast(&self, hir_id: hir::HirId) -> bool {
+        validate_hir_id_for_typeck_results(self.hir_owner, hir_id);
+        self.coercion_casts.contains(&hir_id.local_id)
+    }
+
+    pub fn set_coercion_cast(&mut self, id: ItemLocalId) {
+        self.coercion_casts.insert(id);
+    }
+
+    pub fn coercion_casts(&self) -> &ItemLocalSet {
+        &self.coercion_casts
+    }
+}
+
+/// Validate that the given HirId (respectively its `local_id` part) can be
+/// safely used as a key in the maps of a TypeckResults. For that to be
+/// the case, the HirId must have the same `owner` as all the other IDs in
+/// this table (signified by `hir_owner`). Otherwise the HirId
+/// would be in a different frame of reference and using its `local_id`
+/// would result in lookup errors, or worse, in silently wrong data being
+/// stored/returned.
+#[inline]
+fn validate_hir_id_for_typeck_results(hir_owner: OwnerId, hir_id: hir::HirId) {
+    if hir_id.owner != hir_owner {
+        invalid_hir_id_for_typeck_results(hir_owner, hir_id);
+    }
+}
+
+#[cold]
+#[inline(never)]
+fn invalid_hir_id_for_typeck_results(hir_owner: OwnerId, hir_id: hir::HirId) {
+    ty::tls::with(|tcx| {
+        bug!(
+            "node {} with HirId::owner {:?} cannot be placed in TypeckResults with hir_owner {:?}",
+            tcx.hir().node_to_string(hir_id),
+            hir_id.owner,
+            hir_owner
+        )
+    });
+}
+
+pub struct LocalTableInContext<'a, V> {
+    hir_owner: OwnerId,
+    data: &'a ItemLocalMap<V>,
+}
+
+impl<'a, V> LocalTableInContext<'a, V> {
+    pub fn contains_key(&self, id: hir::HirId) -> bool {
+        validate_hir_id_for_typeck_results(self.hir_owner, id);
+        self.data.contains_key(&id.local_id)
+    }
+
+    pub fn get(&self, id: hir::HirId) -> Option<&V> {
+        validate_hir_id_for_typeck_results(self.hir_owner, id);
+        self.data.get(&id.local_id)
+    }
+
+    pub fn iter(&self) -> hash_map::Iter<'_, hir::ItemLocalId, V> {
+        self.data.iter()
+    }
+}
+
+impl<'a, V> ::std::ops::Index<hir::HirId> for LocalTableInContext<'a, V> {
+    type Output = V;
+
+    fn index(&self, key: hir::HirId) -> &V {
+        self.get(key).expect("LocalTableInContext: key not found")
+    }
+}
+
+pub struct LocalTableInContextMut<'a, V> {
+    hir_owner: OwnerId,
+    data: &'a mut ItemLocalMap<V>,
+}
+
+impl<'a, V> LocalTableInContextMut<'a, V> {
+    pub fn get_mut(&mut self, id: hir::HirId) -> Option<&mut V> {
+        validate_hir_id_for_typeck_results(self.hir_owner, id);
+        self.data.get_mut(&id.local_id)
+    }
+
+    pub fn entry(&mut self, id: hir::HirId) -> Entry<'_, hir::ItemLocalId, V> {
+        validate_hir_id_for_typeck_results(self.hir_owner, id);
+        self.data.entry(id.local_id)
+    }
+
+    pub fn insert(&mut self, id: hir::HirId, val: V) -> Option<V> {
+        validate_hir_id_for_typeck_results(self.hir_owner, id);
+        self.data.insert(id.local_id, val)
+    }
+
+    pub fn remove(&mut self, id: hir::HirId) -> Option<V> {
+        validate_hir_id_for_typeck_results(self.hir_owner, id);
+        self.data.remove(&id.local_id)
+    }
+}
+
+rustc_index::newtype_index! {
+    #[derive(HashStable)]
+    #[debug_format = "UserType({})"]
+    pub struct UserTypeAnnotationIndex {
+        const START_INDEX = 0;
+    }
+}
+
+/// Mapping of type annotation indices to canonical user type annotations.
+pub type CanonicalUserTypeAnnotations<'tcx> =
+    IndexVec<UserTypeAnnotationIndex, CanonicalUserTypeAnnotation<'tcx>>;
+
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)]
+pub struct CanonicalUserTypeAnnotation<'tcx> {
+    pub user_ty: Box<CanonicalUserType<'tcx>>,
+    pub span: Span,
+    pub inferred_ty: Ty<'tcx>,
+}
+
+/// Canonicalized user type annotation.
+pub type CanonicalUserType<'tcx> = Canonical<'tcx, UserType<'tcx>>;
+
+impl<'tcx> CanonicalUserType<'tcx> {
+    /// Returns `true` if this represents a substitution of the form `[?0, ?1, ?2]`,
+    /// i.e., each thing is mapped to a canonical variable with the same index.
+    pub fn is_identity(&self) -> bool {
+        match self.value {
+            UserType::Ty(_) => false,
+            UserType::TypeOf(_, user_substs) => {
+                if user_substs.user_self_ty.is_some() {
+                    return false;
+                }
+
+                iter::zip(user_substs.substs, BoundVar::new(0)..).all(|(kind, cvar)| {
+                    match kind.unpack() {
+                        GenericArgKind::Type(ty) => match ty.kind() {
+                            ty::Bound(debruijn, b) => {
+                                // We only allow a `ty::INNERMOST` index in substitutions.
+                                assert_eq!(*debruijn, ty::INNERMOST);
+                                cvar == b.var
+                            }
+                            _ => false,
+                        },
+
+                        GenericArgKind::Lifetime(r) => match *r {
+                            ty::ReLateBound(debruijn, br) => {
+                                // We only allow a `ty::INNERMOST` index in substitutions.
+                                assert_eq!(debruijn, ty::INNERMOST);
+                                cvar == br.var
+                            }
+                            _ => false,
+                        },
+
+                        GenericArgKind::Const(ct) => match ct.kind() {
+                            ty::ConstKind::Bound(debruijn, b) => {
+                                // We only allow a `ty::INNERMOST` index in substitutions.
+                                assert_eq!(debruijn, ty::INNERMOST);
+                                cvar == b
+                            }
+                            _ => false,
+                        },
+                    }
+                })
+            }
+        }
+    }
+}
+
+/// A user-given type annotation attached to a constant. These arise
+/// from constants that are named via paths, like `Foo::<A>::new` and
+/// so forth.
+#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
+pub enum UserType<'tcx> {
+    Ty(Ty<'tcx>),
+
+    /// The canonical type is the result of `type_of(def_id)` with the
+    /// given substitutions applied.
+    TypeOf(DefId, UserSubsts<'tcx>),
+}
index 857f52c8a245612ddc9d164207681e8c15a7f4aa..5d0af1d4eadc8768355cf3137917bbf9e57ca793 100644 (file)
@@ -3,6 +3,7 @@
 use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use crate::mir;
 use crate::ty::layout::IntegerExt;
+use crate::ty::query::TyCtxtAt;
 use crate::ty::{
     self, DefIdTree, FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
     TypeVisitable,
@@ -769,6 +770,12 @@ pub fn generator_layout_and_saved_local_names(
     }
 }
 
+impl<'tcx> TyCtxtAt<'tcx> {
+    pub fn bound_type_of(self, def_id: DefId) -> ty::EarlyBinder<Ty<'tcx>> {
+        ty::EarlyBinder(self.type_of(def_id))
+    }
+}
+
 struct OpaqueTypeExpander<'tcx> {
     // Contains the DefIds of the opaque types that are currently being
     // expanded. When we expand an opaque type we insert the DefId of
index 802925dfb043e3eafb4f70304a50cf359f0cb78b..f77bd9f0c6ffc320d6222f03130feff9550ab844 100644 (file)
@@ -88,8 +88,8 @@ pub(super) fn vtable_allocation_provider<'tcx>(
                 let fn_ptr = Pointer::from(fn_alloc_id);
                 Scalar::from_pointer(fn_ptr, &tcx)
             }
-            VtblEntry::MetadataSize => Scalar::from_uint(size, ptr_size).into(),
-            VtblEntry::MetadataAlign => Scalar::from_uint(align, ptr_size).into(),
+            VtblEntry::MetadataSize => Scalar::from_uint(size, ptr_size),
+            VtblEntry::MetadataAlign => Scalar::from_uint(align, ptr_size),
             VtblEntry::Vacant => continue,
             VtblEntry::Method(instance) => {
                 // Prepare the fn ptr we write into the vtable.
index 2baa3bfcb6401f3570ee79012cab627d0a6b11f9..4ad3343d3031b2fa1e0f23eb2efc03ffd85edad1 100644 (file)
@@ -17,6 +17,7 @@ rustc_index = { path = "../rustc_index" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_hir = { path = "../rustc_hir" }
 rustc_infer = { path = "../rustc_infer" }
+rustc_macros = { path = "../rustc_macros" }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
index 1fd2e40c187e0487eb761156caa852a091d45b98..34fefb99e09c25c1b034a2f431ce38dafbf3e39c 100644 (file)
@@ -25,7 +25,7 @@
 use rustc_middle::{
     mir::*,
     thir::*,
-    ty::{Ty, TyCtxt},
+    ty::{ParamEnv, Ty, TyCtxt},
 };
 use rustc_span::Span;
 
@@ -78,6 +78,7 @@ pub(super) fn build_custom_mir<'tcx>(
 
     let mut pctxt = ParseCtxt {
         tcx,
+        param_env: tcx.param_env(did),
         thir,
         source_scope: OUTERMOST_SOURCE_SCOPE,
         body: &mut body,
@@ -132,6 +133,7 @@ fn parse_attribute(attr: &Attribute) -> MirPhase {
 
 struct ParseCtxt<'tcx, 'body> {
     tcx: TyCtxt<'tcx>,
+    param_env: ParamEnv<'tcx>,
     thir: &'body Thir<'tcx>,
     source_scope: SourceScope,
 
index 03206af33bfb5dc927da6348f64b84f7d4074a08..7c39a93a8eb9e4b90c97a482c9c4849ed4d1608a 100644 (file)
@@ -1,5 +1,11 @@
 use rustc_middle::mir::interpret::{ConstValue, Scalar};
+use rustc_middle::mir::tcx::PlaceTy;
 use rustc_middle::{mir::*, thir::*, ty};
+use rustc_span::Span;
+use rustc_target::abi::VariantIdx;
+
+use crate::build::custom::ParseError;
+use crate::build::expr::as_constant::as_constant_inner;
 
 use super::{parse_by_kind, PResult, ParseCtxt};
 
@@ -12,6 +18,14 @@ pub fn parse_statement(&self, expr_id: ExprId) -> PResult<StatementKind<'tcx>> {
             @call("mir_retag_raw", args) => {
                 Ok(StatementKind::Retag(RetagKind::Raw, Box::new(self.parse_place(args[0])?)))
             },
+            @call("mir_set_discriminant", args) => {
+                let place = self.parse_place(args[0])?;
+                let var = self.parse_integer_literal(args[1])? as u32;
+                Ok(StatementKind::SetDiscriminant {
+                    place: Box::new(place),
+                    variant_index: VariantIdx::from_u32(var),
+                })
+            },
             ExprKind::Assign { lhs, rhs } => {
                 let lhs = self.parse_place(*lhs)?;
                 let rhs = self.parse_rvalue(*rhs)?;
@@ -21,18 +35,109 @@ pub fn parse_statement(&self, expr_id: ExprId) -> PResult<StatementKind<'tcx>> {
     }
 
     pub fn parse_terminator(&self, expr_id: ExprId) -> PResult<TerminatorKind<'tcx>> {
-        parse_by_kind!(self, expr_id, _, "terminator",
+        parse_by_kind!(self, expr_id, expr, "terminator",
             @call("mir_return", _args) => {
                 Ok(TerminatorKind::Return)
             },
             @call("mir_goto", args) => {
                 Ok(TerminatorKind::Goto { target: self.parse_block(args[0])? } )
             },
+            @call("mir_unreachable", _args) => {
+                Ok(TerminatorKind::Unreachable)
+            },
+            @call("mir_drop", args) => {
+                Ok(TerminatorKind::Drop {
+                    place: self.parse_place(args[0])?,
+                    target: self.parse_block(args[1])?,
+                    unwind: None,
+                })
+            },
+            @call("mir_drop_and_replace", args) => {
+                Ok(TerminatorKind::DropAndReplace {
+                    place: self.parse_place(args[0])?,
+                    value: self.parse_operand(args[1])?,
+                    target: self.parse_block(args[2])?,
+                    unwind: None,
+                })
+            },
+            @call("mir_call", args) => {
+                let destination = self.parse_place(args[0])?;
+                let target = self.parse_block(args[1])?;
+                self.parse_call(args[2], destination, target)
+            },
+            ExprKind::Match { scrutinee, arms } => {
+                let discr = self.parse_operand(*scrutinee)?;
+                self.parse_match(arms, expr.span).map(|t| TerminatorKind::SwitchInt { discr, targets: t })
+            },
+        )
+    }
+
+    fn parse_match(&self, arms: &[ArmId], span: Span) -> PResult<SwitchTargets> {
+        let Some((otherwise, rest)) = arms.split_last() else {
+            return Err(ParseError {
+                span,
+                item_description: "no arms".to_string(),
+                expected: "at least one arm".to_string(),
+            })
+        };
+
+        let otherwise = &self.thir[*otherwise];
+        let PatKind::Wild = otherwise.pattern.kind else {
+            return Err(ParseError {
+                span: otherwise.span,
+                item_description: format!("{:?}", otherwise.pattern.kind),
+                expected: "wildcard pattern".to_string(),
+            })
+        };
+        let otherwise = self.parse_block(otherwise.body)?;
+
+        let mut values = Vec::new();
+        let mut targets = Vec::new();
+        for arm in rest {
+            let arm = &self.thir[*arm];
+            let PatKind::Constant { value } = arm.pattern.kind else {
+                return Err(ParseError {
+                    span: arm.pattern.span,
+                    item_description: format!("{:?}", arm.pattern.kind),
+                    expected: "constant pattern".to_string(),
+                })
+            };
+            values.push(value.eval_bits(self.tcx, self.param_env, arm.pattern.ty));
+            targets.push(self.parse_block(arm.body)?);
+        }
+
+        Ok(SwitchTargets::new(values.into_iter().zip(targets), otherwise))
+    }
+
+    fn parse_call(
+        &self,
+        expr_id: ExprId,
+        destination: Place<'tcx>,
+        target: BasicBlock,
+    ) -> PResult<TerminatorKind<'tcx>> {
+        parse_by_kind!(self, expr_id, _, "function call",
+            ExprKind::Call { fun, args, from_hir_call, fn_span, .. } => {
+                let fun = self.parse_operand(*fun)?;
+                let args = args
+                    .iter()
+                    .map(|arg| self.parse_operand(*arg))
+                    .collect::<PResult<Vec<_>>>()?;
+                Ok(TerminatorKind::Call {
+                    func: fun,
+                    args,
+                    destination,
+                    target: Some(target),
+                    cleanup: None,
+                    from_hir_call: *from_hir_call,
+                    fn_span: *fn_span,
+                })
+            },
         )
     }
 
     fn parse_rvalue(&self, expr_id: ExprId) -> PResult<Rvalue<'tcx>> {
         parse_by_kind!(self, expr_id, _, "rvalue",
+            @call("mir_discriminant", args) => self.parse_place(args[0]).map(Rvalue::Discriminant),
             ExprKind::Borrow { borrow_kind, arg } => Ok(
                 Rvalue::Ref(self.tcx.lifetimes.re_erased, *borrow_kind, self.parse_place(*arg)?)
             ),
@@ -55,7 +160,7 @@ fn parse_operand(&self, expr_id: ExprId) -> PResult<Operand<'tcx>> {
             | ExprKind::ConstParam { .. }
             | ExprKind::ConstBlock { .. } => {
                 Ok(Operand::Constant(Box::new(
-                    crate::build::expr::as_constant::as_constant_inner(expr, |_| None, self.tcx)
+                    as_constant_inner(expr, |_| None, self.tcx)
                 )))
             },
             _ => self.parse_place(expr_id).map(Operand::Copy),
@@ -63,12 +168,42 @@ fn parse_operand(&self, expr_id: ExprId) -> PResult<Operand<'tcx>> {
     }
 
     fn parse_place(&self, expr_id: ExprId) -> PResult<Place<'tcx>> {
-        parse_by_kind!(self, expr_id, _, "place",
-            ExprKind::Deref { arg } => Ok(
-                self.parse_place(*arg)?.project_deeper(&[PlaceElem::Deref], self.tcx)
-            ),
-            _ => self.parse_local(expr_id).map(Place::from),
-        )
+        self.parse_place_inner(expr_id).map(|(x, _)| x)
+    }
+
+    fn parse_place_inner(&self, expr_id: ExprId) -> PResult<(Place<'tcx>, PlaceTy<'tcx>)> {
+        let (parent, proj) = parse_by_kind!(self, expr_id, expr, "place",
+            @call("mir_field", args) => {
+                let (parent, ty) = self.parse_place_inner(args[0])?;
+                let field = Field::from_u32(self.parse_integer_literal(args[1])? as u32);
+                let field_ty = ty.field_ty(self.tcx, field);
+                let proj = PlaceElem::Field(field, field_ty);
+                let place = parent.project_deeper(&[proj], self.tcx);
+                return Ok((place, PlaceTy::from_ty(field_ty)));
+            },
+            @call("mir_variant", args) => {
+                (args[0], PlaceElem::Downcast(
+                    None,
+                    VariantIdx::from_u32(self.parse_integer_literal(args[1])? as u32)
+                ))
+            },
+            ExprKind::Deref { arg } => {
+                parse_by_kind!(self, *arg, _, "does not matter",
+                    @call("mir_make_place", args) => return self.parse_place_inner(args[0]),
+                    _ => (*arg, PlaceElem::Deref),
+                )
+            },
+            ExprKind::Index { lhs, index } => (*lhs, PlaceElem::Index(self.parse_local(*index)?)),
+            ExprKind::Field { lhs, name: field, .. } => (*lhs, PlaceElem::Field(*field, expr.ty)),
+            _ => {
+                let place = self.parse_local(expr_id).map(Place::from)?;
+                return Ok((place, PlaceTy::from_ty(expr.ty)))
+            },
+        );
+        let (parent, ty) = self.parse_place_inner(parent)?;
+        let place = parent.project_deeper(&[proj], self.tcx);
+        let ty = ty.projection_ty(self.tcx, proj);
+        Ok((place, ty))
     }
 
     fn parse_local(&self, expr_id: ExprId) -> PResult<Local> {
@@ -102,4 +237,16 @@ fn parse_static(&self, expr_id: ExprId) -> PResult<Operand<'tcx>> {
             },
         )
     }
+
+    fn parse_integer_literal(&self, expr_id: ExprId) -> PResult<u128> {
+        parse_by_kind!(self, expr_id, expr, "constant",
+            ExprKind::Literal { .. }
+            | ExprKind::NamedConst { .. }
+            | ExprKind::NonHirLiteral { .. }
+            | ExprKind::ConstBlock { .. } => Ok({
+                let value = as_constant_inner(expr, |_| None, self.tcx);
+                value.literal.eval_bits(self.tcx, self.param_env, value.ty())
+            }),
+        )
+    }
 }
index 3b7ed818dc9b7eb7cd88630d60e63e0fa86ad22d..1d96893c7a3ea966aecc4852e79ea01fba386200 100644 (file)
@@ -66,14 +66,14 @@ pub fn as_constant_inner<'tcx>(
 
             let literal = ConstantKind::Val(ConstValue::Scalar(Scalar::Int(lit)), ty);
 
-            Constant { span, user_ty: user_ty, literal }
+            Constant { span, user_ty, literal }
         }
         ExprKind::ZstLiteral { ref user_ty } => {
             let user_ty = user_ty.as_ref().map(push_cuta).flatten();
 
             let literal = ConstantKind::Val(ConstValue::ZeroSized, ty);
 
-            Constant { span, user_ty: user_ty, literal }
+            Constant { span, user_ty, literal }
         }
         ExprKind::NamedConst { def_id, substs, ref user_ty } => {
             let user_ty = user_ty.as_ref().map(push_cuta).flatten();
index 7edcd46a34f293a542e1f2df59bc6f55f07a7bce..f90aba80bf3cf574f17fb3b0571cac22b5b4d6d2 100644 (file)
@@ -2210,7 +2210,7 @@ fn declare_binding(
             BindingMode::ByValue => ty::BindingMode::BindByValue(mutability),
             BindingMode::ByRef(_) => ty::BindingMode::BindByReference(mutability),
         };
-        let local = LocalDecl::<'tcx> {
+        let local = LocalDecl {
             mutability,
             ty: var_ty,
             user_ty: if user_ty.is_empty() { None } else { Some(Box::new(user_ty)) },
index de6a48f7cc411c4c7afb830f729c5bcb95227dfe..46e14cc9ac3b10667b9b5a5c2b19e9f40af71655 100644 (file)
@@ -551,16 +551,15 @@ pub(super) fn sort_candidate<'pat>(
             //
             // FIXME(#29623) we could use PatKind::Range to rule
             // things out here, in some cases.
-            (
-                &TestKind::SwitchInt { switch_ty: _, ref options },
-                &PatKind::Constant { ref value },
-            ) if is_switch_ty(match_pair.pattern.ty) => {
+            (TestKind::SwitchInt { switch_ty: _, options }, PatKind::Constant { value })
+                if is_switch_ty(match_pair.pattern.ty) =>
+            {
                 let index = options.get_index_of(value).unwrap();
                 self.candidate_without_match_pair(match_pair_index, candidate);
                 Some(index)
             }
 
-            (&TestKind::SwitchInt { switch_ty: _, ref options }, &PatKind::Range(ref range)) => {
+            (TestKind::SwitchInt { switch_ty: _, options }, PatKind::Range(range)) => {
                 let not_contained =
                     self.values_not_contained_in_range(&*range, options).unwrap_or(false);
 
@@ -578,7 +577,7 @@ pub(super) fn sort_candidate<'pat>(
 
             (
                 &TestKind::Len { len: test_len, op: BinOp::Eq },
-                &PatKind::Slice { ref prefix, ref slice, ref suffix },
+                PatKind::Slice { prefix, slice, suffix },
             ) => {
                 let pat_len = (prefix.len() + suffix.len()) as u64;
                 match (test_len.cmp(&pat_len), slice) {
@@ -615,7 +614,7 @@ pub(super) fn sort_candidate<'pat>(
 
             (
                 &TestKind::Len { len: test_len, op: BinOp::Ge },
-                &PatKind::Slice { ref prefix, ref slice, ref suffix },
+                PatKind::Slice { prefix, slice, suffix },
             ) => {
                 // the test is `$actual_len >= test_len`
                 let pat_len = (prefix.len() + suffix.len()) as u64;
@@ -651,7 +650,7 @@ pub(super) fn sort_candidate<'pat>(
                 }
             }
 
-            (&TestKind::Range(ref test), &PatKind::Range(ref pat)) => {
+            (TestKind::Range(test), PatKind::Range(pat)) => {
                 use std::cmp::Ordering::*;
 
                 if test == pat {
@@ -678,7 +677,7 @@ pub(super) fn sort_candidate<'pat>(
                 no_overlap
             }
 
-            (&TestKind::Range(ref range), &PatKind::Constant { value }) => {
+            (TestKind::Range(range), &PatKind::Constant { value }) => {
                 if let Some(false) = self.const_range_contains(&*range, value) {
                     // `value` is not contained in the testing range,
                     // so `value` can be matched only if this test fails.
index 7af89dd472f88e9be4ccf03111f2ad525d870d7c..c785dfb500fc9f93d95b6d6beef972391f0ad6d1 100644 (file)
@@ -372,7 +372,7 @@ struct CFG<'tcx> {
 }
 
 rustc_index::newtype_index! {
-    struct ScopeId { .. }
+    struct ScopeId {}
 }
 
 #[derive(Debug)]
index 33f49ffdaf6403fd4ae06a43b763e86789ab567b..c92634a609de0f762df392231779f6510bc5a72e 100644 (file)
@@ -185,7 +185,7 @@ pub(crate) enum BreakableTarget {
 }
 
 rustc_index::newtype_index! {
-    struct DropIdx { .. }
+    struct DropIdx {}
 }
 
 const ROOT_NODE: DropIdx = DropIdx::from_u32(0);
index 3bb1f51650abd5c846acad632a7e649099f4559f..99e96ff77ced9bff4c0ab710e1db1fafc01ebb66 100644 (file)
@@ -1,7 +1,7 @@
 use crate::build::ExprCategory;
+use crate::errors::*;
 use rustc_middle::thir::visit::{self, Visitor};
 
-use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_middle::mir::BorrowKind;
 use rustc_middle::thir::*;
@@ -12,7 +12,6 @@
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
 
-use std::borrow::Cow;
 use std::ops::Bound;
 
 struct UnsafetyVisitor<'a, 'tcx> {
@@ -46,7 +45,9 @@ fn in_safety_context(&mut self, safety_context: SafetyContext, f: impl FnOnce(&m
             self.warn_unused_unsafe(
                 hir_id,
                 block_span,
-                Some((self.tcx.sess.source_map().guess_head_span(enclosing_span), "block")),
+                Some(UnusedUnsafeEnclosing::Block {
+                    span: self.tcx.sess.source_map().guess_head_span(enclosing_span),
+                }),
             );
             f(self);
         } else {
@@ -60,7 +61,9 @@ fn in_safety_context(&mut self, safety_context: SafetyContext, f: impl FnOnce(&m
                     hir_id,
                     span,
                     if self.unsafe_op_in_unsafe_fn_allowed() {
-                        self.body_unsafety.unsafe_fn_sig_span().map(|span| (span, "fn"))
+                        self.body_unsafety
+                            .unsafe_fn_sig_span()
+                            .map(|span| UnusedUnsafeEnclosing::Function { span })
                     } else {
                         None
                     },
@@ -83,30 +86,11 @@ fn requires_unsafe(&mut self, span: Span, kind: UnsafeOpKind) {
             }
             SafetyContext::UnsafeFn if unsafe_op_in_unsafe_fn_allowed => {}
             SafetyContext::UnsafeFn => {
-                let (description, note) = kind.description_and_note(self.tcx);
                 // unsafe_op_in_unsafe_fn is disallowed
-                self.tcx.struct_span_lint_hir(
-                    UNSAFE_OP_IN_UNSAFE_FN,
-                    self.hir_context,
-                    span,
-                    format!("{} is unsafe and requires unsafe block (error E0133)", description,),
-                    |lint| lint.span_label(span, kind.simple_description()).note(note),
-                )
+                kind.emit_unsafe_op_in_unsafe_fn_lint(self.tcx, self.hir_context, span);
             }
             SafetyContext::Safe => {
-                let (description, note) = kind.description_and_note(self.tcx);
-                let fn_sugg = if unsafe_op_in_unsafe_fn_allowed { " function or" } else { "" };
-                struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0133,
-                    "{} is unsafe and requires unsafe{} block",
-                    description,
-                    fn_sugg,
-                )
-                .span_label(span, kind.simple_description())
-                .note(note)
-                .emit();
+                kind.emit_requires_unsafe_err(self.tcx, span, unsafe_op_in_unsafe_fn_allowed);
             }
         }
     }
@@ -115,17 +99,15 @@ fn warn_unused_unsafe(
         &self,
         hir_id: hir::HirId,
         block_span: Span,
-        enclosing_unsafe: Option<(Span, &'static str)>,
+        enclosing_unsafe: Option<UnusedUnsafeEnclosing>,
     ) {
         let block_span = self.tcx.sess.source_map().guess_head_span(block_span);
-        let msg = "unnecessary `unsafe` block";
-        self.tcx.struct_span_lint_hir(UNUSED_UNSAFE, hir_id, block_span, msg, |lint| {
-            lint.span_label(block_span, msg);
-            if let Some((span, kind)) = enclosing_unsafe {
-                lint.span_label(span, format!("because it's nested under this `unsafe` {}", kind));
-            }
-            lint
-        });
+        self.tcx.emit_spanned_lint(
+            UNUSED_UNSAFE,
+            hir_id,
+            block_span,
+            UnusedUnsafe { span: block_span, enclosing: enclosing_unsafe },
+        );
     }
 
     /// Whether the `unsafe_op_in_unsafe_fn` lint is `allow`ed at the current HIR node.
@@ -536,81 +518,189 @@ enum UnsafeOpKind {
 use UnsafeOpKind::*;
 
 impl UnsafeOpKind {
-    pub fn simple_description(&self) -> &'static str {
-        match self {
-            CallToUnsafeFunction(..) => "call to unsafe function",
-            UseOfInlineAssembly => "use of inline assembly",
-            InitializingTypeWith => "initializing type with `rustc_layout_scalar_valid_range` attr",
-            UseOfMutableStatic => "use of mutable static",
-            UseOfExternStatic => "use of extern static",
-            DerefOfRawPointer => "dereference of raw pointer",
-            AccessToUnionField => "access to union field",
-            MutationOfLayoutConstrainedField => "mutation of layout constrained field",
-            BorrowOfLayoutConstrainedField => {
-                "borrow of layout constrained field with interior mutability"
-            }
-            CallToFunctionWith(..) => "call to function with `#[target_feature]`",
-        }
-    }
-
-    pub fn description_and_note(&self, tcx: TyCtxt<'_>) -> (Cow<'static, str>, &'static str) {
+    pub fn emit_unsafe_op_in_unsafe_fn_lint(
+        &self,
+        tcx: TyCtxt<'_>,
+        hir_id: hir::HirId,
+        span: Span,
+    ) {
         match self {
-            CallToUnsafeFunction(did) => (
-                if let Some(did) = did {
-                    Cow::from(format!("call to unsafe function `{}`", tcx.def_path_str(*did)))
-                } else {
-                    Cow::Borrowed(self.simple_description())
+            CallToUnsafeFunction(did) if did.is_some() => tcx.emit_spanned_lint(
+                UNSAFE_OP_IN_UNSAFE_FN,
+                hir_id,
+                span,
+                UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafe {
+                    span,
+                    function: &tcx.def_path_str(did.unwrap()),
                 },
-                "consult the function's documentation for information on how to avoid undefined \
-                 behavior",
             ),
-            UseOfInlineAssembly => (
-                Cow::Borrowed(self.simple_description()),
-                "inline assembly is entirely unchecked and can cause undefined behavior",
+            CallToUnsafeFunction(..) => tcx.emit_spanned_lint(
+                UNSAFE_OP_IN_UNSAFE_FN,
+                hir_id,
+                span,
+                UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafeNameless { span },
+            ),
+            UseOfInlineAssembly => tcx.emit_spanned_lint(
+                UNSAFE_OP_IN_UNSAFE_FN,
+                hir_id,
+                span,
+                UnsafeOpInUnsafeFnUseOfInlineAssemblyRequiresUnsafe { span },
             ),
-            InitializingTypeWith => (
-                Cow::Borrowed(self.simple_description()),
-                "initializing a layout restricted type's field with a value outside the valid \
-                 range is undefined behavior",
+            InitializingTypeWith => tcx.emit_spanned_lint(
+                UNSAFE_OP_IN_UNSAFE_FN,
+                hir_id,
+                span,
+                UnsafeOpInUnsafeFnInitializingTypeWithRequiresUnsafe { span },
             ),
-            UseOfMutableStatic => (
-                Cow::Borrowed(self.simple_description()),
-                "mutable statics can be mutated by multiple threads: aliasing violations or data \
-                 races will cause undefined behavior",
+            UseOfMutableStatic => tcx.emit_spanned_lint(
+                UNSAFE_OP_IN_UNSAFE_FN,
+                hir_id,
+                span,
+                UnsafeOpInUnsafeFnUseOfMutableStaticRequiresUnsafe { span },
             ),
-            UseOfExternStatic => (
-                Cow::Borrowed(self.simple_description()),
-                "extern statics are not controlled by the Rust type system: invalid data, \
-                 aliasing violations or data races will cause undefined behavior",
+            UseOfExternStatic => tcx.emit_spanned_lint(
+                UNSAFE_OP_IN_UNSAFE_FN,
+                hir_id,
+                span,
+                UnsafeOpInUnsafeFnUseOfExternStaticRequiresUnsafe { span },
             ),
-            DerefOfRawPointer => (
-                Cow::Borrowed(self.simple_description()),
-                "raw pointers may be null, dangling or unaligned; they can violate aliasing rules \
-                 and cause data races: all of these are undefined behavior",
+            DerefOfRawPointer => tcx.emit_spanned_lint(
+                UNSAFE_OP_IN_UNSAFE_FN,
+                hir_id,
+                span,
+                UnsafeOpInUnsafeFnDerefOfRawPointerRequiresUnsafe { span },
             ),
-            AccessToUnionField => (
-                Cow::Borrowed(self.simple_description()),
-                "the field may not be properly initialized: using uninitialized data will cause \
-                 undefined behavior",
+            AccessToUnionField => tcx.emit_spanned_lint(
+                UNSAFE_OP_IN_UNSAFE_FN,
+                hir_id,
+                span,
+                UnsafeOpInUnsafeFnAccessToUnionFieldRequiresUnsafe { span },
             ),
-            MutationOfLayoutConstrainedField => (
-                Cow::Borrowed(self.simple_description()),
-                "mutating layout constrained fields cannot statically be checked for valid values",
+            MutationOfLayoutConstrainedField => tcx.emit_spanned_lint(
+                UNSAFE_OP_IN_UNSAFE_FN,
+                hir_id,
+                span,
+                UnsafeOpInUnsafeFnMutationOfLayoutConstrainedFieldRequiresUnsafe { span },
             ),
-            BorrowOfLayoutConstrainedField => (
-                Cow::Borrowed(self.simple_description()),
-                "references to fields of layout constrained fields lose the constraints. Coupled \
-                 with interior mutability, the field can be changed to invalid values",
+            BorrowOfLayoutConstrainedField => tcx.emit_spanned_lint(
+                UNSAFE_OP_IN_UNSAFE_FN,
+                hir_id,
+                span,
+                UnsafeOpInUnsafeFnBorrowOfLayoutConstrainedFieldRequiresUnsafe { span },
             ),
-            CallToFunctionWith(did) => (
-                Cow::from(format!(
-                    "call to function `{}` with `#[target_feature]`",
-                    tcx.def_path_str(*did)
-                )),
-                "can only be called if the required target features are available",
+            CallToFunctionWith(did) => tcx.emit_spanned_lint(
+                UNSAFE_OP_IN_UNSAFE_FN,
+                hir_id,
+                span,
+                UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe {
+                    span,
+                    function: &tcx.def_path_str(*did),
+                },
             ),
         }
     }
+
+    pub fn emit_requires_unsafe_err(
+        &self,
+        tcx: TyCtxt<'_>,
+        span: Span,
+        unsafe_op_in_unsafe_fn_allowed: bool,
+    ) {
+        match self {
+            CallToUnsafeFunction(did) if did.is_some() && unsafe_op_in_unsafe_fn_allowed => {
+                tcx.sess.emit_err(CallToUnsafeFunctionRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+                    span,
+                    function: &tcx.def_path_str(did.unwrap()),
+                });
+            }
+            CallToUnsafeFunction(did) if did.is_some() => {
+                tcx.sess.emit_err(CallToUnsafeFunctionRequiresUnsafe {
+                    span,
+                    function: &tcx.def_path_str(did.unwrap()),
+                });
+            }
+            CallToUnsafeFunction(..) if unsafe_op_in_unsafe_fn_allowed => {
+                tcx.sess.emit_err(
+                    CallToUnsafeFunctionRequiresUnsafeNamelessUnsafeOpInUnsafeFnAllowed { span },
+                );
+            }
+            CallToUnsafeFunction(..) => {
+                tcx.sess.emit_err(CallToUnsafeFunctionRequiresUnsafeNameless { span });
+            }
+            UseOfInlineAssembly if unsafe_op_in_unsafe_fn_allowed => {
+                tcx.sess
+                    .emit_err(UseOfInlineAssemblyRequiresUnsafeUnsafeOpInUnsafeFnAllowed { span });
+            }
+            UseOfInlineAssembly => {
+                tcx.sess.emit_err(UseOfInlineAssemblyRequiresUnsafe { span });
+            }
+            InitializingTypeWith if unsafe_op_in_unsafe_fn_allowed => {
+                tcx.sess
+                    .emit_err(InitializingTypeWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed { span });
+            }
+            InitializingTypeWith => {
+                tcx.sess.emit_err(InitializingTypeWithRequiresUnsafe { span });
+            }
+            UseOfMutableStatic if unsafe_op_in_unsafe_fn_allowed => {
+                tcx.sess
+                    .emit_err(UseOfMutableStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed { span });
+            }
+            UseOfMutableStatic => {
+                tcx.sess.emit_err(UseOfMutableStaticRequiresUnsafe { span });
+            }
+            UseOfExternStatic if unsafe_op_in_unsafe_fn_allowed => {
+                tcx.sess
+                    .emit_err(UseOfExternStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed { span });
+            }
+            UseOfExternStatic => {
+                tcx.sess.emit_err(UseOfExternStaticRequiresUnsafe { span });
+            }
+            DerefOfRawPointer if unsafe_op_in_unsafe_fn_allowed => {
+                tcx.sess
+                    .emit_err(DerefOfRawPointerRequiresUnsafeUnsafeOpInUnsafeFnAllowed { span });
+            }
+            DerefOfRawPointer => {
+                tcx.sess.emit_err(DerefOfRawPointerRequiresUnsafe { span });
+            }
+            AccessToUnionField if unsafe_op_in_unsafe_fn_allowed => {
+                tcx.sess
+                    .emit_err(AccessToUnionFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed { span });
+            }
+            AccessToUnionField => {
+                tcx.sess.emit_err(AccessToUnionFieldRequiresUnsafe { span });
+            }
+            MutationOfLayoutConstrainedField if unsafe_op_in_unsafe_fn_allowed => {
+                tcx.sess.emit_err(
+                    MutationOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+                        span,
+                    },
+                );
+            }
+            MutationOfLayoutConstrainedField => {
+                tcx.sess.emit_err(MutationOfLayoutConstrainedFieldRequiresUnsafe { span });
+            }
+            BorrowOfLayoutConstrainedField if unsafe_op_in_unsafe_fn_allowed => {
+                tcx.sess.emit_err(
+                    BorrowOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed { span },
+                );
+            }
+            BorrowOfLayoutConstrainedField => {
+                tcx.sess.emit_err(BorrowOfLayoutConstrainedFieldRequiresUnsafe { span });
+            }
+            CallToFunctionWith(did) if unsafe_op_in_unsafe_fn_allowed => {
+                tcx.sess.emit_err(CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+                    span,
+                    function: &tcx.def_path_str(*did),
+                });
+            }
+            CallToFunctionWith(did) => {
+                tcx.sess.emit_err(CallToFunctionWithRequiresUnsafe {
+                    span,
+                    function: &tcx.def_path_str(*did),
+                });
+            }
+        }
+    }
 }
 
 pub fn check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam<LocalDefId>) {
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
new file mode 100644 (file)
index 0000000..6817900
--- /dev/null
@@ -0,0 +1,616 @@
+use crate::thir::pattern::MatchCheckCtxt;
+use rustc_errors::Handler;
+use rustc_errors::{
+    error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, MultiSpan,
+};
+use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
+use rustc_middle::ty::{self, Ty};
+use rustc_span::{symbol::Ident, Span};
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_unconditional_recursion)]
+#[help]
+pub struct UnconditionalRecursion {
+    #[label]
+    pub span: Span,
+    #[label(mir_build_unconditional_recursion_call_site_label)]
+    pub call_sites: Vec<Span>,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe)]
+#[note]
+pub struct UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafe<'a> {
+    #[label]
+    pub span: Span,
+    pub function: &'a str,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe_nameless)]
+#[note]
+pub struct UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafeNameless {
+    #[label]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_unsafe_op_in_unsafe_fn_inline_assembly_requires_unsafe)]
+#[note]
+pub struct UnsafeOpInUnsafeFnUseOfInlineAssemblyRequiresUnsafe {
+    #[label]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_unsafe_op_in_unsafe_fn_initializing_type_with_requires_unsafe)]
+#[note]
+pub struct UnsafeOpInUnsafeFnInitializingTypeWithRequiresUnsafe {
+    #[label]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_unsafe_op_in_unsafe_fn_mutable_static_requires_unsafe)]
+#[note]
+pub struct UnsafeOpInUnsafeFnUseOfMutableStaticRequiresUnsafe {
+    #[label]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_unsafe_op_in_unsafe_fn_extern_static_requires_unsafe)]
+#[note]
+pub struct UnsafeOpInUnsafeFnUseOfExternStaticRequiresUnsafe {
+    #[label]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_unsafe_op_in_unsafe_fn_deref_raw_pointer_requires_unsafe)]
+#[note]
+pub struct UnsafeOpInUnsafeFnDerefOfRawPointerRequiresUnsafe {
+    #[label]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_unsafe_op_in_unsafe_fn_union_field_requires_unsafe)]
+#[note]
+pub struct UnsafeOpInUnsafeFnAccessToUnionFieldRequiresUnsafe {
+    #[label]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_unsafe_op_in_unsafe_fn_mutation_of_layout_constrained_field_requires_unsafe)]
+#[note]
+pub struct UnsafeOpInUnsafeFnMutationOfLayoutConstrainedFieldRequiresUnsafe {
+    #[label]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_unsafe_op_in_unsafe_fn_borrow_of_layout_constrained_field_requires_unsafe)]
+pub struct UnsafeOpInUnsafeFnBorrowOfLayoutConstrainedFieldRequiresUnsafe {
+    #[label]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_unsafe_op_in_unsafe_fn_call_to_fn_with_requires_unsafe)]
+#[note]
+pub struct UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe<'a> {
+    #[label]
+    pub span: Span,
+    pub function: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_call_to_unsafe_fn_requires_unsafe, code = "E0133")]
+#[note]
+pub struct CallToUnsafeFunctionRequiresUnsafe<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub function: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_call_to_unsafe_fn_requires_unsafe_nameless, code = "E0133")]
+#[note]
+pub struct CallToUnsafeFunctionRequiresUnsafeNameless {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_call_to_unsafe_fn_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
+#[note]
+pub struct CallToUnsafeFunctionRequiresUnsafeUnsafeOpInUnsafeFnAllowed<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub function: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(
+    mir_build_call_to_unsafe_fn_requires_unsafe_nameless_unsafe_op_in_unsafe_fn_allowed,
+    code = "E0133"
+)]
+#[note]
+pub struct CallToUnsafeFunctionRequiresUnsafeNamelessUnsafeOpInUnsafeFnAllowed {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_inline_assembly_requires_unsafe, code = "E0133")]
+#[note]
+pub struct UseOfInlineAssemblyRequiresUnsafe {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_inline_assembly_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
+#[note]
+pub struct UseOfInlineAssemblyRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_initializing_type_with_requires_unsafe, code = "E0133")]
+#[note]
+pub struct InitializingTypeWithRequiresUnsafe {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(
+    mir_build_initializing_type_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed,
+    code = "E0133"
+)]
+#[note]
+pub struct InitializingTypeWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_mutable_static_requires_unsafe, code = "E0133")]
+#[note]
+pub struct UseOfMutableStaticRequiresUnsafe {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_mutable_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
+#[note]
+pub struct UseOfMutableStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_extern_static_requires_unsafe, code = "E0133")]
+#[note]
+pub struct UseOfExternStaticRequiresUnsafe {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_extern_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
+#[note]
+pub struct UseOfExternStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_deref_raw_pointer_requires_unsafe, code = "E0133")]
+#[note]
+pub struct DerefOfRawPointerRequiresUnsafe {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_deref_raw_pointer_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
+#[note]
+pub struct DerefOfRawPointerRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_union_field_requires_unsafe, code = "E0133")]
+#[note]
+pub struct AccessToUnionFieldRequiresUnsafe {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_union_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
+#[note]
+pub struct AccessToUnionFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_mutation_of_layout_constrained_field_requires_unsafe, code = "E0133")]
+#[note]
+pub struct MutationOfLayoutConstrainedFieldRequiresUnsafe {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(
+    mir_build_mutation_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed,
+    code = "E0133"
+)]
+#[note]
+pub struct MutationOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_borrow_of_layout_constrained_field_requires_unsafe, code = "E0133")]
+#[note]
+pub struct BorrowOfLayoutConstrainedFieldRequiresUnsafe {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(
+    mir_build_borrow_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed,
+    code = "E0133"
+)]
+#[note]
+pub struct BorrowOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_call_to_fn_with_requires_unsafe, code = "E0133")]
+#[note]
+pub struct CallToFunctionWithRequiresUnsafe<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub function: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_call_to_fn_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
+#[note]
+pub struct CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub function: &'a str,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_unused_unsafe)]
+pub struct UnusedUnsafe {
+    #[label]
+    pub span: Span,
+    #[subdiagnostic]
+    pub enclosing: Option<UnusedUnsafeEnclosing>,
+}
+
+#[derive(Subdiagnostic)]
+pub enum UnusedUnsafeEnclosing {
+    #[label(mir_build_unused_unsafe_enclosing_block_label)]
+    Block {
+        #[primary_span]
+        span: Span,
+    },
+    #[label(mir_build_unused_unsafe_enclosing_fn_label)]
+    Function {
+        #[primary_span]
+        span: Span,
+    },
+}
+
+pub(crate) struct NonExhaustivePatternsTypeNotEmpty<'p, 'tcx, 'm> {
+    pub cx: &'m MatchCheckCtxt<'p, 'tcx>,
+    pub expr_span: Span,
+    pub span: Span,
+    pub ty: Ty<'tcx>,
+}
+
+impl<'a> IntoDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> {
+    fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
+        let mut diag = handler.struct_span_err_with_code(
+            self.span,
+            rustc_errors::fluent::mir_build_non_exhaustive_patterns_type_not_empty,
+            error_code!(E0004),
+        );
+
+        let peeled_ty = self.ty.peel_refs();
+        diag.set_arg("ty", self.ty);
+        diag.set_arg("peeled_ty", peeled_ty);
+
+        if let ty::Adt(def, _) = peeled_ty.kind() {
+            let def_span = self
+                .cx
+                .tcx
+                .hir()
+                .get_if_local(def.did())
+                .and_then(|node| node.ident())
+                .map(|ident| ident.span)
+                .unwrap_or_else(|| self.cx.tcx.def_span(def.did()));
+
+            // workaround to make test pass
+            let mut span: MultiSpan = def_span.into();
+            span.push_span_label(def_span, "");
+
+            diag.span_note(span, rustc_errors::fluent::def_note);
+        }
+
+        let is_variant_list_non_exhaustive = match self.ty.kind() {
+            ty::Adt(def, _) if def.is_variant_list_non_exhaustive() && !def.did().is_local() => {
+                true
+            }
+            _ => false,
+        };
+
+        if is_variant_list_non_exhaustive {
+            diag.note(rustc_errors::fluent::non_exhaustive_type_note);
+        } else {
+            diag.note(rustc_errors::fluent::type_note);
+        }
+
+        if let ty::Ref(_, sub_ty, _) = self.ty.kind() {
+            if !sub_ty.is_inhabited_from(self.cx.tcx, self.cx.module, self.cx.param_env) {
+                diag.note(rustc_errors::fluent::reference_note);
+            }
+        }
+
+        let mut suggestion = None;
+        let sm = self.cx.tcx.sess.source_map();
+        if self.span.eq_ctxt(self.expr_span) {
+            // Get the span for the empty match body `{}`.
+            let (indentation, more) = if let Some(snippet) = sm.indentation_before(self.span) {
+                (format!("\n{}", snippet), "    ")
+            } else {
+                (" ".to_string(), "")
+            };
+            suggestion = Some((
+                self.span.shrink_to_hi().with_hi(self.expr_span.hi()),
+                format!(
+                    " {{{indentation}{more}_ => todo!(),{indentation}}}",
+                    indentation = indentation,
+                    more = more,
+                ),
+            ));
+        }
+
+        if let Some((span, sugg)) = suggestion {
+            diag.span_suggestion_verbose(
+                span,
+                rustc_errors::fluent::suggestion,
+                sugg,
+                Applicability::HasPlaceholders,
+            );
+        } else {
+            diag.help(rustc_errors::fluent::help);
+        }
+
+        diag
+    }
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_static_in_pattern, code = "E0158")]
+pub struct StaticInPattern {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_assoc_const_in_pattern, code = "E0158")]
+pub struct AssocConstInPattern {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_const_param_in_pattern, code = "E0158")]
+pub struct ConstParamInPattern {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_non_const_path, code = "E0080")]
+pub struct NonConstPath {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_unreachable_pattern)]
+pub struct UnreachablePattern {
+    #[label]
+    pub span: Option<Span>,
+    #[label(catchall_label)]
+    pub catchall: Option<Span>,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_const_pattern_depends_on_generic_parameter)]
+pub struct ConstPatternDependsOnGenericParameter {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_could_not_eval_const_pattern)]
+pub struct CouldNotEvalConstPattern {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_lower_range_bound_must_be_less_than_or_equal_to_upper, code = "E0030")]
+pub struct LowerRangeBoundMustBeLessThanOrEqualToUpper {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[note(teach_note)]
+    pub teach: Option<()>,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_lower_range_bound_must_be_less_than_upper, code = "E0579")]
+pub struct LowerRangeBoundMustBeLessThanUpper {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_leading_irrefutable_let_patterns)]
+#[note]
+#[help]
+pub struct LeadingIrrefutableLetPatterns {
+    pub count: usize,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_trailing_irrefutable_let_patterns)]
+#[note]
+#[help]
+pub struct TrailingIrrefutableLetPatterns {
+    pub count: usize,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_bindings_with_variant_name, code = "E0170")]
+pub struct BindingsWithVariantName {
+    #[suggestion(code = "{ty_path}::{ident}", applicability = "machine-applicable")]
+    pub suggestion: Option<Span>,
+    pub ty_path: String,
+    pub ident: Ident,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_irrefutable_let_patterns_generic_let)]
+#[note]
+#[help]
+pub struct IrrefutableLetPatternsGenericLet {
+    pub count: usize,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_irrefutable_let_patterns_if_let)]
+#[note]
+#[help]
+pub struct IrrefutableLetPatternsIfLet {
+    pub count: usize,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_irrefutable_let_patterns_if_let_guard)]
+#[note]
+#[help]
+pub struct IrrefutableLetPatternsIfLetGuard {
+    pub count: usize,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_irrefutable_let_patterns_let_else)]
+#[note]
+#[help]
+pub struct IrrefutableLetPatternsLetElse {
+    pub count: usize,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_irrefutable_let_patterns_while_let)]
+#[note]
+#[help]
+pub struct IrrefutableLetPatternsWhileLet {
+    pub count: usize,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_borrow_of_moved_value)]
+pub struct BorrowOfMovedValue<'tcx> {
+    #[primary_span]
+    pub span: Span,
+    #[label]
+    #[label(occurs_because_label)]
+    pub binding_span: Span,
+    #[label(value_borrowed_label)]
+    pub conflicts_ref: Vec<Span>,
+    pub name: Ident,
+    pub ty: Ty<'tcx>,
+    #[suggestion(code = "ref ", applicability = "machine-applicable")]
+    pub suggest_borrowing: Option<Span>,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_multiple_mut_borrows)]
+pub struct MultipleMutBorrows {
+    #[primary_span]
+    pub span: Span,
+    #[label]
+    pub binding_span: Span,
+    #[subdiagnostic]
+    pub occurences: Vec<MultipleMutBorrowOccurence>,
+    pub name: Ident,
+}
+
+#[derive(Subdiagnostic)]
+pub enum MultipleMutBorrowOccurence {
+    #[label(mutable_borrow)]
+    Mutable {
+        #[primary_span]
+        span: Span,
+        name_mut: Ident,
+    },
+    #[label(immutable_borrow)]
+    Immutable {
+        #[primary_span]
+        span: Span,
+        name_immut: Ident,
+    },
+    #[label(moved)]
+    Moved {
+        #[primary_span]
+        span: Span,
+        name_moved: Ident,
+    },
+}
index 8797529459534610bc479c57a9f8dc75cb023059..2b05e92fdcf20c0913e199bf11fdeeb591b73d8d 100644 (file)
@@ -19,6 +19,7 @@
 
 mod build;
 mod check_unsafety;
+mod errors;
 mod lints;
 pub mod thir;
 
index b21f30efce8076dcd993c481dd5f78cbe517e515..8529c64cd5cca64213f3b1efedb38df29c0094b5 100644 (file)
@@ -1,3 +1,4 @@
+use crate::errors::UnconditionalRecursion;
 use rustc_data_structures::graph::iterate::{
     NodeStatus, TriColorDepthFirstSearch, TriColorVisitor,
 };
@@ -36,19 +37,11 @@ pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
 
         let sp = tcx.def_span(def_id);
         let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-        tcx.struct_span_lint_hir(
+        tcx.emit_spanned_lint(
             UNCONDITIONAL_RECURSION,
             hir_id,
             sp,
-            "function cannot return without recursing",
-            |lint| {
-                lint.span_label(sp, "cannot return without recursing");
-                // offer some help to the programmer.
-                for call_span in vis.reachable_recursive_calls {
-                    lint.span_label(call_span, "recursive call site");
-                }
-                lint.help("a `loop` may express intention better if this is on purpose")
-            },
+            UnconditionalRecursion { span: sp, call_sites: vis.reachable_recursive_calls },
         );
     }
 }
index e369dba55242c8f1703b38120a99489ca2c80e0f..a94d8d6c6431c81c0d95e2f525d9cff0d8c12d08 100644 (file)
@@ -4,18 +4,22 @@
 };
 use super::{PatCtxt, PatternError};
 
+use crate::errors::*;
+
 use rustc_arena::TypedArena;
 use rustc_ast::Mutability;
 use rustc_errors::{
-    error_code, pluralize, struct_span_err, Applicability, DelayDm, Diagnostic, DiagnosticBuilder,
-    ErrorGuaranteed, MultiSpan,
+    pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
+    MultiSpan,
 };
 use rustc_hir as hir;
 use rustc_hir::def::*;
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{HirId, Pat};
+use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
+
 use rustc_session::lint::builtin::{
     BINDINGS_WITH_VARIANT_NAME, IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS,
 };
@@ -107,28 +111,20 @@ fn report_inlining_errors(&self) {
         for error in &self.errors {
             match *error {
                 PatternError::StaticInPattern(span) => {
-                    self.span_e0158(span, "statics cannot be referenced in patterns")
+                    self.tcx.sess.emit_err(StaticInPattern { span });
                 }
                 PatternError::AssocConstInPattern(span) => {
-                    self.span_e0158(span, "associated consts cannot be referenced in patterns")
+                    self.tcx.sess.emit_err(AssocConstInPattern { span });
                 }
                 PatternError::ConstParamInPattern(span) => {
-                    self.span_e0158(span, "const parameters cannot be referenced in patterns")
+                    self.tcx.sess.emit_err(ConstParamInPattern { span });
                 }
                 PatternError::NonConstPath(span) => {
-                    rustc_middle::mir::interpret::struct_error(
-                        self.tcx.at(span),
-                        "runtime values cannot be referenced in patterns",
-                    )
-                    .emit();
+                    self.tcx.sess.emit_err(NonConstPath { span });
                 }
             }
         }
     }
-
-    fn span_e0158(&self, span: Span, text: &str) {
-        struct_span_err!(self.tcx.sess, span, E0158, "{}", text).emit();
-    }
 }
 
 impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
@@ -345,29 +341,6 @@ fn check_let_chain(&mut self, cx: &mut MatchCheckCtxt<'p, 'tcx>, pat_id: HirId)
             );
             return true;
         }
-        let lint_affix = |affix: &[Option<(Span, bool)>], kind, suggestion| {
-            let span_start = affix[0].unwrap().0;
-            let span_end = affix.last().unwrap().unwrap().0;
-            let span = span_start.to(span_end);
-            let cnt = affix.len();
-            let s = pluralize!(cnt);
-            cx.tcx.struct_span_lint_hir(
-                IRREFUTABLE_LET_PATTERNS,
-                top,
-                span,
-                format!("{kind} irrefutable pattern{s} in let chain"),
-                |lint| {
-                    lint.note(format!(
-                        "{these} pattern{s} will always match",
-                        these = pluralize!("this", cnt),
-                    ))
-                    .help(format!(
-                        "consider moving {} {suggestion}",
-                        if cnt > 1 { "them" } else { "it" }
-                    ))
-                },
-            );
-        };
         if let Some(until) = chain_refutabilities.iter().position(|r| !matches!(*r, Some((_, false)))) && until > 0 {
             // The chain has a non-zero prefix of irrefutable `let` statements.
 
@@ -381,13 +354,21 @@ fn check_let_chain(&mut self, cx: &mut MatchCheckCtxt<'p, 'tcx>, pat_id: HirId)
             if !matches!(let_source, LetSource::WhileLet | LetSource::IfLetGuard) {
                 // Emit the lint
                 let prefix = &chain_refutabilities[..until];
-                lint_affix(prefix, "leading", "outside of the construct");
+                let span_start = prefix[0].unwrap().0;
+                let span_end = prefix.last().unwrap().unwrap().0;
+                let span = span_start.to(span_end);
+                let count = prefix.len();
+                cx.tcx.emit_spanned_lint(IRREFUTABLE_LET_PATTERNS, top, span, LeadingIrrefutableLetPatterns { count });
             }
         }
         if let Some(from) = chain_refutabilities.iter().rposition(|r| !matches!(*r, Some((_, false)))) && from != (chain_refutabilities.len() - 1) {
             // The chain has a non-empty suffix of irrefutable `let` statements
             let suffix = &chain_refutabilities[from + 1..];
-            lint_affix(suffix, "trailing", "into the body");
+            let span_start = suffix[0].unwrap().0;
+            let span_end = suffix.last().unwrap().unwrap().0;
+            let span = span_start.to(span_end);
+            let count = suffix.len();
+            cx.tcx.emit_spanned_lint(IRREFUTABLE_LET_PATTERNS, top, span, TrailingIrrefutableLetPatterns { count });
         }
         true
     }
@@ -568,32 +549,22 @@ fn check_for_bindings_named_same_as_variants(
             })
         {
             let variant_count = edef.variants().len();
-            cx.tcx.struct_span_lint_hir(
+            let ty_path = with_no_trimmed_paths!({
+                cx.tcx.def_path_str(edef.did())
+            });
+            cx.tcx.emit_spanned_lint(
                 BINDINGS_WITH_VARIANT_NAME,
                 p.hir_id,
                 p.span,
-                DelayDm(|| format!(
-                    "pattern binding `{}` is named the same as one \
-                        of the variants of the type `{}`",
-                    ident, cx.tcx.def_path_str(edef.did())
-                )),
-                |lint| {
-                    let ty_path = cx.tcx.def_path_str(edef.did());
-                    lint.code(error_code!(E0170));
-
+                BindingsWithVariantName {
                     // If this is an irrefutable pattern, and there's > 1 variant,
                     // then we can't actually match on this. Applying the below
                     // suggestion would produce code that breaks on `check_irrefutable`.
-                    if rf == Refutable || variant_count == 1 {
-                        lint.span_suggestion(
-                            p.span,
-                            "to match on the variant, qualify the path",
-                            format!("{}::{}", ty_path, ident),
-                            Applicability::MachineApplicable,
-                        );
-                    }
-
-                    lint
+                    suggestion: if rf == Refutable || variant_count == 1 {
+                        Some(p.span)
+                    } else { None },
+                    ty_path,
+                    ident,
                 },
             )
         }
@@ -611,14 +582,12 @@ fn pat_is_catchall(pat: &DeconstructedPat<'_, '_>) -> bool {
 }
 
 fn unreachable_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, catchall: Option<Span>) {
-    tcx.struct_span_lint_hir(UNREACHABLE_PATTERNS, id, span, "unreachable pattern", |lint| {
-        if let Some(catchall) = catchall {
-            // We had a catchall pattern, hint at that.
-            lint.span_label(span, "unreachable pattern");
-            lint.span_label(catchall, "matches any value");
-        }
-        lint
-    });
+    tcx.emit_spanned_lint(
+        UNREACHABLE_PATTERNS,
+        id,
+        span,
+        UnreachablePattern { span: if catchall.is_some() { Some(span) } else { None }, catchall },
+    );
 }
 
 fn irrefutable_let_pattern(tcx: TyCtxt<'_>, id: HirId, span: Span) {
@@ -634,67 +603,18 @@ fn irrefutable_let_patterns(
     span: Span,
 ) {
     macro_rules! emit_diag {
-        (
-            $lint:expr,
-            $source_name:expr,
-            $note_sufix:expr,
-            $help_sufix:expr
-        ) => {{
-            let s = pluralize!(count);
-            let these = pluralize!("this", count);
-            tcx.struct_span_lint_hir(
-                IRREFUTABLE_LET_PATTERNS,
-                id,
-                span,
-                format!("irrefutable {} pattern{s}", $source_name),
-                |lint| {
-                    lint.note(&format!(
-                        "{these} pattern{s} will always match, so the {}",
-                        $note_sufix
-                    ))
-                    .help(concat!("consider ", $help_sufix))
-                },
-            )
+        ($lint:tt) => {{
+            tcx.emit_spanned_lint(IRREFUTABLE_LET_PATTERNS, id, span, $lint { count });
         }};
     }
 
     match source {
-        LetSource::GenericLet => {
-            emit_diag!(lint, "`let`", "`let` is useless", "removing `let`");
-        }
-        LetSource::IfLet => {
-            emit_diag!(
-                lint,
-                "`if let`",
-                "`if let` is useless",
-                "replacing the `if let` with a `let`"
-            );
-        }
-        LetSource::IfLetGuard => {
-            emit_diag!(
-                lint,
-                "`if let` guard",
-                "guard is useless",
-                "removing the guard and adding a `let` inside the match arm"
-            );
-        }
-        LetSource::LetElse => {
-            emit_diag!(
-                lint,
-                "`let...else`",
-                "`else` clause is useless",
-                "removing the `else` clause"
-            );
-        }
-        LetSource::WhileLet => {
-            emit_diag!(
-                lint,
-                "`while let`",
-                "loop will never exit",
-                "instead using a `loop { ... }` with a `let` inside it"
-            );
-        }
-    };
+        LetSource::GenericLet => emit_diag!(IrrefutableLetPatternsGenericLet),
+        LetSource::IfLet => emit_diag!(IrrefutableLetPatternsIfLet),
+        LetSource::IfLetGuard => emit_diag!(IrrefutableLetPatternsIfLetGuard),
+        LetSource::LetElse => emit_diag!(IrrefutableLetPatternsLetElse),
+        LetSource::WhileLet => emit_diag!(IrrefutableLetPatternsWhileLet),
+    }
 }
 
 fn is_let_irrefutable<'p, 'tcx>(
@@ -760,15 +680,17 @@ fn non_exhaustive_match<'p, 'tcx>(
     // informative.
     let mut err;
     let pattern;
-    let mut patterns_len = 0;
+    let patterns_len;
     if is_empty_match && !non_empty_enum {
-        err = create_e0004(
-            cx.tcx.sess,
-            sp,
-            format!("non-exhaustive patterns: type `{}` is non-empty", scrut_ty),
-        );
-        pattern = "_".to_string();
+        cx.tcx.sess.emit_err(NonExhaustivePatternsTypeNotEmpty {
+            cx,
+            expr_span,
+            span: sp,
+            ty: scrut_ty,
+        });
+        return;
     } else {
+        // FIXME: migration of this diagnostic will require list support
         let joined_patterns = joined_uncovered_patterns(cx, &witnesses);
         err = create_e0004(
             cx.tcx.sess,
@@ -1039,24 +961,17 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa
                 }
             });
             if !conflicts_ref.is_empty() {
-                let occurs_because = format!(
-                    "move occurs because `{}` has type `{}` which does not implement the `Copy` trait",
+                sess.emit_err(BorrowOfMovedValue {
+                    span: pat.span,
+                    binding_span,
+                    conflicts_ref,
                     name,
-                    typeck_results.node_type(pat.hir_id),
-                );
-                let mut err = sess.struct_span_err(pat.span, "borrow of moved value");
-                err.span_label(binding_span, format!("value moved into `{}` here", name))
-                    .span_label(binding_span, occurs_because)
-                    .span_labels(conflicts_ref, "value borrowed here after move");
-                if pat.span.contains(binding_span) {
-                    err.span_suggestion_verbose(
-                        binding_span.shrink_to_lo(),
-                        "borrow this binding in the pattern to avoid moving the value",
-                        "ref ".to_string(),
-                        Applicability::MachineApplicable,
-                    );
-                }
-                err.emit();
+                    ty: typeck_results.node_type(pat.hir_id),
+                    suggest_borrowing: pat
+                        .span
+                        .contains(binding_span)
+                        .then(|| binding_span.shrink_to_lo()),
+                });
             }
             return;
         }
@@ -1086,19 +1001,18 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa
     // Report errors if any.
     if !conflicts_mut_mut.is_empty() {
         // Report mutability conflicts for e.g. `ref mut x @ Some(ref mut y)`.
-        let mut err = sess
-            .struct_span_err(pat.span, "cannot borrow value as mutable more than once at a time");
-        err.span_label(binding_span, format!("first mutable borrow, by `{}`, occurs here", name));
-        for (span, name) in conflicts_mut_mut {
-            err.span_label(span, format!("another mutable borrow, by `{}`, occurs here", name));
+        let mut occurences = vec![];
+
+        for (span, name_mut) in conflicts_mut_mut {
+            occurences.push(MultipleMutBorrowOccurence::Mutable { span, name_mut });
         }
-        for (span, name) in conflicts_mut_ref {
-            err.span_label(span, format!("also borrowed as immutable, by `{}`, here", name));
+        for (span, name_immut) in conflicts_mut_ref {
+            occurences.push(MultipleMutBorrowOccurence::Immutable { span, name_immut });
         }
-        for (span, name) in conflicts_move {
-            err.span_label(span, format!("also moved into `{}` here", name));
+        for (span, name_moved) in conflicts_move {
+            occurences.push(MultipleMutBorrowOccurence::Moved { span, name_moved });
         }
-        err.emit();
+        sess.emit_err(MultipleMutBorrows { span: pat.span, binding_span, occurences, name });
     } else if !conflicts_mut_ref.is_empty() {
         // Report mutability conflicts for e.g. `ref x @ Some(ref mut y)` or the converse.
         let (primary, also) = match mut_outer {
index 48a231a6cd6b7c4648396131e1743e0a71065b04..2c775b397182b352eea62549c4b7179129e20178 100644 (file)
@@ -6,10 +6,12 @@
 mod usefulness;
 
 pub(crate) use self::check_match::check_match;
+pub(crate) use self::usefulness::MatchCheckCtxt;
 
+use crate::errors::*;
 use crate::thir::util::UserAnnotatedTyHelpers;
 
-use rustc_errors::struct_span_err;
+use rustc_errors::error_code;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::pat_util::EnumerateAndAdjustIterator;
@@ -139,13 +141,7 @@ fn lower_pattern_range(
             }
             // `x..y` where `x >= y`. The range is empty => error.
             (RangeEnd::Excluded, _) => {
-                struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0579,
-                    "lower range bound must be less than upper"
-                )
-                .emit();
+                self.tcx.sess.emit_err(LowerRangeBoundMustBeLessThanUpper { span });
                 PatKind::Wild
             }
             // `x..=y` where `x == y`.
@@ -156,23 +152,10 @@ fn lower_pattern_range(
             }
             // `x..=y` where `x > y` hence the range is empty => error.
             (RangeEnd::Included, _) => {
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
+                self.tcx.sess.emit_err(LowerRangeBoundMustBeLessThanOrEqualToUpper {
                     span,
-                    E0030,
-                    "lower range bound must be less than or equal to upper"
-                );
-                err.span_label(span, "lower bound larger than upper bound");
-                if self.tcx.sess.teach(&err.get_code().unwrap()) {
-                    err.note(
-                        "When matching against a range, the compiler \
-                              verifies that the range is non-empty. Range \
-                              patterns include both end-points, so this is \
-                              equivalent to requiring the start of the range \
-                              to be less than or equal to the end of the range.",
-                    );
-                }
-                err.emit();
+                    teach: if self.tcx.sess.teach(&error_code!(E0030)) { Some(()) } else { None },
+                });
                 PatKind::Wild
             }
         }
@@ -501,7 +484,7 @@ fn lower_path(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) ->
             }
 
             Err(_) => {
-                self.tcx.sess.span_err(span, "could not evaluate constant pattern");
+                self.tcx.sess.emit_err(CouldNotEvalConstPattern { span });
                 return pat_from_kind(PatKind::Wild);
             }
         };
@@ -548,11 +531,11 @@ fn lower_path(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) ->
             Err(ErrorHandled::TooGeneric) => {
                 // While `Reported | Linted` cases will have diagnostics emitted already
                 // it is not true for TooGeneric case, so we need to give user more information.
-                self.tcx.sess.span_err(span, "constant pattern depends on a generic parameter");
+                self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
                 pat_from_kind(PatKind::Wild)
             }
             Err(_) => {
-                self.tcx.sess.span_err(span, "could not evaluate constant pattern");
+                self.tcx.sess.emit_err(CouldNotEvalConstPattern { span });
                 pat_from_kind(PatKind::Wild)
             }
         }
@@ -584,7 +567,7 @@ fn lower_inline_const(
             mir::ConstantKind::Val(_, _) => self.const_to_pat(value, id, span, false).kind,
             mir::ConstantKind::Unevaluated(..) => {
                 // If we land here it means the const can't be evaluated because it's `TooGeneric`.
-                self.tcx.sess.span_err(span, "constant pattern depends on a generic parameter");
+                self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
                 return PatKind::Wild;
             }
         }
index b36e268cf8bf78cc0f29604bc56f36050600c121..9b053985bedf6823f13a47fe5f5a6d5770cc38b8 100644 (file)
@@ -14,9 +14,8 @@
 mod abs_domain;
 
 rustc_index::newtype_index! {
-    pub struct MovePathIndex {
-        DEBUG_FORMAT = "mp{}"
-    }
+    #[debug_format = "mp{}"]
+    pub struct MovePathIndex {}
 }
 
 impl polonius_engine::Atom for MovePathIndex {
@@ -26,15 +25,13 @@ fn index(self) -> usize {
 }
 
 rustc_index::newtype_index! {
-    pub struct MoveOutIndex {
-        DEBUG_FORMAT = "mo{}"
-    }
+    #[debug_format = "mo{}"]
+    pub struct MoveOutIndex {}
 }
 
 rustc_index::newtype_index! {
-    pub struct InitIndex {
-        DEBUG_FORMAT = "in{}"
-    }
+    #[debug_format = "in{}"]
+    pub struct InitIndex {}
 }
 
 impl MoveOutIndex {
index 782abd7804d5d0f66ed7175a141d42fe41bb6e2d..9c22b5df73ce85ea2423352c4c8d55ed0ea20abe 100644 (file)
@@ -500,7 +500,7 @@ fn unsafety_check_result<'tcx>(
     // `mir_built` force this.
     let body = &tcx.mir_built(def).borrow();
 
-    if body.should_skip() {
+    if body.is_custom_mir() {
         return tcx.arena.alloc(UnsafetyCheckResult {
             violations: Vec::new(),
             used_unsafe_blocks: FxHashSet::default(),
index 3378923c22c367c1a9396ab54e07d0ba3279e282..d435d3ee69b76a94eda4fe73a4ff40d60eb8aa0d 100644 (file)
@@ -1,39 +1,44 @@
-//! This module provides a pass to replacing the following statements with
-//! [`Nop`]s
+//! This module provides a pass that removes parts of MIR that are no longer relevant after
+//! analysis phase and borrowck. In particular, it removes false edges, user type annotations and
+//! replaces following statements with [`Nop`]s:
 //!
 //!   - [`AscribeUserType`]
 //!   - [`FakeRead`]
 //!   - [`Assign`] statements with a [`Shallow`] borrow
 //!
-//! The `CleanFakeReadsAndBorrows` "pass" is actually implemented as two
-//! traversals (aka visits) of the input MIR. The first traversal,
-//! `DeleteAndRecordFakeReads`, deletes the fake reads and finds the
-//! temporaries read by [`ForMatchGuard`] reads, and `DeleteFakeBorrows`
-//! deletes the initialization of those temporaries.
-//!
 //! [`AscribeUserType`]: rustc_middle::mir::StatementKind::AscribeUserType
-//! [`Shallow`]: rustc_middle::mir::BorrowKind::Shallow
-//! [`FakeRead`]: rustc_middle::mir::StatementKind::FakeRead
 //! [`Assign`]: rustc_middle::mir::StatementKind::Assign
-//! [`ForMatchGuard`]: rustc_middle::mir::FakeReadCause::ForMatchGuard
+//! [`FakeRead`]: rustc_middle::mir::StatementKind::FakeRead
 //! [`Nop`]: rustc_middle::mir::StatementKind::Nop
+//! [`Shallow`]: rustc_middle::mir::BorrowKind::Shallow
 
 use crate::MirPass;
-use rustc_middle::mir::visit::MutVisitor;
-use rustc_middle::mir::{Body, BorrowKind, Location, Rvalue};
-use rustc_middle::mir::{Statement, StatementKind};
+use rustc_middle::mir::{Body, BorrowKind, Rvalue, StatementKind, TerminatorKind};
 use rustc_middle::ty::TyCtxt;
 
-pub struct CleanupNonCodegenStatements;
+pub struct CleanupPostBorrowck;
 
-pub struct DeleteNonCodegenStatements<'tcx> {
-    tcx: TyCtxt<'tcx>,
-}
+impl<'tcx> MirPass<'tcx> for CleanupPostBorrowck {
+    fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        for basic_block in body.basic_blocks.as_mut() {
+            for statement in basic_block.statements.iter_mut() {
+                match statement.kind {
+                    StatementKind::AscribeUserType(..)
+                    | StatementKind::Assign(box (_, Rvalue::Ref(_, BorrowKind::Shallow, _)))
+                    | StatementKind::FakeRead(..) => statement.make_nop(),
+                    _ => (),
+                }
+            }
+            let terminator = basic_block.terminator_mut();
+            match terminator.kind {
+                TerminatorKind::FalseEdge { real_target, .. }
+                | TerminatorKind::FalseUnwind { real_target, .. } => {
+                    terminator.kind = TerminatorKind::Goto { target: real_target };
+                }
+                _ => {}
+            }
+        }
 
-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_preserves_cfg(body);
         body.user_type_annotations.raw.clear();
 
         for decl in &mut body.local_decls {
@@ -41,19 +46,3 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         }
     }
 }
-
-impl<'tcx> MutVisitor<'tcx> for DeleteNonCodegenStatements<'tcx> {
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-
-    fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) {
-        match statement.kind {
-            StatementKind::AscribeUserType(..)
-            | StatementKind::Assign(box (_, Rvalue::Ref(_, BorrowKind::Shallow, _)))
-            | StatementKind::FakeRead(..) => statement.make_nop(),
-            _ => (),
-        }
-        self.super_statement(statement, location);
-    }
-}
index b0514e033566c9a65ebe8f5484a41d74ddb39898..e384cfe165990c47940bde2566b8da034d49fe33 100644 (file)
@@ -6,6 +6,7 @@
 use either::Right;
 
 use rustc_ast::Mutability;
+use rustc_const_eval::const_eval::CheckAlignment;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def::DefKind;
 use rustc_index::bit_set::BitSet;
@@ -22,7 +23,7 @@
 use rustc_middle::ty::InternalSubsts;
 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::abi::{self, Align, HasDataLayout, Size, TargetDataLayout};
 use rustc_target::spec::abi::Abi as CallAbi;
 use rustc_trait_selection::traits;
 
@@ -186,16 +187,27 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
     type MemoryKind = !;
 
     #[inline(always)]
-    fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
+    fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> CheckAlignment {
         // We do not check for alignment to avoid having to carry an `Align`
         // in `ConstValue::ByRef`.
-        false
+        CheckAlignment::No
     }
 
     #[inline(always)]
     fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
         false // for now, we don't enforce validity
     }
+    fn alignment_check_failed(
+        ecx: &InterpCx<'mir, 'tcx, Self>,
+        _has: Align,
+        _required: Align,
+        _check: CheckAlignment,
+    ) -> InterpResult<'tcx, ()> {
+        span_bug!(
+            ecx.cur_span(),
+            "`alignment_check_failed` called when no alignment check requested"
+        )
+    }
 
     fn load_mir(
         _ecx: &InterpCx<'mir, 'tcx, Self>,
@@ -689,8 +701,8 @@ fn eval_rvalue_with_identities(
                     BinOp::Mul if const_arg.layout.ty.is_integral() && arg_value == 0 => {
                         if let Rvalue::CheckedBinaryOp(_, _) = rvalue {
                             let val = Immediate::ScalarPair(
-                                const_arg.to_scalar().into(),
-                                Scalar::from_bool(false).into(),
+                                const_arg.to_scalar(),
+                                Scalar::from_bool(false),
                             );
                             this.ecx.write_immediate(val, &dest)
                         } else {
index 782129be088b68ce979b6323463ba8525a512f41..78d28f1ebab7ce345d5082169bb0b80e4c34045b 100644 (file)
@@ -282,9 +282,9 @@ fn predecessors(&self, node: Self::Node) -> <Self as graph::GraphPredecessors<'_
 
 rustc_index::newtype_index! {
     /// A node in the control-flow graph of CoverageGraph.
+    #[debug_format = "bcb{}"]
     pub(super) struct BasicCoverageBlock {
-        DEBUG_FORMAT = "bcb{}",
-        const START_BCB = 0,
+        const START_BCB = 0;
     }
 }
 
index e9027387413cfe1e97425a7992e74e33384fbfb3..c75fe2327de3eb0b52e35f0cbebfe02fc9282838 100644 (file)
@@ -2,6 +2,7 @@
 //!
 //! Currently, this pass only propagates scalar values.
 
+use rustc_const_eval::const_eval::CheckAlignment;
 use rustc_const_eval::interpret::{ConstValue, ImmTy, Immediate, InterpCx, Scalar};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::mir::visit::{MutVisitor, Visitor};
@@ -10,6 +11,7 @@
 use rustc_mir_dataflow::value_analysis::{Map, State, TrackElem, ValueAnalysis, ValueOrPlace};
 use rustc_mir_dataflow::{lattice::FlatSet, Analysis, ResultsVisitor, SwitchIntEdgeEffects};
 use rustc_span::DUMMY_SP;
+use rustc_target::abi::Align;
 
 use crate::MirPass;
 
@@ -448,13 +450,21 @@ impl<'mir, 'tcx> rustc_const_eval::interpret::Machine<'mir, 'tcx> for DummyMachi
     type MemoryKind = !;
     const PANIC_ON_ALLOC_FAIL: bool = true;
 
-    fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
+    fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> CheckAlignment {
         unimplemented!()
     }
 
     fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
         unimplemented!()
     }
+    fn alignment_check_failed(
+        _ecx: &InterpCx<'mir, 'tcx, Self>,
+        _has: Align,
+        _required: Align,
+        _check: CheckAlignment,
+    ) -> interpret::InterpResult<'tcx, ()> {
+        unimplemented!()
+    }
 
     fn find_mir_or_eval_fn(
         _ecx: &mut InterpCx<'mir, 'tcx, Self>,
index 3e45319431cec0e9de6816ed78310c892d09d461..74d8337653f034f968ea516556563ebd1dc068c1 100644 (file)
 
 use std::collections::hash_map::{Entry, OccupiedEntry};
 
+use crate::simplify::remove_dead_blocks;
 use crate::MirPass;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_index::bit_set::BitSet;
@@ -235,6 +236,12 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
             apply_merges(body, tcx, &merges, &merged_locals);
         }
 
+        if round_count != 0 {
+            // Merging can introduce overlap between moved arguments and/or call destination in an
+            // unreachable code, which validator considers to be ill-formed.
+            remove_dead_blocks(tcx, body);
+        }
+
         trace!(round_count);
     }
 }
index 93200b28830f0cdd44b0625acdf52d2758c2902b..aba5a8580f19485b78da4a3b034659ef63b1fefc 100644 (file)
@@ -77,8 +77,6 @@
 mod multiple_return_terminators;
 mod normalize_array_len;
 mod nrvo;
-// This pass is public to allow external drivers to perform MIR cleanup
-pub mod remove_false_edges;
 mod remove_noop_landing_pads;
 mod remove_storage_markers;
 mod remove_uninit_drops;
@@ -494,10 +492,9 @@ fn run_analysis_to_runtime_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>
 /// After this series of passes, no lifetime analysis based on borrowing can be done.
 fn run_analysis_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
     let passes: &[&dyn MirPass<'tcx>] = &[
-        &remove_false_edges::RemoveFalseEdges,
+        &cleanup_post_borrowck::CleanupPostBorrowck,
         &simplify_branches::SimplifyConstCondition::new("initial"),
         &remove_noop_landing_pads::RemoveNoopLandingPads,
-        &cleanup_post_borrowck::CleanupNonCodegenStatements,
         &simplify::SimplifyCfg::new("early-opt"),
         &deref_separator::Derefer,
     ];
index a159e61717823e5847d01641fc9f9762bae81139..1708b287e56f25bca285136fca3a92649a0bafd6 100644 (file)
@@ -16,7 +16,8 @@
 
 impl<'tcx> MirPass<'tcx> for NormalizeArrayLen {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
-        sess.mir_opt_level() >= 4
+        // See #105929
+        sess.mir_opt_level() >= 4 && sess.opts.unstable_opts.unsound_mir_opts
     }
 
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
diff --git a/compiler/rustc_mir_transform/src/remove_false_edges.rs b/compiler/rustc_mir_transform/src/remove_false_edges.rs
deleted file mode 100644 (file)
index 71f5ccf..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-use rustc_middle::mir::{Body, TerminatorKind};
-use rustc_middle::ty::TyCtxt;
-
-use crate::MirPass;
-
-/// Removes `FalseEdge` and `FalseUnwind` terminators from the MIR.
-///
-/// These are only needed for borrow checking, and can be removed afterwards.
-///
-/// FIXME: This should probably have its own MIR phase.
-pub struct RemoveFalseEdges;
-
-impl<'tcx> MirPass<'tcx> for RemoveFalseEdges {
-    fn run_pass(&self, _: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        for block in body.basic_blocks_mut() {
-            let terminator = block.terminator_mut();
-            terminator.kind = match terminator.kind {
-                TerminatorKind::FalseEdge { real_target, .. } => {
-                    TerminatorKind::Goto { target: real_target }
-                }
-                TerminatorKind::FalseUnwind { real_target, .. } => {
-                    TerminatorKind::Goto { target: real_target }
-                }
-
-                _ => continue,
-            }
-        }
-    }
-}
index 558a372fb1e8a60b7f1fb5f8c5ae261883117cb7..3a2bf051516554bc6f6acdf220f42a604a5de656 100644 (file)
@@ -182,7 +182,7 @@ fn replace_flattened_locals<'tcx>(
     let mut fragments = IndexVec::new();
     for (k, v) in &replacements.fields {
         fragments.ensure_contains_elem(k.local, || Vec::new());
-        fragments[k.local].push((&k.projection[..], *v));
+        fragments[k.local].push((k.projection, *v));
     }
     debug!(?fragments);
 
index 10ea4d29cfe4e3317df1500b046cb1ec2d32c67c..deeeb9af4eb9232b38a525b98cc0cdfc19924dde 100644 (file)
@@ -595,8 +595,8 @@ fn check_recursion_limit<'tcx>(
         let def_path_str = tcx.def_path_str(def_id);
         let (shrunk, written_to_path) = shrunk_instance_name(tcx, &instance);
         let mut path = PathBuf::new();
-        let was_written = if written_to_path.is_some() {
-            path = written_to_path.unwrap();
+        let was_written = if let Some(written_to_path) = written_to_path {
+            path = written_to_path;
             Some(())
         } else {
             None
index f1ca72de8dbe47d934cc8b8c197c5ed4b4d11ff7..f15cf54718e2b7221bbb70fb9261f36af32fd525 100644 (file)
@@ -77,3 +77,9 @@ pub struct SymbolAlreadyDefined {
     pub span: Option<Span>,
     pub symbol: String,
 }
+
+#[derive(Diagnostic)]
+#[diag(monomorphize_couldnt_dump_mono_stats)]
+pub struct CouldntDumpMonoStats {
+    pub error: String,
+}
index 932edc6675f5900cb6dd04d9678d7847345f0f9b..38e1d98e44e13f0d72af80666004b666fb21835c 100644 (file)
 mod default;
 mod merging;
 
+use std::cmp;
+use std::fs::{self, File};
+use std::io::{BufWriter, Write};
+use std::path::{Path, PathBuf};
+
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync;
 use rustc_hir::def_id::DefIdSet;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
+use rustc_session::config::SwitchWithOptPath;
 use rustc_span::symbol::Symbol;
 
 use crate::collector::InliningMap;
 use crate::collector::{self, MonoItemCollectionMode};
-use crate::errors::{SymbolAlreadyDefined, UnknownPartitionStrategy};
+use crate::errors::{CouldntDumpMonoStats, SymbolAlreadyDefined, UnknownPartitionStrategy};
 
 pub struct PartitioningCx<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
@@ -411,6 +417,15 @@ fn collect_and_partition_mono_items<'tcx>(
         })
         .collect();
 
+    // Output monomorphization stats per def_id
+    if let SwitchWithOptPath::Enabled(ref path) = tcx.sess.opts.unstable_opts.dump_mono_stats {
+        if let Err(err) =
+            dump_mono_items_stats(tcx, &codegen_units, path, tcx.sess.opts.crate_name.as_deref())
+        {
+            tcx.sess.emit_fatal(CouldntDumpMonoStats { error: err.to_string() });
+        }
+    }
+
     if tcx.sess.opts.unstable_opts.print_mono_items.is_some() {
         let mut item_to_cgus: FxHashMap<_, Vec<_>> = Default::default();
 
@@ -465,6 +480,67 @@ fn collect_and_partition_mono_items<'tcx>(
     (tcx.arena.alloc(mono_items), codegen_units)
 }
 
+/// Outputs stats about instantation counts and estimated size, per `MonoItem`'s
+/// def, to a file in the given output directory.
+fn dump_mono_items_stats<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    codegen_units: &[CodegenUnit<'tcx>],
+    output_directory: &Option<PathBuf>,
+    crate_name: Option<&str>,
+) -> Result<(), Box<dyn std::error::Error>> {
+    let output_directory = if let Some(ref directory) = output_directory {
+        fs::create_dir_all(directory)?;
+        directory
+    } else {
+        Path::new(".")
+    };
+
+    let filename = format!("{}.mono_items.md", crate_name.unwrap_or("unknown-crate"));
+    let output_path = output_directory.join(&filename);
+    let file = File::create(output_path)?;
+    let mut file = BufWriter::new(file);
+
+    // Gather instantiated mono items grouped by def_id
+    let mut items_per_def_id: FxHashMap<_, Vec<_>> = Default::default();
+    for cgu in codegen_units {
+        for (&mono_item, _) in cgu.items() {
+            // Avoid variable-sized compiler-generated shims
+            if mono_item.is_user_defined() {
+                items_per_def_id.entry(mono_item.def_id()).or_default().push(mono_item);
+            }
+        }
+    }
+
+    // Output stats sorted by total instantiated size, from heaviest to lightest
+    let mut stats: Vec<_> = items_per_def_id
+        .into_iter()
+        .map(|(def_id, items)| {
+            let instantiation_count = items.len();
+            let size_estimate = items[0].size_estimate(tcx);
+            let total_estimate = instantiation_count * size_estimate;
+            (def_id, instantiation_count, size_estimate, total_estimate)
+        })
+        .collect();
+    stats.sort_unstable_by_key(|(_, _, _, total_estimate)| cmp::Reverse(*total_estimate));
+
+    if !stats.is_empty() {
+        writeln!(
+            file,
+            "| Item | Instantiation count | Estimated Cost Per Instantiation | Total Estimated Cost |"
+        )?;
+        writeln!(file, "| --- | ---: | ---: | ---: |")?;
+        for (def_id, instantiation_count, size_estimate, total_estimate) in stats {
+            let item = with_no_trimmed_paths!(tcx.def_path_str(def_id));
+            writeln!(
+                file,
+                "| {item} | {instantiation_count} | {size_estimate} | {total_estimate} |"
+            )?;
+        }
+    }
+
+    Ok(())
+}
+
 fn codegened_and_inlined_items<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> &'tcx DefIdSet {
     let (items, cgus) = tcx.collect_and_partition_mono_items(());
     let mut visited = DefIdSet::default();
index bebb012660a16ae140a780bb5da5049761bc0faa..40b88788caa6743c66a5e7f9c0e6dba47fd6cb9a 100644 (file)
@@ -25,7 +25,7 @@
 use rustc_ast::util::case::Case;
 use rustc_ast::AttrId;
 use rustc_ast::DUMMY_NODE_ID;
-use rustc_ast::{self as ast, AnonConst, AttrStyle, AttrVec, Const, DelimArgs, Extern};
+use rustc_ast::{self as ast, AnonConst, AttrStyle, Const, DelimArgs, Extern};
 use rustc_ast::{Async, AttrArgs, AttrArgsEq, Expr, ExprKind, MacDelimiter, Mutability, StrLit};
 use rustc_ast::{HasAttrs, HasTokens, Unsafe, Visibility, VisibilityKind};
 use rustc_ast_pretty::pprust;
@@ -1217,11 +1217,7 @@ fn parse_const_block(&mut self, span: Span, pat: bool) -> PResult<'a, P<Expr>> {
             value: self.mk_expr(blk.span, ExprKind::Block(blk, None)),
         };
         let blk_span = anon_const.value.span;
-        Ok(self.mk_expr_with_attrs(
-            span.to(blk_span),
-            ExprKind::ConstBlock(anon_const),
-            AttrVec::from(attrs),
-        ))
+        Ok(self.mk_expr_with_attrs(span.to(blk_span), ExprKind::ConstBlock(anon_const), attrs))
     }
 
     /// Parses mutability (`mut` or nothing).
index 2d432e3f5bd65500b5ab8279efb4bd9298eaef62..5333d3b8587ddaafa80c49336c50890d4f25af7a 100644 (file)
@@ -277,8 +277,7 @@ pub(super) fn parse_path_segment(
                         if let Some(arg) = args
                             .iter()
                             .rev()
-                            .skip_while(|arg| matches!(arg, AngleBracketedArg::Constraint(_)))
-                            .next()
+                            .find(|arg| !matches!(arg, AngleBracketedArg::Constraint(_)))
                         {
                             err.span_suggestion_verbose(
                                 arg.span().shrink_to_hi(),
index a71ae717a508d37ee42db75d1a5add8a994fac0b..f5556738bff91bfa75a6d3f4738ec0bfd4ac9586 100644 (file)
@@ -787,7 +787,6 @@ fn warn_dead_fields_and_variants(
         let mut dead_codes = dead_codes
             .iter()
             .filter(|v| !v.name.as_str().starts_with('_'))
-            .map(|v| v)
             .collect::<Vec<&DeadVariant>>();
         if dead_codes.is_empty() {
             return;
index a7854cd49988f721806864a33570b646bc5379d2..272386f313e8d0736aecdd274652c4374e1fca6e 100644 (file)
@@ -121,7 +121,7 @@ fn record_inner<T>(
 
     fn print(&self, title: &str, prefix: &str) {
         let mut nodes: Vec<_> = self.nodes.iter().collect();
-        nodes.sort_by_key(|&(_, ref node)| node.stats.count * node.stats.size);
+        nodes.sort_by_key(|(_, node)| node.stats.count * node.stats.size);
 
         let total_size = nodes.iter().map(|(_, node)| node.stats.count * node.stats.size).sum();
 
@@ -147,7 +147,7 @@ fn print(&self, title: &str, prefix: &str) {
             );
             if !node.subnodes.is_empty() {
                 let mut subnodes: Vec<_> = node.subnodes.iter().collect();
-                subnodes.sort_by_key(|&(_, ref subnode)| subnode.count * subnode.size);
+                subnodes.sort_by_key(|(_, subnode)| subnode.count * subnode.size);
 
                 for (label, subnode) in subnodes {
                     let size = subnode.count * subnode.size;
index 99efed0b7fb46be15f9d92585c159c7ccf05b7fa..9a40b847d8552ebd9800fa42f6a6791b17562f73 100644 (file)
@@ -83,7 +83,6 @@ fn collect_item(&mut self, lang_item: LangItem, item_def_id: DefId) {
                         .map(|p| p.display().to_string())
                         .collect::<Vec<_>>()
                         .join(", ")
-                        .into()
                 };
                 let first_defined_span = self.tcx.hir().span_if_local(original_def_id);
                 let mut orig_crate_name = Empty;
@@ -98,7 +97,6 @@ fn collect_item(&mut self, lang_item: LangItem, item_def_id: DefId) {
                         .map(|p| p.display().to_string())
                         .collect::<Vec<_>>()
                         .join(", ")
-                        .into()
                 };
                 if first_defined_span.is_none() {
                     orig_crate_name = self.tcx.crate_name(original_def_id.krate);
index 1f65cc8b6096775368cd47562ecf3e55cf48ea4b..b49432b79962bd3c288ec770a85fe2d1d1e5483c 100644 (file)
 mod rwu_table;
 
 rustc_index::newtype_index! {
-    pub struct Variable {
-        DEBUG_FORMAT = "v({})",
-    }
+    #[debug_format = "v({})"]
+    pub struct Variable {}
 }
 
 rustc_index::newtype_index! {
-    pub struct LiveNode {
-        DEBUG_FORMAT = "ln({})",
-    }
+    #[debug_format = "ln({})"]
+    pub struct LiveNode {}
 }
 
 #[derive(Copy, Clone, PartialEq, Debug)]
index ac9653b90071cdacd01923cd3bb2c6c42479be14..c4e605c18521746f38c1633396243095c69a5f71 100644 (file)
@@ -965,7 +965,7 @@ fn encode(&self, s: &mut CacheEncoder<'a, 'tcx>) {
                     s.emit_str(self.as_str());
                 }
                 Entry::Occupied(o) => {
-                    let x = o.get().clone();
+                    let x = *o.get();
                     s.emit_u8(SYMBOL_OFFSET);
                     s.emit_usize(x);
                 }
index 0e7d628c1eb630c030946079bfaa9259a3785c01..52957ee0222387b62747d335e3429016184cf0bf 100644 (file)
@@ -37,7 +37,7 @@ pub struct DepGraph<K: DepKind> {
 }
 
 rustc_index::newtype_index! {
-    pub struct DepNodeIndex { .. }
+    pub struct DepNodeIndex {}
 }
 
 impl DepNodeIndex {
@@ -974,7 +974,7 @@ pub struct WorkProduct {
 
 // Index type for `DepNodeData`'s edges.
 rustc_index::newtype_index! {
-    struct EdgeIndex { .. }
+    struct EdgeIndex {}
 }
 
 /// `CurrentDepGraph` stores the dependency graph for the current session. It
index d292f4beef2ebccc33f0bebfa0894a7d756e5a1a..a918328d4130ea08257536e8f432ca0c42396a32 100644 (file)
@@ -27,9 +27,8 @@
 // unused so that we can store multiple index types in `CompressedHybridIndex`,
 // and use those bits to encode which index type it contains.
 rustc_index::newtype_index! {
-    pub struct SerializedDepNodeIndex {
-        MAX = 0x7FFF_FFFF
-    }
+    #[max = 0x7FFF_FFFF]
+    pub struct SerializedDepNodeIndex {}
 }
 
 /// Data for use when recompiling the **current crate**.
index f4a6a08df1c8514fe24987fce26eb2827b7afcc4..cf63599626866203f41feeaca0bf156bd9d0ce75 100644 (file)
@@ -576,7 +576,7 @@ fn build_reduced_graph_for_use_tree(
                 // Ensure there is at most one `self` in the list
                 let self_spans = items
                     .iter()
-                    .filter_map(|&(ref use_tree, _)| {
+                    .filter_map(|(use_tree, _)| {
                         if let ast::UseTreeKind::Simple(..) = use_tree.kind {
                             if use_tree.ident().name == kw::SelfLower {
                                 return Some(use_tree.span);
index 49bbe37ee4328ad5dadd9ae79c87a7ded364dcd0..600308b6508db9931c3b6974acf48493421d8bfc 100644 (file)
@@ -277,11 +277,7 @@ fn make_base_error(
                 let override_suggestion =
                     if ["true", "false"].contains(&item_str.to_string().to_lowercase().as_str()) {
                         let item_typo = item_str.to_string().to_lowercase();
-                        Some((
-                            item_span,
-                            "you may want to use a bool value instead",
-                            format!("{}", item_typo),
-                        ))
+                        Some((item_span, "you may want to use a bool value instead", item_typo))
                     // FIXME(vincenzopalazzo): make the check smarter,
                     // and maybe expand with levenshtein distance checks
                     } else if item_str.as_str() == "printf" {
@@ -2324,7 +2320,7 @@ fn suggest_introducing_lifetime(
                         let message = format!("consider introducing lifetime `{}` here", name);
                         should_continue = suggest(err, false, span, &message, sugg);
                     } else {
-                        let message = format!("consider introducing a named lifetime parameter");
+                        let message = "consider introducing a named lifetime parameter";
                         should_continue = suggest(err, false, span, &message, sugg);
                     }
                 }
index 24e4b5bdd3f50d8f84e8d3f435062eb401e9de07..4861ee746aae3158de435a078c5d83a2143d454a 100644 (file)
@@ -1491,7 +1491,7 @@ pub fn clone_outputs(&self) -> ResolverOutputs {
             label_res_map: self.label_res_map.clone(),
             lifetimes_res_map: self.lifetimes_res_map.clone(),
             extra_lifetime_params_map: self.extra_lifetime_params_map.clone(),
-            next_node_id: self.next_node_id.clone(),
+            next_node_id: self.next_node_id,
             node_id_to_def_id: self.node_id_to_def_id.clone(),
             def_id_to_node_id: self.def_id_to_node_id.clone(),
             trait_map: self.trait_map.clone(),
index 25d84506efaf0df5477c34bbab0392fc5b9fa20a..e72b76cfee9e9660a427746e2cadd14cb0ef711c 100644 (file)
@@ -115,6 +115,10 @@ pub struct StackProtectorNotSupportedForTarget<'a> {
     pub target_triple: &'a TargetTriple,
 }
 
+#[derive(Diagnostic)]
+#[diag(session_branch_protection_requires_aarch64)]
+pub(crate) struct BranchProtectionRequiresAArch64;
+
 #[derive(Diagnostic)]
 #[diag(session_split_debuginfo_unstable_platform)]
 pub struct SplitDebugInfoUnstablePlatform {
index 1855a49c1ecdf36b331a92e362feaa3f54eec1d5..6f1b31ff9c3aec9cbce8cb0bf3b2fe053a566ba7 100644 (file)
@@ -122,7 +122,7 @@ fn current_dll_path() -> Result<PathBuf, String> {
     let target = crate::config::host_triple();
     let mut sysroot_candidates: SmallVec<[PathBuf; 2]> =
         smallvec![get_or_default_sysroot().expect("Failed finding sysroot")];
-    let path = current_dll_path().and_then(|s| Ok(s.canonicalize().map_err(|e| e.to_string())?));
+    let path = current_dll_path().and_then(|s| s.canonicalize().map_err(|e| e.to_string()));
     if let Ok(dll) = path {
         // use `parent` twice to chop off the file name and then also the
         // directory containing the dll which should be either `lib` or `bin`.
@@ -165,7 +165,7 @@ fn canonicalize(path: PathBuf) -> PathBuf {
     }
 
     fn default_from_rustc_driver_dll() -> Result<PathBuf, String> {
-        let dll = current_dll_path().and_then(|s| Ok(canonicalize(s)))?;
+        let dll = current_dll_path().map(|s| canonicalize(s))?;
 
         // `dll` will be in one of the following two:
         // - compiler's libdir: $sysroot/lib/*.dll
index dab9c736d14d59d496f8bbed8b2e2d52f57a5980..40bc669707aa01d33f55a89e9eaef27cf7127cbf 100644 (file)
@@ -1294,6 +1294,9 @@ pub(crate) fn parse_proc_macro_execution_strategy(
         computed `block` spans (one span encompassing a block's terminator and \
         all statements). If `-Z instrument-coverage` is also enabled, create \
         an additional `.html` file showing the computed coverage spans."),
+    dump_mono_stats: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
+        parse_switch_with_opt_path, [UNTRACKED],
+        "output statistics about monomorphization collection (format: markdown)"),
     dwarf_version: Option<u32> = (None, parse_opt_number, [TRACKED],
         "version of DWARF debug information to emit (default: 2 or 4, depending on platform)"),
     dylib_lto: bool = (false, parse_bool, [UNTRACKED],
@@ -1418,6 +1421,8 @@ pub(crate) fn parse_proc_macro_execution_strategy(
         "run all passes except codegen; no output"),
     no_generate_arange_section: bool = (false, parse_no_flag, [TRACKED],
         "omit DWARF address ranges that give faster lookups"),
+    no_jump_tables: bool = (false, parse_no_flag, [TRACKED],
+        "disable the jump tables and lookup tables that can be generated from a switch case lowering"),
     no_leak_check: bool = (false, parse_no_flag, [UNTRACKED],
         "disable the 'leak check' for subtyping; unsound, but useful for tests"),
     no_link: bool = (false, parse_no_flag, [TRACKED],
index 8859b76d28972f7b36005f035f591300f22e9b79..01a9b1000882bd5c77a20b64a697a57ea409d260 100644 (file)
@@ -3,10 +3,10 @@
 pub use crate::code_stats::{DataTypeKind, FieldInfo, SizeKind, VariantInfo};
 use crate::config::{self, CrateType, InstrumentCoverage, OptLevel, OutputType, SwitchWithOptPath};
 use crate::errors::{
-    CannotEnableCrtStaticLinux, CannotMixAndMatchSanitizers, LinkerPluginToWindowsNotSupported,
-    NotCircumventFeature, ProfileSampleUseFileDoesNotExist, ProfileUseFileDoesNotExist,
-    SanitizerCfiEnabled, SanitizerNotSupported, SanitizersNotSupported, SkippingConstChecks,
-    SplitDebugInfoUnstablePlatform, StackProtectorNotSupportedForTarget,
+    BranchProtectionRequiresAArch64, CannotEnableCrtStaticLinux, CannotMixAndMatchSanitizers,
+    LinkerPluginToWindowsNotSupported, NotCircumventFeature, ProfileSampleUseFileDoesNotExist,
+    ProfileUseFileDoesNotExist, SanitizerCfiEnabled, SanitizerNotSupported, SanitizersNotSupported,
+    SkippingConstChecks, SplitDebugInfoUnstablePlatform, StackProtectorNotSupportedForTarget,
     TargetRequiresUnwindTables, UnleashedFeatureHelp, UnstableVirtualFunctionElimination,
     UnsupportedDwarfVersion,
 };
@@ -1323,7 +1323,7 @@ pub fn build_session(
     let warnings_allow = sopts
         .lint_opts
         .iter()
-        .rfind(|&&(ref key, _)| *key == "warnings")
+        .rfind(|&(key, _)| *key == "warnings")
         .map_or(false, |&(_, level)| level == lint::Allow);
     let cap_lints_allow = sopts.lint_cap.map_or(false, |cap| cap == lint::Allow);
     let can_emit_warnings = !(warnings_allow || cap_lints_allow);
@@ -1565,6 +1565,10 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
         }
     }
 
+    if sess.opts.unstable_opts.branch_protection.is_some() && sess.target.arch != "aarch64" {
+        sess.emit_err(BranchProtectionRequiresAArch64);
+    }
+
     if let Some(dwarf_version) = sess.opts.unstable_opts.dwarf_version {
         if dwarf_version > 5 {
             sess.emit_err(UnsupportedDwarfVersion { dwarf_version });
index 48a2ab0f904ac073b76107c232d133a24139fb67..5ce2577b63c1d81cfd46150dffeb5e039ee00b0c 100644 (file)
@@ -13,7 +13,7 @@ rustc_index = { path = "../rustc_index" }
 rustc_arena = { path = "../rustc_arena" }
 scoped-tls = "1.0"
 unicode-width = "0.1.4"
-cfg-if = "0.1.2"
+cfg-if = "1.0"
 tracing = "0.1"
 sha1 = { package = "sha-1", version = "0.10.0" }
 sha2 = "0.10.1"
index e62ce2c266aa04ca507edd377ab92672d193a336..221f65b66e6d4b77a1a0f63bc27acf3905e718b5 100644 (file)
 use std::hash::{Hash, Hasher};
 
 rustc_index::newtype_index! {
-    pub struct CrateNum {
-        ENCODABLE = custom
-        DEBUG_FORMAT = "crate{}"
-    }
+    #[custom_encodable]
+    #[debug_format = "crate{}"]
+    pub struct CrateNum {}
 }
 
 /// Item definitions in the currently-compiled crate would have the `CrateNum`
@@ -194,13 +193,12 @@ pub fn new(crate_name: Symbol, is_exe: bool, mut metadata: Vec<String>) -> Stabl
     /// A DefIndex is an index into the hir-map for a crate, identifying a
     /// particular definition. It should really be considered an interned
     /// shorthand for a particular DefPath.
+    #[custom_encodable] // (only encodable in metadata)
+    #[debug_format = "DefIndex({})"]
     pub struct DefIndex {
-        ENCODABLE = custom // (only encodable in metadata)
-
-        DEBUG_FORMAT = "DefIndex({})",
         /// The crate root is always assigned index 0 by the AST Map code,
         /// thanks to `NodeCollector::new`.
-        const CRATE_DEF_INDEX = 0,
+        const CRATE_DEF_INDEX = 0;
     }
 }
 
index 038699154c727dc72d9add71fc1e6ecc6f70b78c..c2d8287f2431dc3faa5cad0a1b0070e97257dc72 100644 (file)
@@ -61,9 +61,8 @@ pub struct SyntaxContextData {
 
 rustc_index::newtype_index! {
     /// A unique ID associated with a macro invocation and expansion.
-    pub struct ExpnIndex {
-        ENCODABLE = custom
-    }
+    #[custom_encodable]
+    pub struct ExpnIndex {}
 }
 
 /// A unique ID associated with a macro invocation and expansion.
@@ -82,11 +81,10 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 
 rustc_index::newtype_index! {
     /// A unique ID associated with a macro invocation and expansion.
-    pub struct LocalExpnId {
-        ENCODABLE = custom
-        ORD_IMPL = custom
-        DEBUG_FORMAT = "expn{}"
-    }
+    #[custom_encodable]
+    #[no_ord_impl]
+    #[debug_format = "expn{}"]
+    pub struct LocalExpnId {}
 }
 
 // To ensure correctness of incremental compilation,
index 5525eb5331c2776c82374222c7a47b32d7744573..2181c090027b535819aec1eb8afeb1851c0f4841 100644 (file)
@@ -259,6 +259,10 @@ pub fn to_string_lossy(&self, display_pref: FileNameDisplayPreference) -> Cow<'_
             FileNameDisplayPreference::Remapped => {
                 self.remapped_path_if_available().to_string_lossy()
             }
+            FileNameDisplayPreference::Short => self
+                .local_path_if_available()
+                .file_name()
+                .map_or_else(|| "".into(), |f| f.to_string_lossy()),
         }
     }
 }
@@ -302,6 +306,9 @@ pub enum FileNameDisplayPreference {
     /// Display the path before the application of rewrite rules provided via `--remap-path-prefix`.
     /// This is appropriate for use in user-facing output (such as diagnostics).
     Local,
+    /// Display only the filename, as a way to reduce the verbosity of the output.
+    /// This is appropriate for use in user-facing output (such as diagnostics).
+    Short,
 }
 
 pub struct FileNameDisplay<'a> {
index fb3e4a6c083f82d69661213a16bc4f538045f5ff..d9c87ac0ba82bfb6ecb0c9b3991dc6dee752ea44 100644 (file)
@@ -438,7 +438,11 @@ pub fn lookup_line(&self, pos: BytePos) -> Result<SourceFileAndLine, Lrc<SourceF
         }
     }
 
-    fn span_to_string(&self, sp: Span, filename_display_pref: FileNameDisplayPreference) -> String {
+    pub fn span_to_string(
+        &self,
+        sp: Span,
+        filename_display_pref: FileNameDisplayPreference,
+    ) -> String {
         if self.files.borrow().source_files.is_empty() || sp.is_dummy() {
             return "no-location".to_string();
         }
@@ -446,12 +450,15 @@ fn span_to_string(&self, sp: Span, filename_display_pref: FileNameDisplayPrefere
         let lo = self.lookup_char_pos(sp.lo());
         let hi = self.lookup_char_pos(sp.hi());
         format!(
-            "{}:{}:{}: {}:{}",
+            "{}:{}:{}{}",
             lo.file.name.display(filename_display_pref),
             lo.line,
             lo.col.to_usize() + 1,
-            hi.line,
-            hi.col.to_usize() + 1,
+            if let FileNameDisplayPreference::Short = filename_display_pref {
+                String::new()
+            } else {
+                format!(": {}:{}", hi.line, hi.col.to_usize() + 1)
+            }
         )
     }
 
index ace095736c92fd8a1a2e2b39c91b4c08b1ed6115..f23959b6e476d2fdc89f51b337fe62cbb5ce7a41 100644 (file)
         Capture,
         Center,
         Clone,
-        Context,
         Continue,
         Copy,
         Count,
         Relaxed,
         Release,
         Result,
+        ResumeTy,
         Return,
         Right,
         Rust,
         generic_associated_types_extended,
         generic_const_exprs,
         generic_param_attrs,
+        get_context,
         global_allocator,
         global_asm,
         globs,
@@ -1801,7 +1802,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 pub struct Symbol(SymbolIndex);
 
 rustc_index::newtype_index! {
-    struct SymbolIndex { .. }
+    struct SymbolIndex {}
 }
 
 impl Symbol {
index c9ddb084d63a12d2f5198bae6c2f19ec3493a12b..0845b1b6b096c600b124ec94690a231b4c5d6187 100644 (file)
@@ -99,13 +99,8 @@ fn is_c_void_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
         ty::Adt(adt_def, ..) => {
             let def_id = adt_def.0.did;
             let crate_name = tcx.crate_name(def_id.krate);
-            if tcx.item_name(def_id).as_str() == "c_void"
+            tcx.item_name(def_id).as_str() == "c_void"
                 && (crate_name == sym::core || crate_name == sym::std || crate_name == sym::libc)
-            {
-                true
-            } else {
-                false
-            }
         }
         _ => false,
     }
@@ -267,8 +262,7 @@ fn encode_predicates<'tcx>(
 ) -> String {
     // <predicate1[..predicateN]>E as part of vendor extended type
     let mut s = String::new();
-    let predicates: Vec<ty::PolyExistentialPredicate<'tcx>> =
-        predicates.iter().map(|predicate| predicate).collect();
+    let predicates: Vec<ty::PolyExistentialPredicate<'tcx>> = predicates.iter().collect();
     for predicate in predicates {
         s.push_str(&encode_predicate(tcx, predicate, dict, options));
     }
@@ -322,7 +316,7 @@ fn encode_substs<'tcx>(
 ) -> String {
     // [I<subst1..substN>E] as part of vendor extended type
     let mut s = String::new();
-    let substs: Vec<GenericArg<'_>> = substs.iter().map(|subst| subst).collect();
+    let substs: Vec<GenericArg<'_>> = substs.iter().collect();
     if !substs.is_empty() {
         s.push('I');
         for subst in substs {
@@ -703,11 +697,8 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio
                         tcx.layout_of(param_env.and(ty)).map_or(false, |layout| layout.is_zst());
                     !is_zst
                 });
-                if field.is_none() {
-                    // Transform repr(transparent) types without non-ZST field into ()
-                    ty = tcx.mk_unit();
-                } else {
-                    let ty0 = tcx.type_of(field.unwrap().did);
+                if let Some(field) = field {
+                    let ty0 = tcx.type_of(field.did);
                     // Generalize any repr(transparent) user-defined type that is either a pointer
                     // or reference, and either references itself or any other type that contains or
                     // references itself, to avoid a reference cycle.
@@ -720,6 +711,9 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio
                     } else {
                         ty = transform_ty(tcx, ty0, options);
                     }
+                } else {
+                    // Transform repr(transparent) types without non-ZST field into ()
+                    ty = tcx.mk_unit();
                 }
             } else {
                 ty = tcx.mk_adt(*adt_def, transform_substs(tcx, substs, options));
index 53c9878ab8740be4c8187d1eb90a07e9f350dbf0..88a0a1f8ecfdedafd60a8d9f6f516f488f06ca79 100644 (file)
@@ -20,9 +20,8 @@ fn to_json(&self) -> Json {
 }
 
 rustc_index::newtype_index! {
-    pub struct VariantIdx {
-        derive [HashStable_Generic]
-    }
+    #[derive(HashStable_Generic)]
+    pub struct VariantIdx {}
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)]
index aef2f8ff9911cc90b565bf27c02d946d0ffcd766..948632ccc6c40a87082f62225f42bd1b09ee68ba 100644 (file)
@@ -159,13 +159,12 @@ pub fn find_auto_trait_generics<A>(
             orig_env,
             orig_env,
             &mut fresh_preds,
-            false,
         ) else {
             return AutoTraitResult::NegativeImpl;
         };
 
         let (full_env, full_user_env) = self
-            .evaluate_predicates(&infcx, trait_did, ty, new_env, user_env, &mut fresh_preds, true)
+            .evaluate_predicates(&infcx, trait_did, ty, new_env, user_env, &mut fresh_preds)
             .unwrap_or_else(|| {
                 panic!("Failed to fully process: {:?} {:?} {:?}", ty, trait_did, orig_env)
             });
@@ -247,7 +246,6 @@ fn evaluate_predicates(
         param_env: ty::ParamEnv<'tcx>,
         user_env: ty::ParamEnv<'tcx>,
         fresh_preds: &mut FxHashSet<ty::Predicate<'tcx>>,
-        only_projections: bool,
     ) -> Option<(ty::ParamEnv<'tcx>, ty::ParamEnv<'tcx>)> {
         let tcx = infcx.tcx;
 
@@ -322,7 +320,6 @@ fn evaluate_predicates(
                         fresh_preds,
                         &mut predicates,
                         &mut select,
-                        only_projections,
                     ) {
                         return None;
                     }
@@ -600,7 +597,6 @@ fn evaluate_nested_obligations(
         fresh_preds: &mut FxHashSet<ty::Predicate<'tcx>>,
         predicates: &mut VecDeque<ty::PolyTraitPredicate<'tcx>>,
         selcx: &mut SelectionContext<'_, 'tcx>,
-        only_projections: bool,
     ) -> bool {
         let dummy_cause = ObligationCause::dummy();
 
@@ -744,7 +740,6 @@ fn evaluate_nested_obligations(
                                     fresh_preds,
                                     predicates,
                                     selcx,
-                                    only_projections,
                                 ) {
                                     return false;
                                 }
index 7c9fde27420bc2b12ba79a6d08083b507dc2b8ec..f8efe9bfa9f827b3d98c2544ebb544d73849e339 100644 (file)
@@ -138,10 +138,10 @@ pub fn is_const_evaluatable<'tcx>(
                 } else if uv.has_non_region_param() {
                     NotConstEvaluatable::MentionsParam
                 } else {
-                    let guar = infcx.tcx.sess.delay_span_bug(
-                        span,
-                        format!("Missing value for constant, but no error reported?"),
-                    );
+                    let guar = infcx
+                        .tcx
+                        .sess
+                        .delay_span_bug(span, "Missing value for constant, but no error reported?");
                     NotConstEvaluatable::Error(guar)
                 };
 
index 3c5e36123ecf56ac325a8a4badbf1922bc8990d9..8f317beaa77dd15c32a76fb0656ca732d8d1f3ae 100644 (file)
@@ -35,7 +35,7 @@
 use rustc_middle::ty::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::error::ExpectedFound;
 use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
-use rustc_middle::ty::print::{FmtPrinter, Print};
+use rustc_middle::ty::print::{with_forced_trimmed_paths, FmtPrinter, Print};
 use rustc_middle::ty::{
     self, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable,
     TypeVisitable,
@@ -226,7 +226,7 @@ fn report_arg_count_mismatch(
             let arg_length = arguments.len();
             let distinct = matches!(other, &[ArgKind::Tuple(..)]);
             match (arg_length, arguments.get(0)) {
-                (1, Some(&ArgKind::Tuple(_, ref fields))) => {
+                (1, Some(ArgKind::Tuple(_, fields))) => {
                     format!("a single {}-tuple as argument", fields.len())
                 }
                 _ => format!(
@@ -1574,7 +1574,7 @@ fn report_fulfillment_error(
                     &error.obligation.cause,
                     expected_found.expected,
                     expected_found.found,
-                    err.clone(),
+                    *err,
                 )
                 .emit();
             }
@@ -1583,7 +1583,7 @@ fn report_fulfillment_error(
                     &error.obligation.cause,
                     expected_found.expected,
                     expected_found.found,
-                    err.clone(),
+                    *err,
                 );
                 let code = error.obligation.cause.code().peel_derives().peel_match_impls();
                 if let ObligationCauseCode::BindingObligation(..)
@@ -1735,8 +1735,8 @@ fn report_projection_error(
                 values.map(|(_, is_normalized_ty_expected, normalized_ty, expected_ty)| {
                     infer::ValuePairs::Terms(ExpectedFound::new(
                         is_normalized_ty_expected,
-                        normalized_ty.into(),
-                        expected_ty.into(),
+                        normalized_ty,
+                        expected_ty,
                     ))
                 }),
                 err,
@@ -1757,21 +1757,26 @@ fn maybe_detailed_projection_msg(
         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.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
+        with_forced_trimmed_paths! {
+            if Some(pred.projection_ty.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
+            }
         }
     }
 
@@ -2307,18 +2312,19 @@ fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
                         let trait_impls = self.tcx.trait_impls_of(data.trait_ref.def_id);
 
                         if trait_impls.blanket_impls().is_empty()
-                            && let Some((impl_ty, _)) = trait_impls.non_blanket_impls().iter().next()
-                            && let Some(impl_def_id) = impl_ty.def() {
-                            let message = if trait_impls.non_blanket_impls().len() == 1 {
+                            && let Some(impl_def_id) = trait_impls.non_blanket_impls().values().flatten().next()
+                        {
+                            let non_blanket_impl_count = trait_impls.non_blanket_impls().values().flatten().count();
+                            let message = if non_blanket_impl_count == 1 {
                                 "use the fully-qualified path to the only available implementation".to_string()
                             } else {
                                 format!(
                                     "use a fully-qualified path to a specific available implementation ({} found)",
-                                    trait_impls.non_blanket_impls().len()
+                                    non_blanket_impl_count
                                 )
                             };
                             let mut suggestions = vec![(
-                                trait_path_segment.ident.span.shrink_to_lo(),
+                                path.span.shrink_to_lo(),
                                 format!("<{} as ", self.tcx.type_of(impl_def_id))
                             )];
                             if let Some(generic_arg) = trait_path_segment.args {
@@ -2326,9 +2332,9 @@ fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
                                 // get rid of :: between Trait and <type>
                                 // must be '::' between them, otherwise the parser won't accept the code
                                 suggestions.push((between_span, "".to_string(),));
-                                suggestions.push((generic_arg.span_ext.shrink_to_hi(), format!(">")));
+                                suggestions.push((generic_arg.span_ext.shrink_to_hi(), ">".to_string()));
                             } else {
-                                suggestions.push((trait_path_segment.ident.span.shrink_to_hi(), format!(">")));
+                                suggestions.push((trait_path_segment.ident.span.shrink_to_hi(), ">".to_string()));
                             }
                             err.multipart_suggestion(
                                 message,
index dd5085bf4f300d029f779b55f909eb5ae4e500bf..036e8f6d47bbaaf26bb2f041c2578e74ed0ac0d7 100644 (file)
@@ -352,6 +352,14 @@ fn point_at_chain(
         param_env: ty::ParamEnv<'tcx>,
         err: &mut Diagnostic,
     );
+    fn probe_assoc_types_at_expr(
+        &self,
+        type_diffs: &[TypeError<'tcx>],
+        span: Span,
+        prev_ty: Ty<'tcx>,
+        body_id: hir::HirId,
+        param_env: ty::ParamEnv<'tcx>,
+    ) -> Vec<Option<(Span, (DefId, Ty<'tcx>))>>;
 }
 
 fn predicate_constraint(generics: &hir::Generics<'_>, pred: ty::Predicate<'_>) -> (Span, String) {
@@ -1618,7 +1626,7 @@ fn suggest_impl_trait(
         let trait_obj = if has_dyn { &snippet[4..] } else { &snippet };
         if only_never_return {
             // No return paths, probably using `panic!()` or similar.
-            // Suggest `-> T`, `-> impl Trait`, and if `Trait` is object safe, `-> Box<dyn Trait>`.
+            // Suggest `-> impl Trait`, and if `Trait` is object safe, `-> Box<dyn Trait>`.
             suggest_trait_object_return_type_alternatives(
                 err,
                 ret_ty.span,
@@ -1781,7 +1789,7 @@ pub(crate) fn build_fn_sig_ty<'tcx>(
         self.note_conflicting_closure_bounds(cause, &mut err);
 
         if let Some(found_node) = found_node {
-            hint_missing_borrow(span, found_span, found, expected, found_node, &mut err);
+            hint_missing_borrow(span, found, expected, found_node, &mut err);
         }
 
         err
@@ -1804,10 +1812,10 @@ fn note_conflicting_closure_bounds(
             && self.tcx.is_fn_trait(trait_pred.def_id())
         {
             let expected_self =
-                self.tcx.anonymize_late_bound_regions(pred.kind().rebind(trait_pred.self_ty()));
+                self.tcx.anonymize_bound_vars(pred.kind().rebind(trait_pred.self_ty()));
             let expected_substs = self
                 .tcx
-                .anonymize_late_bound_regions(pred.kind().rebind(trait_pred.trait_ref.substs));
+                .anonymize_bound_vars(pred.kind().rebind(trait_pred.trait_ref.substs));
 
             // Find another predicate whose self-type is equal to the expected self type,
             // but whose substs don't match.
@@ -1820,12 +1828,12 @@ fn note_conflicting_closure_bounds(
                             // Make sure that the self type matches
                             // (i.e. constraining this closure)
                             && expected_self
-                                == self.tcx.anonymize_late_bound_regions(
+                                == self.tcx.anonymize_bound_vars(
                                     pred.kind().rebind(trait_pred.self_ty()),
                                 )
                             // But the substs don't match (i.e. incompatible args)
                             && expected_substs
-                                != self.tcx.anonymize_late_bound_regions(
+                                != self.tcx.anonymize_bound_vars(
                                     pred.kind().rebind(trait_pred.trait_ref.substs),
                                 ) =>
                     {
@@ -2336,28 +2344,33 @@ fn note_obligation_cause_for_async_await(
                 }
             }
             GeneratorInteriorOrUpvar::Upvar(upvar_span) => {
-                // `Some(ref_ty)` if `target_ty` is `&T` and `T` fails to impl `Sync`
-                let refers_to_non_sync = match target_ty.kind() {
-                    ty::Ref(_, ref_ty, _) => match self.evaluate_obligation(&obligation) {
-                        Ok(eval) if !eval.may_apply() => Some(ref_ty),
+                // `Some((ref_ty, is_mut))` if `target_ty` is `&T` or `&mut T` and fails to impl `Send`
+                let non_send = match target_ty.kind() {
+                    ty::Ref(_, ref_ty, mutability) => match self.evaluate_obligation(&obligation) {
+                        Ok(eval) if !eval.may_apply() => Some((ref_ty, mutability.is_mut())),
                         _ => None,
                     },
                     _ => None,
                 };
 
-                let (span_label, span_note) = match refers_to_non_sync {
-                    // if `target_ty` is `&T` and `T` fails to impl `Sync`,
-                    // include suggestions to make `T: Sync` so that `&T: Send`
-                    Some(ref_ty) => (
-                        format!(
-                            "has type `{}` which {}, because `{}` is not `Sync`",
-                            target_ty, trait_explanation, ref_ty
-                        ),
-                        format!(
-                            "captured value {} because `&` references cannot be sent unless their referent is `Sync`",
-                            trait_explanation
-                        ),
-                    ),
+                let (span_label, span_note) = match non_send {
+                    // if `target_ty` is `&T` or `&mut T` and fails to impl `Send`,
+                    // include suggestions to make `T: Sync` so that `&T: Send`,
+                    // or to make `T: Send` so that `&mut T: Send`
+                    Some((ref_ty, is_mut)) => {
+                        let ref_ty_trait = if is_mut { "Send" } else { "Sync" };
+                        let ref_kind = if is_mut { "&mut" } else { "&" };
+                        (
+                            format!(
+                                "has type `{}` which {}, because `{}` is not `{}`",
+                                target_ty, trait_explanation, ref_ty, ref_ty_trait
+                            ),
+                            format!(
+                                "captured value {} because `{}` references cannot be sent unless their referent is `{}`",
+                                trait_explanation, ref_kind, ref_ty_trait
+                            ),
+                        )
+                    }
                     None => (
                         format!("has type `{}` which {}", target_ty, trait_explanation),
                         format!("captured value {}", trait_explanation),
@@ -2540,6 +2553,25 @@ fn note_obligation_cause_code<T>(
             }
             ObligationCauseCode::SizedArgumentType(sp) => {
                 if let Some(span) = sp {
+                    if let ty::PredicateKind::Clause(clause) = predicate.kind().skip_binder()
+                        && let ty::Clause::Trait(trait_pred) = clause
+                        && let ty::Dynamic(..) = trait_pred.self_ty().kind()
+                    {
+                        let span = if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
+                            && snippet.starts_with("dyn ")
+                        {
+                            let pos = snippet.len() - snippet[3..].trim_start().len();
+                            span.with_hi(span.lo() + BytePos(pos as u32))
+                        } else {
+                            span.shrink_to_lo()
+                        };
+                        err.span_suggestion_verbose(
+                            span,
+                            "you can use `impl Trait` as the argument type",
+                            "impl ".to_string(),
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
                     err.span_suggestion_verbose(
                         span.shrink_to_lo(),
                         "function arguments must have a statically known size, borrowed types \
@@ -2713,7 +2745,7 @@ fn note_obligation_cause_code<T>(
                             }
                             ty::Closure(def_id, _) => err.span_note(
                                 self.tcx.def_span(def_id),
-                                &format!("required because it's used within this closure"),
+                                "required because it's used within this closure",
                             ),
                             _ => err.note(&msg),
                         };
@@ -3152,23 +3184,37 @@ fn function_argument_obligation(
             if let ObligationCauseCode::ExprBindingObligation(def_id, _, _, idx) = parent_code.deref()
                 && let predicates = self.tcx.predicates_of(def_id).instantiate_identity(self.tcx)
                 && let Some(pred) = predicates.predicates.get(*idx)
-                && let Ok(trait_pred) = pred.kind().try_map_bound(|pred| match pred {
-                    ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) => Ok(trait_pred),
-                    _ => Err(()),
-                })
             {
-                let mut c = CollectAllMismatches {
-                    infcx: self.infcx,
-                    param_env,
-                    errors: vec![],
-                };
-                if let Ok(trait_predicate) = predicate.kind().try_map_bound(|pred| match pred {
+                if let Ok(trait_pred) = pred.kind().try_map_bound(|pred| match pred {
                     ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) => Ok(trait_pred),
                     _ => Err(()),
-                }) {
+                })
+                    && let Ok(trait_predicate) = predicate.kind().try_map_bound(|pred| match pred {
+                        ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) => Ok(trait_pred),
+                        _ => Err(()),
+                    })
+                {
+                    let mut c = CollectAllMismatches {
+                        infcx: self.infcx,
+                        param_env,
+                        errors: vec![],
+                    };
                     if let Ok(_) = c.relate(trait_pred, trait_predicate) {
                         type_diffs = c.errors;
                     }
+                } else if let ty::PredicateKind::Clause(
+                    ty::Clause::Projection(proj)
+                ) = pred.kind().skip_binder()
+                    && let ty::PredicateKind::Clause(
+                        ty::Clause::Projection(projection)
+                    ) = predicate.kind().skip_binder()
+                {
+                    type_diffs = vec![
+                        Sorts(ty::error::ExpectedFound {
+                            expected: self.tcx.mk_ty(ty::Alias(ty::Projection, proj.projection_ty)),
+                            found: projection.term.ty().unwrap(),
+                        }),
+                    ];
                 }
             }
             if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
@@ -3221,10 +3267,8 @@ fn point_at_chain(
 
         let tcx = self.tcx;
 
+        let mut print_root_expr = true;
         let mut assocs = vec![];
-        // We still want to point at the different methods even if there hasn't
-        // been a change of assoc type.
-        let mut call_spans = vec![];
         let mut expr = expr;
         let mut prev_ty = self.resolve_vars_if_possible(
             typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error()),
@@ -3234,63 +3278,8 @@ fn point_at_chain(
             // vec![1, 2, 3].iter().map(mapper).sum<i32>()
             //               ^^^^^^ ^^^^^^^^^^^
             expr = rcvr_expr;
-            let mut assocs_in_this_method = Vec::with_capacity(type_diffs.len());
-            call_spans.push(span);
-
-            let ocx = ObligationCtxt::new_in_snapshot(self.infcx);
-            for diff in &type_diffs {
-                let Sorts(expected_found) = diff else { continue; };
-                let ty::Alias(ty::Projection, proj) = expected_found.expected.kind() else { continue; };
-
-                let origin =
-                    TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span };
-                let trait_def_id = proj.trait_def_id(self.tcx);
-                // Make `Self` be equivalent to the type of the call chain
-                // expression we're looking at now, so that we can tell what
-                // for example `Iterator::Item` is at this point in the chain.
-                let substs = InternalSubsts::for_item(self.tcx, trait_def_id, |param, _| {
-                    match param.kind {
-                        ty::GenericParamDefKind::Type { .. } => {
-                            if param.index == 0 {
-                                return prev_ty.into();
-                            }
-                        }
-                        ty::GenericParamDefKind::Lifetime
-                        | ty::GenericParamDefKind::Const { .. } => {}
-                    }
-                    self.var_for_def(span, param)
-                });
-                // This will hold the resolved type of the associated type, if the
-                // current expression implements the trait that associated type is
-                // in. For example, this would be what `Iterator::Item` is here.
-                let ty_var = self.infcx.next_ty_var(origin);
-                // This corresponds to `<ExprTy as Iterator>::Item = _`.
-                let projection = ty::Binder::dummy(ty::PredicateKind::Clause(
-                    ty::Clause::Projection(ty::ProjectionPredicate {
-                        projection_ty: tcx.mk_alias_ty(proj.def_id, substs),
-                        term: ty_var.into(),
-                    }),
-                ));
-                // Add `<ExprTy as Iterator>::Item = _` obligation.
-                ocx.register_obligation(Obligation::misc(
-                    self.tcx,
-                    span,
-                    expr.hir_id,
-                    param_env,
-                    projection,
-                ));
-                if ocx.select_where_possible().is_empty() {
-                    // `ty_var` now holds the type that `Item` is for `ExprTy`.
-                    let ty_var = self.resolve_vars_if_possible(ty_var);
-                    assocs_in_this_method.push(Some((span, (proj.def_id, ty_var))));
-                } else {
-                    // `<ExprTy as Iterator>` didn't select, so likely we've
-                    // reached the end of the iterator chain, like the originating
-                    // `Vec<_>`.
-                    // Keep the space consistent for later zipping.
-                    assocs_in_this_method.push(None);
-                }
-            }
+            let assocs_in_this_method =
+                self.probe_assoc_types_at_expr(&type_diffs, span, prev_ty, expr.hir_id, param_env);
             assocs.push(assocs_in_this_method);
             prev_ty = self.resolve_vars_if_possible(
                 typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error()),
@@ -3300,17 +3289,32 @@ fn point_at_chain(
                 && let hir::Path { res: hir::def::Res::Local(hir_id), .. } = path
                 && let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(*hir_id)
                 && let parent_hir_id = self.tcx.hir().get_parent_node(binding.hir_id)
-                && let Some(hir::Node::Local(local)) = self.tcx.hir().find(parent_hir_id)
-                && let Some(binding_expr) = local.init
+                && let Some(parent) = self.tcx.hir().find(parent_hir_id)
             {
-                // We've reached the root of the method call chain and it is a
-                // binding. Get the binding creation and try to continue the chain.
-                expr = binding_expr;
+                // We've reached the root of the method call chain...
+                if let hir::Node::Local(local) = parent
+                    && let Some(binding_expr) = local.init
+                {
+                    // ...and it is a binding. Get the binding creation and continue the chain.
+                    expr = binding_expr;
+                }
+                if let hir::Node::Param(param) = parent {
+                    // ...and it is a an fn argument.
+                    let prev_ty = self.resolve_vars_if_possible(
+                        typeck_results.node_type_opt(param.hir_id).unwrap_or(tcx.ty_error()),
+                    );
+                    let assocs_in_this_method = self.probe_assoc_types_at_expr(&type_diffs, param.ty_span, prev_ty, param.hir_id, param_env);
+                    if assocs_in_this_method.iter().any(|a| a.is_some()) {
+                        assocs.push(assocs_in_this_method);
+                        print_root_expr = false;
+                    }
+                    break;
+                }
             }
         }
         // We want the type before deref coercions, otherwise we talk about `&[_]`
         // instead of `Vec<_>`.
-        if let Some(ty) = typeck_results.expr_ty_opt(expr) {
+        if let Some(ty) = typeck_results.expr_ty_opt(expr) && print_root_expr {
             let ty = with_forced_trimmed_paths!(self.ty_to_string(ty));
             // Point at the root expression
             // vec![1, 2, 3].iter().map(mapper).sum<i32>()
@@ -3324,7 +3328,7 @@ fn point_at_chain(
             let Some(prev_assoc_in_method) = assocs.peek() else {
                 for entry in assocs_in_method {
                     let Some((span, (assoc, ty))) = entry else { continue; };
-                    if type_diffs.iter().any(|diff| {
+                    if primary_spans.is_empty() || type_diffs.iter().any(|diff| {
                         let Sorts(expected_found) = diff else { return false; };
                         self.can_eq(param_env, expected_found.found, ty).is_ok()
                     }) {
@@ -3353,7 +3357,7 @@ fn point_at_chain(
                         let ty_str = with_forced_trimmed_paths!(self.ty_to_string(ty));
 
                         let assoc = with_forced_trimmed_paths!(self.tcx.def_path_str(assoc));
-                        if ty != *prev_ty {
+                        if self.can_eq(param_env, ty, *prev_ty).is_err() {
                             if type_diffs.iter().any(|diff| {
                                 let Sorts(expected_found) = diff else { return false; };
                                 self.can_eq(param_env, expected_found.found, ty).is_ok()
@@ -3380,13 +3384,6 @@ fn point_at_chain(
                 }
             }
         }
-        for span in call_spans {
-            if span_labels.iter().find(|(s, _)| *s == span).is_none() {
-                // Ensure we are showing the entire chain, even if the assoc types
-                // haven't changed.
-                span_labels.push((span, String::new()));
-            }
-        }
         if !primary_spans.is_empty() {
             let mut multi_span: MultiSpan = primary_spans.into();
             for (span, label) in span_labels {
@@ -3394,19 +3391,75 @@ fn point_at_chain(
             }
             err.span_note(
                 multi_span,
-                format!(
-                    "the method call chain might not have had the expected \
-                                     associated types",
-                ),
+                "the method call chain might not have had the expected associated types",
             );
         }
     }
+
+    fn probe_assoc_types_at_expr(
+        &self,
+        type_diffs: &[TypeError<'tcx>],
+        span: Span,
+        prev_ty: Ty<'tcx>,
+        body_id: hir::HirId,
+        param_env: ty::ParamEnv<'tcx>,
+    ) -> Vec<Option<(Span, (DefId, Ty<'tcx>))>> {
+        let ocx = ObligationCtxt::new_in_snapshot(self.infcx);
+        let mut assocs_in_this_method = Vec::with_capacity(type_diffs.len());
+        for diff in type_diffs {
+            let Sorts(expected_found) = diff else { continue; };
+            let ty::Alias(ty::Projection, proj) = expected_found.expected.kind() else { continue; };
+
+            let origin = TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span };
+            let trait_def_id = proj.trait_def_id(self.tcx);
+            // Make `Self` be equivalent to the type of the call chain
+            // expression we're looking at now, so that we can tell what
+            // for example `Iterator::Item` is at this point in the chain.
+            let substs = InternalSubsts::for_item(self.tcx, trait_def_id, |param, _| {
+                match param.kind {
+                    ty::GenericParamDefKind::Type { .. } => {
+                        if param.index == 0 {
+                            return prev_ty.into();
+                        }
+                    }
+                    ty::GenericParamDefKind::Lifetime | ty::GenericParamDefKind::Const { .. } => {}
+                }
+                self.var_for_def(span, param)
+            });
+            // This will hold the resolved type of the associated type, if the
+            // current expression implements the trait that associated type is
+            // in. For example, this would be what `Iterator::Item` is here.
+            let ty_var = self.infcx.next_ty_var(origin);
+            // This corresponds to `<ExprTy as Iterator>::Item = _`.
+            let projection = ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::Projection(
+                ty::ProjectionPredicate {
+                    projection_ty: self.tcx.mk_alias_ty(proj.def_id, substs),
+                    term: ty_var.into(),
+                },
+            )));
+            // Add `<ExprTy as Iterator>::Item = _` obligation.
+            ocx.register_obligation(Obligation::misc(
+                self.tcx, span, body_id, param_env, projection,
+            ));
+            if ocx.select_where_possible().is_empty() {
+                // `ty_var` now holds the type that `Item` is for `ExprTy`.
+                let ty_var = self.resolve_vars_if_possible(ty_var);
+                assocs_in_this_method.push(Some((span, (proj.def_id, ty_var))));
+            } else {
+                // `<ExprTy as Iterator>` didn't select, so likely we've
+                // reached the end of the iterator chain, like the originating
+                // `Vec<_>`.
+                // Keep the space consistent for later zipping.
+                assocs_in_this_method.push(None);
+            }
+        }
+        assocs_in_this_method
+    }
 }
 
 /// Add a hint to add a missing borrow or remove an unnecessary one.
 fn hint_missing_borrow<'tcx>(
     span: Span,
-    found_span: Span,
     found: Ty<'tcx>,
     expected: Ty<'tcx>,
     found_node: Node<'_>,
@@ -3425,9 +3478,8 @@ fn hint_missing_borrow<'tcx>(
         }
     };
 
-    let fn_decl = found_node
-        .fn_decl()
-        .unwrap_or_else(|| span_bug!(found_span, "found node must be a function"));
+    // This could be a variant constructor, for example.
+    let Some(fn_decl) = found_node.fn_decl() else { return; };
 
     let arg_spans = fn_decl.inputs.iter().map(|ty| ty.span);
 
@@ -3580,13 +3632,6 @@ fn suggest_trait_object_return_type_alternatives(
     trait_obj: &str,
     is_object_safe: bool,
 ) {
-    err.span_suggestion(
-        ret_ty,
-        "use some type `T` that is `T: Sized` as the return type if all return paths have the \
-            same type",
-        "T",
-        Applicability::MaybeIncorrect,
-    );
     err.span_suggestion(
         ret_ty,
         &format!(
index a995eeb9a7afb8841b5539440c9df059dfd49484..0e0a883d9f5908ffcf0dfe5c41a34daa5c1639e2 100644 (file)
@@ -451,19 +451,21 @@ fn compute(&mut self, arg: GenericArg<'tcx>) {
                 GenericArgKind::Const(ct) => {
                     match ct.kind() {
                         ty::ConstKind::Unevaluated(uv) => {
-                            let obligations = self.nominal_obligations(uv.def.did, uv.substs);
-                            self.out.extend(obligations);
-
-                            let predicate =
-                                ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ct));
-                            let cause = self.cause(traits::WellFormed(None));
-                            self.out.push(traits::Obligation::with_depth(
-                                self.tcx(),
-                                cause,
-                                self.recursion_depth,
-                                self.param_env,
-                                predicate,
-                            ));
+                            if !ct.has_escaping_bound_vars() {
+                                let obligations = self.nominal_obligations(uv.def.did, uv.substs);
+                                self.out.extend(obligations);
+
+                                let predicate =
+                                    ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ct));
+                                let cause = self.cause(traits::WellFormed(None));
+                                self.out.push(traits::Obligation::with_depth(
+                                    self.tcx(),
+                                    cause,
+                                    self.recursion_depth,
+                                    self.param_env,
+                                    predicate,
+                                ));
+                            }
                         }
                         ty::ConstKind::Infer(_) => {
                             let cause = self.cause(traits::WellFormed(None));
index c2bc47bc043a0d358bf77a7826423b05cad1cedb..78fcceb5f2cb512a3d7ec17e201577a988ab0e9f 100644 (file)
@@ -123,7 +123,7 @@ pub(crate) fn concat(self, other: Self) -> Self {
             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();
+                let entry = entry.entry(edge).or_default();
                 for destination in destinations {
                     entry.insert(fix_state(destination));
                 }
@@ -147,7 +147,7 @@ pub(crate) fn union(self, other: Self) -> Self {
             }
             let entry = transitions.entry(source).or_default();
             for (edge, destinations) in transition {
-                let entry = entry.entry(edge.clone()).or_default();
+                let entry = entry.entry(*edge).or_default();
                 for &(mut destination) in destinations {
                     // if dest is accepting state of `other`, replace with accepting state of `self`
                     if destination == other.accepting {
index adab343ac98aaa4b225a4b2bcb790d3000f3c2ea..e4f3e7928da5a3eb54b57a13c589d8ba26300ae9 100644 (file)
@@ -76,11 +76,7 @@ fn is_accessible_from(&self, def: Self::Def, scope: Self::Scope) -> bool {
                 }
             };
 
-            let ret = if self.visibility(def_id).is_accessible_from(parent, *self) {
-                true
-            } else {
-                false
-            };
+            let ret: bool = self.visibility(def_id).is_accessible_from(parent, *self);
 
             trace!(?ret, "ret");
             ret
index c992dbccd62d5656439cc6ca72578f8656200075..dd36a5c7a2169af3af0ed9e267b46d5e0cfabd0b 100644 (file)
@@ -301,9 +301,9 @@ pub struct TypeFlags: u32 {
     ///
     /// [dbi]: https://en.wikipedia.org/wiki/De_Bruijn_index
     #[derive(HashStable_Generic)]
+    #[debug_format = "DebruijnIndex({})"]
     pub struct DebruijnIndex {
-        DEBUG_FORMAT = "DebruijnIndex({})",
-        const INNERMOST = 0,
+        const INNERMOST = 0;
     }
 }
 
@@ -499,9 +499,8 @@ pub enum IntVarValue {
 
 rustc_index::newtype_index! {
     /// A **ty**pe **v**ariable **ID**.
-    pub struct TyVid {
-        DEBUG_FORMAT = "_#{}t"
-    }
+    #[debug_format = "_#{}t"]
+    pub struct TyVid {}
 }
 
 /// An **int**egral (`u32`, `i32`, `usize`, etc.) type **v**ariable **ID**.
@@ -788,9 +787,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     /// type -- an idealized representative of "types in general" that we
     /// use for checking generic functions.
     #[derive(HashStable_Generic)]
-    pub struct UniverseIndex {
-        DEBUG_FORMAT = "U{}",
-    }
+    #[debug_format = "U{}"]
+    pub struct UniverseIndex {}
 }
 
 impl UniverseIndex {
index e5f6b0c0c65d2b0700dac2b59b8a353698644f3c..b154688fb087b94626f87e0a1f7af57d3f507ebb 100644 (file)
@@ -2033,7 +2033,7 @@ extern "rust-call" fn call(&self, args: Args) -> Self::Output {
     }
 }
 
-#[unstable(feature = "coerce_unsized", issue = "27732")]
+#[unstable(feature = "coerce_unsized", issue = "18598")]
 impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Box<U, A>> for Box<T, A> {}
 
 #[unstable(feature = "dispatch_from_dyn", issue = "none")]
index 4b9bd74d3924f49a93abb03a3e56b645566de6cf..c955db46d29fe11dae1fe3f2d38deed47dbe00ea 100644 (file)
@@ -535,12 +535,13 @@ impl<T> VecDeque<T> {
     ///
     /// let deque: VecDeque<u32> = VecDeque::new();
     /// ```
-    // FIXME: This should probably be const
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_stable(feature = "const_vec_deque_new", since = "CURRENT_RUSTC_VERSION")]
     #[must_use]
-    pub fn new() -> VecDeque<T> {
-        VecDeque::new_in(Global)
+    pub const fn new() -> VecDeque<T> {
+        // FIXME: This should just be `VecDeque::new_in(Global)` once that hits stable.
+        VecDeque { head: 0, len: 0, buf: RawVec::NEW }
     }
 
     /// Creates an empty deque with space for at least `capacity` elements.
@@ -2541,7 +2542,7 @@ pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result<usize
     /// The deque is assumed to be partitioned according to the given predicate.
     /// This means that all elements for which the predicate returns true are at the start of the deque
     /// and all elements for which the predicate returns false are at the end.
-    /// For example, [7, 15, 3, 5, 4, 12, 6] is a partitioned under the predicate x % 2 != 0
+    /// For example, `[7, 15, 3, 5, 4, 12, 6]` is partitioned under the predicate `x % 2 != 0`
     /// (all odd numbers are at the start, all even at the end).
     ///
     /// If the deque is not partitioned, the returned result is unspecified and meaningless,
index 799ce9d5daa888573c48100239baa23df32300d6..eadb35cb96d422cfcdc84250b820b7cef65ea54c 100644 (file)
 //!         // documentation for details, and the function `pad` can be used
 //!         // to pad strings.
 //!         let decimals = f.precision().unwrap_or(3);
-//!         let string = format!("{:.*}", decimals, magnitude);
+//!         let string = format!("{magnitude:.decimals$}");
 //!         f.pad_integral(true, "", &string)
 //!     }
 //! }
 //! write!(&mut some_writer, "{}", format_args!("print with a {}", "macro"));
 //!
 //! fn my_fmt_fn(args: fmt::Arguments) {
-//!     write!(&mut io::stdout(), "{}", args);
+//!     write!(&mut io::stdout(), "{args}");
 //! }
 //! my_fmt_fn(format_args!(", or a {} too", "function"));
 //! ```
index 38e31b1802a42f0ee0dcf2f10cb725ba3693e624..80a5913daa6e032720e832141d4105c6d8311106 100644 (file)
@@ -336,7 +336,7 @@ impl<T: RefUnwindSafe + ?Sized> UnwindSafe for Rc<T> {}
 #[stable(feature = "rc_ref_unwind_safe", since = "1.58.0")]
 impl<T: RefUnwindSafe + ?Sized> RefUnwindSafe for Rc<T> {}
 
-#[unstable(feature = "coerce_unsized", issue = "27732")]
+#[unstable(feature = "coerce_unsized", issue = "18598")]
 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Rc<U>> for Rc<T> {}
 
 #[unstable(feature = "dispatch_from_dyn", issue = "none")]
@@ -2190,7 +2190,7 @@ impl<T: ?Sized> !marker::Send for Weak<T> {}
 #[stable(feature = "rc_weak", since = "1.4.0")]
 impl<T: ?Sized> !marker::Sync for Weak<T> {}
 
-#[unstable(feature = "coerce_unsized", issue = "27732")]
+#[unstable(feature = "coerce_unsized", issue = "18598")]
 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Weak<U>> for Weak<T> {}
 
 #[unstable(feature = "dispatch_from_dyn", issue = "none")]
index f7dc4d1094ca3f8b1a0d160435ba6aa2653fa828..ddcd863aa3e338352b8d0a5ff9956e42cdfb0b10 100644 (file)
@@ -254,7 +254,7 @@ unsafe impl<T: ?Sized + Sync + Send> Sync for Arc<T> {}
 #[stable(feature = "catch_unwind", since = "1.9.0")]
 impl<T: RefUnwindSafe + ?Sized> UnwindSafe for Arc<T> {}
 
-#[unstable(feature = "coerce_unsized", issue = "27732")]
+#[unstable(feature = "coerce_unsized", issue = "18598")]
 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Arc<U>> for Arc<T> {}
 
 #[unstable(feature = "dispatch_from_dyn", issue = "none")]
@@ -306,7 +306,7 @@ unsafe impl<T: ?Sized + Sync + Send> Send for Weak<T> {}
 #[stable(feature = "arc_weak", since = "1.4.0")]
 unsafe impl<T: ?Sized + Sync + Send> Sync for Weak<T> {}
 
-#[unstable(feature = "coerce_unsized", issue = "27732")]
+#[unstable(feature = "coerce_unsized", issue = "18598")]
 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Weak<U>> for Weak<T> {}
 #[unstable(feature = "dispatch_from_dyn", issue = "none")]
 impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Weak<U>> for Weak<T> {}
index 94a1a1d32bcd66d7327c2a2a1142774cdcd33973..2825e0bbb438593a9217c8a490fd6161f5f2bcd0 100644 (file)
@@ -69,7 +69,7 @@
 /// if any element creation was unsuccessful.
 ///
 /// The return type of this function depends on the return type of the closure.
-/// If you return `Result<T, E>` from the closure, you'll get a `Result<[T; N]; E>`.
+/// If you return `Result<T, E>` from the closure, you'll get a `Result<[T; N], E>`.
 /// If you return `Option<T>` from the closure, you'll get an `Option<[T; N]>`.
 ///
 /// # Arguments
@@ -522,7 +522,7 @@ macro_rules! array_impl_default {
     /// return an array the same size as `self` or the first error encountered.
     ///
     /// The return type of this function depends on the return type of the closure.
-    /// If you return `Result<T, E>` from the closure, you'll get a `Result<[T; N]; E>`.
+    /// If you return `Result<T, E>` from the closure, you'll get a `Result<[T; N], E>`.
     /// If you return `Option<T>` from the closure, you'll get an `Option<[T; N]>`.
     ///
     /// # Examples
index 47cce2aa39b0c5fb8d4fb5b23b10a5c9b7204088..b4e173ce03d8a6b5ca911005712ab8daf4d217da 100644 (file)
@@ -568,7 +568,7 @@ pub fn take(&self) -> T {
     }
 }
 
-#[unstable(feature = "coerce_unsized", issue = "27732")]
+#[unstable(feature = "coerce_unsized", issue = "18598")]
 impl<T: CoerceUnsized<U>, U> CoerceUnsized<Cell<U>> for Cell<T> {}
 
 impl<T> Cell<[T]> {
@@ -1266,7 +1266,7 @@ fn from(t: T) -> RefCell<T> {
     }
 }
 
-#[unstable(feature = "coerce_unsized", issue = "27732")]
+#[unstable(feature = "coerce_unsized", issue = "18598")]
 impl<T: CoerceUnsized<U>, U> CoerceUnsized<RefCell<U>> for RefCell<T> {}
 
 struct BorrowRef<'b> {
@@ -1492,7 +1492,7 @@ pub fn leak(orig: Ref<'b, T>) -> &'b T {
     }
 }
 
-#[unstable(feature = "coerce_unsized", issue = "27732")]
+#[unstable(feature = "coerce_unsized", issue = "18598")]
 impl<'b, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Ref<'b, U>> for Ref<'b, T> {}
 
 #[stable(feature = "std_guard_impls", since = "1.20.0")]
@@ -1738,7 +1738,7 @@ fn deref_mut(&mut self) -> &mut T {
     }
 }
 
-#[unstable(feature = "coerce_unsized", issue = "27732")]
+#[unstable(feature = "coerce_unsized", issue = "18598")]
 impl<'b, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<RefMut<'b, U>> for RefMut<'b, T> {}
 
 #[stable(feature = "std_guard_impls", since = "1.20.0")]
@@ -2074,7 +2074,7 @@ fn from(t: T) -> UnsafeCell<T> {
     }
 }
 
-#[unstable(feature = "coerce_unsized", issue = "27732")]
+#[unstable(feature = "coerce_unsized", issue = "18598")]
 impl<T: CoerceUnsized<U>, U> CoerceUnsized<UnsafeCell<U>> for UnsafeCell<T> {}
 
 /// [`UnsafeCell`], but [`Sync`].
@@ -2164,7 +2164,7 @@ fn from(t: T) -> SyncUnsafeCell<T> {
     }
 }
 
-#[unstable(feature = "coerce_unsized", issue = "27732")]
+#[unstable(feature = "coerce_unsized", issue = "18598")]
 //#[unstable(feature = "sync_unsafe_cell", issue = "95439")]
 impl<T: CoerceUnsized<U>, U> CoerceUnsized<SyncUnsafeCell<U>> for SyncUnsafeCell<T> {}
 
index 9c0d7e9a1e89e25014d5d42809caecd70c485a7f..45e2f711c6c90f363e0947b4d0fb1d1a78cf6a6e 100644 (file)
@@ -168,6 +168,26 @@ macro_rules! impl_from_bool {
 // Float -> Float
 impl_from! { f32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
 
+// bool -> Float
+#[stable(feature = "float_from_bool", since = "CURRENT_RUSTC_VERSION")]
+#[rustc_const_unstable(feature = "const_num_from_num", issue = "87852")]
+impl const From<bool> for f32 {
+    /// Converts `bool` to `f32` losslessly.
+    #[inline]
+    fn from(small: bool) -> Self {
+        small as u8 as Self
+    }
+}
+#[stable(feature = "float_from_bool", since = "CURRENT_RUSTC_VERSION")]
+#[rustc_const_unstable(feature = "const_num_from_num", issue = "87852")]
+impl const From<bool> for f64 {
+    /// Converts `bool` to `f64` losslessly.
+    #[inline]
+    fn from(small: bool) -> Self {
+        small as u8 as Self
+    }
+}
+
 // no possible bounds violation
 macro_rules! try_from_unbounded {
     ($source:ty, $($target:ty),*) => {$(
index ec1eaa99f0b8e756cb4c7c713180a6368dfac458..76daceecd7befb3864e448fce6807bacb7a95025 100644 (file)
@@ -227,7 +227,12 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// Basic implementation of a `va_list`.
 // The name is WIP, using `VaListImpl` for now.
 #[cfg(any(
-    all(not(target_arch = "aarch64"), not(target_arch = "powerpc"), not(target_arch = "x86_64")),
+    all(
+        not(target_arch = "aarch64"),
+        not(target_arch = "powerpc"),
+        not(target_arch = "s390x"),
+        not(target_arch = "x86_64")
+    ),
     all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios")),
     target_family = "wasm",
     target_arch = "asmjs",
@@ -251,7 +256,12 @@ pub struct VaListImpl<'f> {
 }
 
 #[cfg(any(
-    all(not(target_arch = "aarch64"), not(target_arch = "powerpc"), not(target_arch = "x86_64")),
+    all(
+        not(target_arch = "aarch64"),
+        not(target_arch = "powerpc"),
+        not(target_arch = "s390x"),
+        not(target_arch = "x86_64")
+    ),
     all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios")),
     target_family = "wasm",
     target_arch = "asmjs",
@@ -319,6 +329,25 @@ pub struct VaListImpl<'f> {
     _marker: PhantomData<&'f mut &'f c_void>,
 }
 
+/// s390x ABI implementation of a `va_list`.
+#[cfg(target_arch = "s390x")]
+#[repr(C)]
+#[derive(Debug)]
+#[unstable(
+    feature = "c_variadic",
+    reason = "the `c_variadic` feature has not been properly tested on \
+              all supported platforms",
+    issue = "44930"
+)]
+#[lang = "va_list"]
+pub struct VaListImpl<'f> {
+    gpr: i64,
+    fpr: i64,
+    overflow_arg_area: *mut c_void,
+    reg_save_area: *mut c_void,
+    _marker: PhantomData<&'f mut &'f c_void>,
+}
+
 /// x86_64 ABI implementation of a `va_list`.
 #[cfg(all(target_arch = "x86_64", not(target_os = "uefi"), not(windows)))]
 #[repr(C)]
@@ -352,6 +381,7 @@ pub struct VaList<'a, 'f: 'a> {
         all(
             not(target_arch = "aarch64"),
             not(target_arch = "powerpc"),
+            not(target_arch = "s390x"),
             not(target_arch = "x86_64")
         ),
         all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios")),
@@ -363,7 +393,12 @@ pub struct VaList<'a, 'f: 'a> {
     inner: VaListImpl<'f>,
 
     #[cfg(all(
-        any(target_arch = "aarch64", target_arch = "powerpc", target_arch = "x86_64"),
+        any(
+            target_arch = "aarch64",
+            target_arch = "powerpc",
+            target_arch = "s390x",
+            target_arch = "x86_64"
+        ),
         any(not(target_arch = "aarch64"), not(any(target_os = "macos", target_os = "ios"))),
         not(target_family = "wasm"),
         not(target_arch = "asmjs"),
@@ -376,7 +411,12 @@ pub struct VaList<'a, 'f: 'a> {
 }
 
 #[cfg(any(
-    all(not(target_arch = "aarch64"), not(target_arch = "powerpc"), not(target_arch = "x86_64")),
+    all(
+        not(target_arch = "aarch64"),
+        not(target_arch = "powerpc"),
+        not(target_arch = "s390x"),
+        not(target_arch = "x86_64")
+    ),
     all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios")),
     target_family = "wasm",
     target_arch = "asmjs",
@@ -398,7 +438,12 @@ pub fn as_va_list<'a>(&'a mut self) -> VaList<'a, 'f> {
 }
 
 #[cfg(all(
-    any(target_arch = "aarch64", target_arch = "powerpc", target_arch = "x86_64"),
+    any(
+        target_arch = "aarch64",
+        target_arch = "powerpc",
+        target_arch = "s390x",
+        target_arch = "x86_64"
+    ),
     any(not(target_arch = "aarch64"), not(any(target_os = "macos", target_os = "ios"))),
     not(target_family = "wasm"),
     not(target_arch = "asmjs"),
index 48b6177434bcbea9d6b7f20f24f70b4809b025e5..5f4a666de928439750910fc044105108d7c7a612 100644 (file)
@@ -405,7 +405,7 @@ pub const fn new_v1(pieces: &'a [&'static str], args: &'a [ArgumentV1<'a>]) -> A
     /// 1. The `pieces` slice must be at least as long as `fmt`.
     /// 2. Every [`rt::v1::Argument::position`] value within `fmt` must be a
     ///    valid index of `args`.
-    /// 3. Every [`Count::Param`] within `fmt` must contain a valid index of
+    /// 3. Every [`rt::v1::Count::Param`] within `fmt` must contain a valid index of
     ///    `args`.
     #[doc(hidden)]
     #[inline]
@@ -2471,8 +2471,8 @@ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized> Pointer for *const T {
     fn fmt(&self, f: &mut Formatter<'_>) -> Result {
-        // Cast is needed here because `.addr()` requires `T: Sized`.
-        pointer_fmt_inner((*self as *const ()).addr(), f)
+        // Cast is needed here because `.expose_addr()` requires `T: Sized`.
+        pointer_fmt_inner((*self as *const ()).expose_addr(), f)
     }
 }
 
index 2a8e12fd4cf60fcc2bbc8aa749c500a6229f009c..f2b961d62e00c8149750785c3792cdf94924ce1d 100644 (file)
@@ -44,7 +44,7 @@
 ///    non-Send/Sync as well, and we don't want that.
 ///
 /// It also simplifies the HIR lowering of `.await`.
-// FIXME(swatinem): This type can be removed when bumping the bootstrap compiler
+#[cfg_attr(not(bootstrap), lang = "ResumeTy")]
 #[doc(hidden)]
 #[unstable(feature = "gen_future", issue = "50547")]
 #[derive(Debug, Copy, Clone)]
@@ -61,7 +61,6 @@ unsafe impl Sync for ResumeTy {}
 /// This function returns a `GenFuture` underneath, but hides it in `impl Trait` to give
 /// better error messages (`impl Future` rather than `GenFuture<[closure.....]>`).
 // This is `const` to avoid extra errors after we recover from `const async fn`
-// FIXME(swatinem): This fn can be removed when bumping the bootstrap compiler
 #[cfg_attr(bootstrap, lang = "from_generator")]
 #[doc(hidden)]
 #[unstable(feature = "gen_future", issue = "50547")]
@@ -103,8 +102,7 @@ fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
     GenFuture(gen)
 }
 
-// FIXME(swatinem): This fn can be removed when bumping the bootstrap compiler
-#[cfg_attr(bootstrap, lang = "get_context")]
+#[lang = "get_context"]
 #[doc(hidden)]
 #[unstable(feature = "gen_future", issue = "50547")]
 #[must_use]
@@ -115,10 +113,6 @@ pub unsafe fn get_context<'a, 'b>(cx: ResumeTy) -> &'a mut Context<'b> {
     unsafe { &mut *cx.0.as_ptr().cast() }
 }
 
-// FIXME(swatinem): This fn is currently needed to work around shortcomings
-// in type and lifetime inference.
-// See the comment at the bottom of `LoweringContext::make_async_expr` and
-// <https://github.com/rust-lang/rust/issues/104826>.
 #[cfg_attr(not(bootstrap), lang = "identity_future")]
 #[doc(hidden)]
 #[unstable(feature = "gen_future", issue = "50547")]
index 8ba1c122884ca431173cc28a77d33b6282e7169d..e08a15571fcbed0f74ccc42144202c8addfac029 100644 (file)
 //! #[custom_mir(dialect = "built")]
 //! pub fn simple(x: i32) -> i32 {
 //!     mir!(
-//!         let temp1: i32;
-//!         let temp2: _;
+//!         let temp2: i32;
 //!
 //!         {
-//!             temp1 = x;
-//!             Goto(exit)
+//!             let temp1 = x;
+//!             Goto(my_second_block)
 //!         }
 //!
-//!         exit = {
+//!         my_second_block = {
 //!             temp2 = Move(temp1);
 //!             RET = temp2;
 //!             Return()
 //! }
 //! ```
 //!
-//! Hopefully most of this is fairly self-explanatory. Expanding on some notable details:
+//! The `custom_mir` attribute tells the compiler to treat the function as being custom MIR. This
+//! attribute only works on functions - there is no way to insert custom MIR into the middle of
+//! another function. The `dialect` and `phase` parameters indicate which [version of MIR][dialect
+//! docs] you are inserting here. Generally you'll want to use `#![custom_mir(dialect = "built")]`
+//! if you want your MIR to be modified by the full MIR pipeline, or `#![custom_mir(dialect =
+//! "runtime", phase = "optimized")] if you don't.
 //!
-//!  - The `custom_mir` attribute tells the compiler to treat the function as being custom MIR. This
-//!    attribute only works on functions - there is no way to insert custom MIR into the middle of
-//!    another function.
-//!  - The `dialect` and `phase` parameters indicate which version of MIR you are inserting here.
-//!    This will normally be the phase that corresponds to the thing you are trying to test. The
-//!    phase can be omitted for dialects that have just one.
-//!  - You should define your function signature like you normally would. Externally, this function
-//!    can be called like any other function.
-//!  - Type inference works - you don't have to spell out the type of all of your locals.
+//! [dialect docs]:
+//!     https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/enum.MirPhase.html
 //!
-//! For now, all statements and terminators are parsed from nested invocations of the special
-//! functions provided in this module. We additionally want to (but do not yet) support more
-//! "normal" Rust syntax in places where it makes sense. Also, most kinds of instructions are not
-//! supported yet.
+//! The input to the [`mir!`] macro is:
+//!
+//!  - A possibly empty list of local declarations. Locals can also be declared inline on
+//!    assignments via `let`. Type inference generally works. Shadowing does not.
+//!  - A list of basic blocks. The first of these is the start block and is where execution begins.
+//!    All blocks other than the start block need to be given a name, so that they can be referred
+//!    to later.
+//!     - Each block is a list of semicolon terminated statements, followed by a terminator. The
+//!       syntax for the various statements and terminators is designed to be as similar as possible
+//!       to the syntax for analogous concepts in native Rust. See below for a list.
+//!
+//! # Examples
+//!
+//! ```rust
+//! #![feature(core_intrinsics, custom_mir)]
+//!
+//! extern crate core;
+//! use core::intrinsics::mir::*;
+//!
+//! #[custom_mir(dialect = "built")]
+//! pub fn choose_load(a: &i32, b: &i32, c: bool) -> i32 {
+//!     mir!(
+//!         {
+//!             match c {
+//!                 true => t,
+//!                 _ => f,
+//!             }
+//!         }
+//!
+//!         t = {
+//!             let temp = a;
+//!             Goto(load_and_exit)
+//!         }
+//!
+//!         f = {
+//!             temp = b;
+//!             Goto(load_and_exit)
+//!         }
+//!
+//!         load_and_exit = {
+//!             RET = *temp;
+//!             Return()
+//!         }
+//!     )
+//! }
+//!
+//! #[custom_mir(dialect = "built")]
+//! fn unwrap_unchecked<T>(opt: Option<T>) -> T {
+//!     mir!({
+//!         RET = Move(Field(Variant(opt, 1), 0));
+//!         Return()
+//!     })
+//! }
+//!
+//! #[custom_mir(dialect = "runtime", phase = "optimized")]
+//! fn push_and_pop<T>(v: &mut Vec<T>, value: T) {
+//!     mir!(
+//!         let unused;
+//!         let popped;
+//!
+//!         {
+//!             Call(unused, pop, Vec::push(v, value))
+//!         }
+//!
+//!         pop = {
+//!             Call(popped, drop, Vec::pop(v))
+//!         }
+//!
+//!         drop = {
+//!             Drop(popped, ret)
+//!         }
+//!
+//!         ret = {
+//!             Return()
+//!         }
+//!     )
+//! }
+//! ```
+//!
+//! We can also set off compilation failures that happen in sufficiently late stages of the
+//! compiler:
+//!
+//! ```rust,compile_fail
+//! #![feature(core_intrinsics, custom_mir)]
+//!
+//! extern crate core;
+//! use core::intrinsics::mir::*;
+//!
+//! #[custom_mir(dialect = "built")]
+//! fn borrow_error(should_init: bool) -> i32 {
+//!     mir!(
+//!         let temp: i32;
+//!
+//!         {
+//!             match should_init {
+//!                 true => init,
+//!                 _ => use_temp,
+//!             }
+//!         }
+//!
+//!         init = {
+//!             temp = 0;
+//!             Goto(use_temp)
+//!         }
+//!
+//!         use_temp = {
+//!             RET = temp;
+//!             Return()
+//!         }
+//!     )
+//! }
+//! ```
+//!
+//! ```text
+//! error[E0381]: used binding is possibly-uninitialized
+//!   --> test.rs:24:13
+//!    |
+//! 8  | /     mir!(
+//! 9  | |         let temp: i32;
+//! 10 | |
+//! 11 | |         {
+//! ...  |
+//! 19 | |             temp = 0;
+//!    | |             -------- binding initialized here in some conditions
+//! ...  |
+//! 24 | |             RET = temp;
+//!    | |             ^^^^^^^^^^ value used here but it is possibly-uninitialized
+//! 25 | |             Return()
+//! 26 | |         }
+//! 27 | |     )
+//!    | |_____- binding declared here but left uninitialized
+//!
+//! error: aborting due to previous error
+//!
+//! For more information about this error, try `rustc --explain E0381`.
+//! ```
+//!
+//! # Syntax
+//!
+//! The lists below are an exhaustive description of how various MIR constructs can be created.
+//! Anything missing from the list should be assumed to not be supported, PRs welcome.
+//!
+//! #### Locals
+//!
+//!  - The `_0` return local can always be accessed via `RET`.
+//!  - Arguments can be accessed via their regular name.
+//!  - All other locals need to be declared with `let` somewhere and then can be accessed by name.
+//!
+//! #### Places
+//!  - Locals implicit convert to places.
+//!  - Field accesses, derefs, and indexing work normally.
+//!  - Fields in variants can be accessed via the [`Variant`] and [`Field`] associated functions,
+//!    see their documentation for details.
+//!
+//! #### Operands
+//!  - Places implicitly convert to `Copy` operands.
+//!  - `Move` operands can be created via [`Move`].
+//!  - Const blocks, literals, named constants, and const params all just work.
+//!  - [`Static`] and [`StaticMut`] can be used to create `&T` and `*mut T`s to statics. These are
+//!    constants in MIR and the only way to access statics.
+//!
+//! #### Statements
+//!  - Assign statements work via normal Rust assignment.
+//!  - [`Retag`] statements have an associated function.
+//!
+//! #### Rvalues
+//!
+//!  - Operands implicitly convert to `Use` rvalues.
+//!  - `&`, `&mut`, `addr_of!`, and `addr_of_mut!` all work to create their associated rvalue.
+//!  - [`Discriminant`] has an associated function.
+//!
+//! #### Terminators
+//!
+//! Custom MIR does not currently support cleanup blocks or non-trivial unwind paths. As such, there
+//! are no resume and abort terminators, and terminators that might unwind do not have any way to
+//! indicate the unwind block.
+//!
+//!  - [`Goto`], [`Return`], [`Unreachable`], [`Drop`](Drop()), and [`DropAndReplace`] have associated functions.
+//!  - `match some_int_operand` becomes a `SwitchInt`. Each arm should be `literal => basic_block`
+//!     - The exception is the last arm, which must be `_ => basic_block` and corresponds to the
+//!       otherwise branch.
+//!  - [`Call`] has an associated function as well. The third argument of this function is a normal
+//!    function call expresion, for example `my_other_function(a, 5)`.
 //!
 
 #![unstable(
 pub struct BasicBlock;
 
 macro_rules! define {
-    ($name:literal, $($sig:tt)*) => {
+    ($name:literal, $( #[ $meta:meta ] )* fn $($sig:tt)*) => {
         #[rustc_diagnostic_item = $name]
-        pub $($sig)* { panic!() }
+        $( #[ $meta ] )*
+        pub fn $($sig)* { panic!() }
     }
 }
 
 define!("mir_return", fn Return() -> BasicBlock);
 define!("mir_goto", fn Goto(destination: BasicBlock) -> BasicBlock);
+define!("mir_unreachable", fn Unreachable() -> BasicBlock);
+define!("mir_drop", fn Drop<T>(place: T, goto: BasicBlock));
+define!("mir_drop_and_replace", fn DropAndReplace<T>(place: T, value: T, goto: BasicBlock));
+define!("mir_call", fn Call<T>(place: T, goto: BasicBlock, call: T));
 define!("mir_retag", fn Retag<T>(place: T));
 define!("mir_retag_raw", fn RetagRaw<T>(place: T));
 define!("mir_move", fn Move<T>(place: T) -> T);
 define!("mir_static", fn Static<T>(s: T) -> &'static T);
 define!("mir_static_mut", fn StaticMut<T>(s: T) -> *mut T);
+define!(
+    "mir_discriminant",
+    /// Gets the discriminant of a place.
+    fn Discriminant<T>(place: T) -> <T as ::core::marker::DiscriminantKind>::Discriminant
+);
+define!("mir_set_discriminant", fn SetDiscriminant<T>(place: T, index: u32));
+define!(
+    "mir_field",
+    /// Access the field with the given index of some place.
+    ///
+    /// This only makes sense to use in conjunction with [`Variant`]. If the type you are looking to
+    /// access the field of does not have variants, you can use normal field projection syntax.
+    ///
+    /// There is no proper way to do a place projection to a variant in Rust, and so these two
+    /// functions are a workaround. You can access a field of a variant via `Field(Variant(place,
+    /// var_idx), field_idx)`, where `var_idx` and `field_idx` are appropriate literals. Some
+    /// caveats:
+    ///
+    ///  - The return type of `Variant` is always `()`. Don't worry about that, the correct MIR will
+    ///    still be generated.
+    ///  - In some situations, the return type of `Field` cannot be inferred. You may need to
+    ///    annotate it on the function in these cases.
+    ///  - Since `Field` is a function call which is not a place expression, using this on the left
+    ///    hand side of an expression is rejected by the compiler. [`place!`] is a macro provided to
+    ///    work around that issue. Wrap the left hand side of an assignment in the macro to convince
+    ///    the compiler that it's ok.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// #![feature(custom_mir, core_intrinsics)]
+    ///
+    /// extern crate core;
+    /// use core::intrinsics::mir::*;
+    ///
+    /// #[custom_mir(dialect = "built")]
+    /// fn unwrap_deref(opt: Option<&i32>) -> i32 {
+    ///     mir!({
+    ///         RET = *Field::<&i32>(Variant(opt, 1), 0);
+    ///         Return()
+    ///     })
+    /// }
+    ///
+    /// #[custom_mir(dialect = "built")]
+    /// fn set(opt: &mut Option<i32>) {
+    ///     mir!({
+    ///         place!(Field(Variant(*opt, 1), 0)) = 5;
+    ///         Return()
+    ///     })
+    /// }
+    /// ```
+    fn Field<F>(place: (), field: u32) -> F
+);
+define!(
+    "mir_variant",
+    /// Adds a variant projection with the given index to the place.
+    ///
+    /// See [`Field`] for documentation.
+    fn Variant<T>(place: T, index: u32) -> ()
+);
+define!(
+    "mir_make_place",
+    #[doc(hidden)]
+    fn __internal_make_place<T>(place: T) -> *mut T
+);
 
-/// Convenience macro for generating custom MIR.
+/// Macro for generating custom MIR.
 ///
 /// See the module documentation for syntax details. This macro is not magic - it only transforms
 /// your MIR into something that is easier to parse in the compiler.
@@ -139,6 +385,13 @@ macro_rules! define {
     }}
 }
 
+/// Helper macro that allows you to treat a value expression like a place expression.
+///
+/// See the documentation on [`Variant`] for why this is necessary and how to use it.
+pub macro place($e:expr) {
+    (*::core::intrinsics::mir::__internal_make_place($e))
+}
+
 /// Helper macro that extracts the `let` declarations out of a bunch of statements.
 ///
 /// This macro is written using the "statement muncher" strategy. Each invocation parses the first
index 1cdee992137daebebe8cafa38c4786400d46e9fe..bac836292f8fa836c163823280463423b12b6700 100644 (file)
@@ -2734,7 +2734,7 @@ fn check<T, B>(mut f: impl FnMut(T) -> Option<B>) -> impl FnMut((), T) -> Contro
     /// the first true result or the first error.
     ///
     /// The return type of this method depends on the return type of the closure.
-    /// If you return `Result<bool, E>` from the closure, you'll get a `Result<Option<Self::Item>; E>`.
+    /// If you return `Result<bool, E>` from the closure, you'll get a `Result<Option<Self::Item>, E>`.
     /// If you return `Option<bool>` from the closure, you'll get an `Option<Option<Self::Item>>`.
     ///
     /// # Examples
index 42c342801976957a9696b25b92511653d313b918..4b85c1112b94096b8132b7607fc4c05368ff7196 100644 (file)
@@ -126,7 +126,7 @@ pub trait Sized {
 /// [`Rc`]: ../../std/rc/struct.Rc.html
 /// [RFC982]: https://github.com/rust-lang/rfcs/blob/master/text/0982-dst-coercion.md
 /// [nomicon-coerce]: ../../nomicon/coercions.html
-#[unstable(feature = "unsize", issue = "27732")]
+#[unstable(feature = "unsize", issue = "18598")]
 #[lang = "unsize"]
 #[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
 pub trait Unsize<T: ?Sized> {
index eb2a92f4644d11e8bc903cceb47ac527afbde4eb..97d9b750d92f9f3abc04cc742e93031101306092 100644 (file)
 #[unstable(feature = "generator_trait", issue = "43122")]
 pub use self::generator::{Generator, GeneratorState};
 
-#[unstable(feature = "coerce_unsized", issue = "27732")]
+#[unstable(feature = "coerce_unsized", issue = "18598")]
 pub use self::unsize::CoerceUnsized;
 
 #[unstable(feature = "dispatch_from_dyn", issue = "none")]
index a920b9165c18e2dc86bf1af173cb9746d79881a8..b51f12580ea4f6e7cf36a49ad27f4f307560095e 100644 (file)
 /// [dst-coerce]: https://github.com/rust-lang/rfcs/blob/master/text/0982-dst-coercion.md
 /// [unsize]: crate::marker::Unsize
 /// [nomicon-coerce]: ../../nomicon/coercions.html
-#[unstable(feature = "coerce_unsized", issue = "27732")]
+#[unstable(feature = "coerce_unsized", issue = "18598")]
 #[lang = "coerce_unsized"]
 pub trait CoerceUnsized<T: ?Sized> {
     // Empty.
 }
 
 // &mut T -> &mut U
-#[unstable(feature = "coerce_unsized", issue = "27732")]
+#[unstable(feature = "coerce_unsized", issue = "18598")]
 impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {}
 // &mut T -> &U
-#[unstable(feature = "coerce_unsized", issue = "27732")]
+#[unstable(feature = "coerce_unsized", issue = "18598")]
 impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b mut T {}
 // &mut T -> *mut U
-#[unstable(feature = "coerce_unsized", issue = "27732")]
+#[unstable(feature = "coerce_unsized", issue = "18598")]
 impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for &'a mut T {}
 // &mut T -> *const U
-#[unstable(feature = "coerce_unsized", issue = "27732")]
+#[unstable(feature = "coerce_unsized", issue = "18598")]
 impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for &'a mut T {}
 
 // &T -> &U
-#[unstable(feature = "coerce_unsized", issue = "27732")]
+#[unstable(feature = "coerce_unsized", issue = "18598")]
 impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
 // &T -> *const U
-#[unstable(feature = "coerce_unsized", issue = "27732")]
+#[unstable(feature = "coerce_unsized", issue = "18598")]
 impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for &'a T {}
 
 // *mut T -> *mut U
-#[unstable(feature = "coerce_unsized", issue = "27732")]
+#[unstable(feature = "coerce_unsized", issue = "18598")]
 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
 // *mut T -> *const U
-#[unstable(feature = "coerce_unsized", issue = "27732")]
+#[unstable(feature = "coerce_unsized", issue = "18598")]
 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *mut T {}
 
 // *const T -> *const U
-#[unstable(feature = "coerce_unsized", issue = "27732")]
+#[unstable(feature = "coerce_unsized", issue = "18598")]
 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
 
 /// `DispatchFromDyn` is used in the implementation of object safety checks (specifically allowing
index 4524fa4c48d2b8a062f1cf2d2b0cb9cdfa2da323..3f8acc8505ff10fa608f432fd466fd35d7d65f36 100644 (file)
@@ -485,6 +485,16 @@ impl<P: Deref<Target: Unpin>> Pin<P> {
     ///
     /// Unlike `Pin::new_unchecked`, this method is safe because the pointer
     /// `P` dereferences to an [`Unpin`] type, which cancels the pinning guarantees.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::pin::Pin;
+    ///
+    /// let mut val: u8 = 5;
+    /// // We can pin the value, since it doesn't care about being moved
+    /// let mut pinned: Pin<&mut u8> = Pin::new(&mut val);
+    /// ```
     #[inline(always)]
     #[rustc_const_unstable(feature = "const_pin", issue = "76654")]
     #[stable(feature = "pin", since = "1.33.0")]
@@ -496,8 +506,20 @@ pub const fn new(pointer: P) -> Pin<P> {
 
     /// Unwraps this `Pin<P>` returning the underlying pointer.
     ///
-    /// This requires that the data inside this `Pin` is [`Unpin`] so that we
+    /// This requires that the data inside this `Pin` implements [`Unpin`] so that we
     /// can ignore the pinning invariants when unwrapping it.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::pin::Pin;
+    ///
+    /// let mut val: u8 = 5;
+    /// let pinned: Pin<&mut u8> = Pin::new(&mut val);
+    /// // Unwrap the pin to get a reference to the value
+    /// let r = Pin::into_inner(pinned);
+    /// assert_eq!(*r, 5);
+    /// ```
     #[inline(always)]
     #[rustc_const_unstable(feature = "const_pin", issue = "76654")]
     #[stable(feature = "pin_into_inner", since = "1.39.0")]
@@ -707,6 +729,18 @@ pub fn as_mut(&mut self) -> Pin<&mut P::Target> {
     ///
     /// This overwrites pinned data, but that is okay: its destructor gets
     /// run before being overwritten, so no pinning guarantee is violated.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::pin::Pin;
+    ///
+    /// let mut val: u8 = 5;
+    /// let mut pinned: Pin<&mut u8> = Pin::new(&mut val);
+    /// println!("{}", pinned); // 5
+    /// pinned.as_mut().set(10);
+    /// println!("{}", pinned); // 10
+    /// ```
     #[stable(feature = "pin", since = "1.33.0")]
     #[inline(always)]
     pub fn set(&mut self, value: P::Target)
index c4348169c78c7e391e975f6d67cd9415264e8aa9..af79d4bbd836c027e8037ed1808afd6e762b07d6 100644 (file)
@@ -712,7 +712,7 @@ fn clone(&self) -> Self {
 #[stable(feature = "nonnull", since = "1.25.0")]
 impl<T: ?Sized> Copy for NonNull<T> {}
 
-#[unstable(feature = "coerce_unsized", issue = "27732")]
+#[unstable(feature = "coerce_unsized", issue = "18598")]
 impl<T: ?Sized, U: ?Sized> CoerceUnsized<NonNull<U>> for NonNull<T> where T: Unsize<U> {}
 
 #[unstable(feature = "dispatch_from_dyn", issue = "none")]
index d9281a9252c08057e162462071a9eb59d1355d5a..2c469f61854f3cb2acff0185738b73b8d7228bc6 100644 (file)
@@ -1002,6 +1002,17 @@ pub fn chunks_exact_mut(&mut self, chunk_size: usize) -> ChunksExactMut<'_, T> {
     /// assert_eq!(chunks, &[['l', 'o'], ['r', 'e']]);
     /// assert_eq!(remainder, &['m']);
     /// ```
+    ///
+    /// If you expect the slice to be an exact multiple, you can combine
+    /// `let`-`else` with an empty slice pattern:
+    /// ```
+    /// #![feature(slice_as_chunks)]
+    /// let slice = ['R', 'u', 's', 't'];
+    /// let (chunks, []) = slice.as_chunks::<2>() else {
+    ///     panic!("slice didn't have even length")
+    /// };
+    /// assert_eq!(chunks, &[['R', 'u'], ['s', 't']]);
+    /// ```
     #[unstable(feature = "slice_as_chunks", issue = "74985")]
     #[inline]
     #[must_use]
@@ -3795,7 +3806,7 @@ pub fn is_sorted_by_key<'a, F, K>(&'a self, f: F) -> bool
     /// The slice is assumed to be partitioned according to the given predicate.
     /// This means that all elements for which the predicate returns true are at the start of the slice
     /// and all elements for which the predicate returns false are at the end.
-    /// For example, [7, 15, 3, 5, 4, 12, 6] is a partitioned under the predicate x % 2 != 0
+    /// For example, `[7, 15, 3, 5, 4, 12, 6]` is partitioned under the predicate `x % 2 != 0`
     /// (all odd numbers are at the start, all even at the end).
     ///
     /// If this slice is not partitioned, the returned result is unspecified and meaningless,
index 9ab9b0ba1c79739548fc891ba34d5d0f33bb82dc..0cff972df3a5a8d4e961fe5fca309ab69a62b827 100644 (file)
@@ -174,7 +174,6 @@ pub const fn new(
 /// Currently, `Context` only serves to provide access to a [`&Waker`](Waker)
 /// which can be used to wake the current task.
 #[stable(feature = "futures_api", since = "1.36.0")]
-#[cfg_attr(not(bootstrap), lang = "Context")]
 pub struct Context<'a> {
     waker: &'a Waker,
     // Ensure we future-proof against variance changes by forcing
index 4748ac9d97ef8fda19d11f2d2f48e403ef466fae..b385ebde439794e9fc1b3fa0e526aec447a15031 100644 (file)
@@ -1567,3 +1567,31 @@ fn test_eq_direntry_metadata() {
         assert_eq!(ft1, ft2);
     }
 }
+
+/// Regression test for https://github.com/rust-lang/rust/issues/50619.
+#[test]
+#[cfg(target_os = "linux")]
+fn test_read_dir_infinite_loop() {
+    use crate::io::ErrorKind;
+    use crate::process::Command;
+
+    // Create a zombie child process
+    let Ok(mut child) = Command::new("echo").spawn() else { return };
+
+    // Make sure the process is (un)dead
+    match child.kill() {
+        // InvalidInput means the child already exited
+        Err(e) if e.kind() != ErrorKind::InvalidInput => return,
+        _ => {}
+    }
+
+    // open() on this path will succeed, but readdir() will fail
+    let id = child.id();
+    let path = format!("/proc/{id}/net");
+
+    // Skip the test if we can't open the directory in the first place
+    let Ok(dir) = fs::read_dir(path) else { return };
+
+    // Check for duplicate errors
+    assert!(dir.filter(|e| e.is_err()).take(2).count() < 2);
+}
index 6c957c2fa90eb517088f085687474dbc3b6d702a..73b5056e932672bc85e38a96de4920c10e3cb31e 100644 (file)
@@ -1748,6 +1748,14 @@ fn deref(&self) -> &Path {
     }
 }
 
+#[stable(feature = "path_buf_deref_mut", since = "CURRENT_RUSTC_VERSION")]
+impl ops::DerefMut for PathBuf {
+    #[inline]
+    fn deref_mut(&mut self) -> &mut Path {
+        Path::from_inner_mut(&mut self.inner)
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Borrow<Path> for PathBuf {
     #[inline]
@@ -2000,6 +2008,12 @@ pub fn new<S: AsRef<OsStr> + ?Sized>(s: &S) -> &Path {
         unsafe { &*(s.as_ref() as *const OsStr as *const Path) }
     }
 
+    fn from_inner_mut(inner: &mut OsStr) -> &mut Path {
+        // SAFETY: Path is just a wrapper around OsStr,
+        // therefore converting &mut OsStr to &mut Path is safe.
+        unsafe { &mut *(inner as *mut OsStr as *mut Path) }
+    }
+
     /// Yields the underlying [`OsStr`] slice.
     ///
     /// # Examples
@@ -2025,12 +2039,12 @@ pub fn as_os_str(&self) -> &OsStr {
     /// #![feature(path_as_mut_os_str)]
     /// use std::path::{Path, PathBuf};
     ///
-    /// let mut path = PathBuf::from("/Foo.TXT").into_boxed_path();
+    /// let mut path = PathBuf::from("Foo.TXT");
     ///
-    /// assert_ne!(&*path, Path::new("/foo.txt"));
+    /// assert_ne!(path, Path::new("foo.txt"));
     ///
     /// path.as_mut_os_str().make_ascii_lowercase();
-    /// assert_eq!(&*path, Path::new("/foo.txt"));
+    /// assert_eq!(path, Path::new("foo.txt"));
     /// ```
     #[unstable(feature = "path_as_mut_os_str", issue = "105021")]
     #[must_use]
index 400d25beb26f3d521387b5933e8a30ab6d1507b2..17aff342c1599455b2160b43b456bdb8f752246e 100644 (file)
@@ -362,6 +362,10 @@ fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
     fn is_read_vectored(&self) -> bool {
         self.inner.is_read_vectored()
     }
+
+    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        self.inner.read_to_end(buf)
+    }
 }
 
 impl AsInner<AnonPipe> for ChildStdout {
@@ -907,10 +911,8 @@ pub fn spawn(&mut self) -> io::Result<Child> {
     /// ```
     #[stable(feature = "process", since = "1.0.0")]
     pub fn output(&mut self) -> io::Result<Output> {
-        self.inner
-            .spawn(imp::Stdio::MakePipe, false)
-            .map(Child::from_inner)
-            .and_then(|p| p.wait_with_output())
+        let (status, stdout, stderr) = self.inner.output()?;
+        Ok(Output { status: ExitStatus(status), stdout, stderr })
     }
 
     /// Executes a command as a child process, waiting for it to finish and
index 818914a2df074d3f3d0ba46a57ef805f42dc6347..d5f50d77911fcafe3ef883f4f85cf3d808d3e223 100644 (file)
@@ -243,17 +243,15 @@ struct InnerReadDir {
 
 pub struct ReadDir {
     inner: Arc<InnerReadDir>,
-    #[cfg(not(any(
-        target_os = "android",
-        target_os = "linux",
-        target_os = "solaris",
-        target_os = "illumos",
-        target_os = "fuchsia",
-        target_os = "redox",
-    )))]
     end_of_stream: bool,
 }
 
+impl ReadDir {
+    fn new(inner: InnerReadDir) -> Self {
+        Self { inner: Arc::new(inner), end_of_stream: false }
+    }
+}
+
 struct Dir(*mut libc::DIR);
 
 unsafe impl Send for Dir {}
@@ -594,6 +592,10 @@ impl Iterator for ReadDir {
         target_os = "illumos"
     ))]
     fn next(&mut self) -> Option<io::Result<DirEntry>> {
+        if self.end_of_stream {
+            return None;
+        }
+
         unsafe {
             loop {
                 // As of POSIX.1-2017, readdir() is not required to be thread safe; only
@@ -604,8 +606,12 @@ fn next(&mut self) -> Option<io::Result<DirEntry>> {
                 super::os::set_errno(0);
                 let entry_ptr = readdir64(self.inner.dirp.0);
                 if entry_ptr.is_null() {
-                    // null can mean either the end is reached or an error occurred.
-                    // So we had to clear errno beforehand to check for an error now.
+                    // We either encountered an error, or reached the end.  Either way,
+                    // the next call to next() should return None.
+                    self.end_of_stream = true;
+
+                    // To distinguish between errors and end-of-directory, we had to clear
+                    // errno beforehand to check for an error now.
                     return match super::os::errno() {
                         0 => None,
                         e => Some(Err(Error::from_raw_os_error(e))),
@@ -1363,18 +1369,7 @@ pub fn readdir(path: &Path) -> io::Result<ReadDir> {
     } else {
         let root = path.to_path_buf();
         let inner = InnerReadDir { dirp: Dir(ptr), root };
-        Ok(ReadDir {
-            inner: Arc::new(inner),
-            #[cfg(not(any(
-                target_os = "android",
-                target_os = "linux",
-                target_os = "solaris",
-                target_os = "illumos",
-                target_os = "fuchsia",
-                target_os = "redox",
-            )))]
-            end_of_stream: false,
-        })
+        Ok(ReadDir::new(inner))
     }
 }
 
@@ -1755,7 +1750,6 @@ mod remove_dir_impl {
     use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
     use crate::os::unix::prelude::{OwnedFd, RawFd};
     use crate::path::{Path, PathBuf};
-    use crate::sync::Arc;
     use crate::sys::common::small_c_string::run_path_with_cstr;
     use crate::sys::{cvt, cvt_r};
 
@@ -1832,21 +1826,8 @@ fn fdreaddir(dir_fd: OwnedFd) -> io::Result<(ReadDir, RawFd)> {
         // a valid root is not needed because we do not call any functions involving the full path
         // of the DirEntrys.
         let dummy_root = PathBuf::new();
-        Ok((
-            ReadDir {
-                inner: Arc::new(InnerReadDir { dirp, root: dummy_root }),
-                #[cfg(not(any(
-                    target_os = "android",
-                    target_os = "linux",
-                    target_os = "solaris",
-                    target_os = "illumos",
-                    target_os = "fuchsia",
-                    target_os = "redox",
-                )))]
-                end_of_stream: false,
-            },
-            new_parent_fd,
-        ))
+        let inner = InnerReadDir { dirp, root: dummy_root };
+        Ok((ReadDir::new(inner), new_parent_fd))
     }
 
     #[cfg(any(
index a56c275c942071793a3e456ffa97260d5fb2f7fb..a744d0ab6404334e2b43512a5b81b9283a687a84 100644 (file)
@@ -58,6 +58,10 @@ pub fn is_read_vectored(&self) -> bool {
         self.0.is_read_vectored()
     }
 
+    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        self.0.read_to_end(buf)
+    }
+
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         self.0.write(buf)
     }
index 66ea3db2015a40fd3868d4a51077b5c29fda3ae2..4c99d758c93a3156e1ccfafe6252443c4f4468b5 100644 (file)
@@ -35,6 +35,11 @@ pub fn spawn(
         Ok((Process { handle: Handle::new(process_handle) }, ours))
     }
 
+    pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
+        let (proc, pipes) = self.spawn(Stdio::MakePipe, false)?;
+        crate::sys_common::process::wait_with_output(proc, pipes)
+    }
+
     pub fn exec(&mut self, default: Stdio) -> io::Error {
         if self.saw_nul() {
             return io::const_io_error!(
index c0716a089bc38b1b2b3be521c41165e259daeb46..39d1c8b1d8ebc75d0da500c882e4683bd167ba40 100644 (file)
@@ -133,6 +133,11 @@ pub fn spawn(
         }
     }
 
+    pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
+        let (proc, pipes) = self.spawn(Stdio::MakePipe, false)?;
+        crate::sys_common::process::wait_with_output(proc, pipes)
+    }
+
     // Attempts to fork the process. If successful, returns Ok((0, -1))
     // in the child, and Ok((child_pid, -1)) in the parent.
     #[cfg(not(target_os = "linux"))]
index 72f9f3f9ca74c0371427c67df9a337f1fe603db4..f28ca58d02038ade1af035abc4f7abc627455b0d 100644 (file)
@@ -20,6 +20,10 @@ pub fn spawn(
         unsupported()
     }
 
+    pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
+        unsupported()
+    }
+
     pub fn exec(&mut self, _default: Stdio) -> io::Error {
         unsupported_err()
     }
index 200ef6719679845ca7ed9076ebc7a23bc46ccbea..f549d37c301165fad9019ca014f5770398cdcf5c 100644 (file)
@@ -108,6 +108,11 @@ macro_rules! t {
         }
     }
 
+    pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
+        let (proc, pipes) = self.spawn(Stdio::MakePipe, false)?;
+        crate::sys_common::process::wait_with_output(proc, pipes)
+    }
+
     pub fn exec(&mut self, default: Stdio) -> io::Error {
         let ret = Command::spawn(self, default, false);
         match ret {
index 7bf6d40b76daa7746e676d85b9458362e6dcce14..15b22c620d583f64874d71d6fd91e0f077aab72b 100644 (file)
@@ -9,6 +9,7 @@
 pub mod io;
 pub mod locks;
 pub mod net;
+pub mod once;
 pub mod os;
 #[path = "../unix/os_str.rs"]
 pub mod os_str;
diff --git a/library/std/src/sys/unsupported/once.rs b/library/std/src/sys/unsupported/once.rs
new file mode 100644 (file)
index 0000000..b4bb497
--- /dev/null
@@ -0,0 +1,89 @@
+use crate::cell::Cell;
+use crate::sync as public;
+
+pub struct Once {
+    state: Cell<State>,
+}
+
+pub struct OnceState {
+    poisoned: bool,
+    set_state_to: Cell<State>,
+}
+
+#[derive(Clone, Copy, PartialEq, Eq)]
+enum State {
+    Incomplete,
+    Poisoned,
+    Running,
+    Complete,
+}
+
+struct CompletionGuard<'a> {
+    state: &'a Cell<State>,
+    set_state_on_drop_to: State,
+}
+
+impl<'a> Drop for CompletionGuard<'a> {
+    fn drop(&mut self) {
+        self.state.set(self.set_state_on_drop_to);
+    }
+}
+
+// Safety: threads are not supported on this platform.
+unsafe impl Sync for Once {}
+
+impl Once {
+    #[inline]
+    #[rustc_const_stable(feature = "const_once_new", since = "1.32.0")]
+    pub const fn new() -> Once {
+        Once { state: Cell::new(State::Incomplete) }
+    }
+
+    #[inline]
+    pub fn is_completed(&self) -> bool {
+        self.state.get() == State::Complete
+    }
+
+    #[cold]
+    #[track_caller]
+    pub fn call(&self, ignore_poisoning: bool, f: &mut impl FnMut(&public::OnceState)) {
+        let state = self.state.get();
+        match state {
+            State::Poisoned if !ignore_poisoning => {
+                // Panic to propagate the poison.
+                panic!("Once instance has previously been poisoned");
+            }
+            State::Incomplete | State::Poisoned => {
+                self.state.set(State::Running);
+                // `guard` will set the new state on drop.
+                let mut guard =
+                    CompletionGuard { state: &self.state, set_state_on_drop_to: State::Poisoned };
+                // Run the function, letting it know if we're poisoned or not.
+                let f_state = public::OnceState {
+                    inner: OnceState {
+                        poisoned: state == State::Poisoned,
+                        set_state_to: Cell::new(State::Complete),
+                    },
+                };
+                f(&f_state);
+                guard.set_state_on_drop_to = f_state.inner.set_state_to.get();
+            }
+            State::Running => {
+                panic!("one-time initialization may not be performed recursively");
+            }
+            State::Complete => {}
+        }
+    }
+}
+
+impl OnceState {
+    #[inline]
+    pub fn is_poisoned(&self) -> bool {
+        self.poisoned
+    }
+
+    #[inline]
+    pub fn poison(&self) {
+        self.set_state_to.set(State::Poisoned)
+    }
+}
index 25514c2322fa45d3890efeb67f86dc2a99b0c99c..0bba673b458cb690011d413db588dffb9bde88c1 100644 (file)
@@ -15,6 +15,10 @@ pub fn is_read_vectored(&self) -> bool {
         self.0
     }
 
+    pub fn read_to_end(&self, _buf: &mut Vec<u8>) -> io::Result<usize> {
+        self.0
+    }
+
     pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
         self.0
     }
index 633f17c054bc670c59d6f17c4a51003ba2c92e3b..a494f2d6b4c1529314c3a2a4b91184d9d6fa1697 100644 (file)
@@ -75,6 +75,10 @@ pub fn spawn(
     ) -> io::Result<(Process, StdioPipes)> {
         unsupported()
     }
+
+    pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
+        unsupported()
+    }
 }
 
 impl From<AnonPipe> for Stdio {
index c8c47763a340b30299e61d6fa4a358b82759c678..1dc3f2b20266dfa85e8a13d736231f58d6e1b4e5 100644 (file)
@@ -32,6 +32,8 @@
 #[path = "../unsupported/locks/mod.rs"]
 pub mod locks;
 pub mod net;
+#[path = "../unsupported/once.rs"]
+pub mod once;
 pub mod os;
 #[path = "../unix/os_str.rs"]
 pub mod os_str;
index d68c3e5f1dfbfaf281d0139c40bc2d337672b661..77ebe3c4ac6f5676e99ea5df211e4a48bb6fce4c 100644 (file)
@@ -66,6 +66,8 @@ pub mod locks {
     } else {
         #[path = "../unsupported/locks/mod.rs"]
         pub mod locks;
+        #[path = "../unsupported/once.rs"]
+        pub mod once;
         #[path = "../unsupported/thread.rs"]
         pub mod thread;
     }
index 9f26acc45205cde3ac32ffcf38747a5c8e0e7f95..7b25edaa556f082e211cf0f90ad07ba67181d29f 100644 (file)
@@ -1,7 +1,7 @@
 use crate::os::windows::prelude::*;
 
 use crate::ffi::OsStr;
-use crate::io::{self, IoSlice, IoSliceMut};
+use crate::io::{self, IoSlice, IoSliceMut, Read};
 use crate::mem;
 use crate::path::Path;
 use crate::ptr;
@@ -261,6 +261,10 @@ pub fn is_read_vectored(&self) -> bool {
         self.inner.is_read_vectored()
     }
 
+    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        self.handle().read_to_end(buf)
+    }
+
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         unsafe {
             let len = crate::cmp::min(buf.len(), c::DWORD::MAX as usize) as c::DWORD;
index 31e9b34fb9efdf1739cebdd4b100977fb5269af8..10bc949e1f45faf7c167e66e6b5c61a4c2aae980 100644 (file)
@@ -351,6 +351,11 @@ pub fn spawn(
             ))
         }
     }
+
+    pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
+        let (proc, pipes) = self.spawn(Stdio::MakePipe, false)?;
+        crate::sys_common::process::wait_with_output(proc, pipes)
+    }
 }
 
 impl fmt::Debug for Command {
diff --git a/library/std/src/sys_common/once/generic.rs b/library/std/src/sys_common/once/generic.rs
deleted file mode 100644 (file)
index d953a67..0000000
+++ /dev/null
@@ -1,283 +0,0 @@
-// Each `Once` has one word of atomic state, and this state is CAS'd on to
-// determine what to do. There are four possible state of a `Once`:
-//
-// * Incomplete - no initialization has run yet, and no thread is currently
-//                using the Once.
-// * Poisoned - some thread has previously attempted to initialize the Once, but
-//              it panicked, so the Once is now poisoned. There are no other
-//              threads currently accessing this Once.
-// * Running - some thread is currently attempting to run initialization. It may
-//             succeed, so all future threads need to wait for it to finish.
-//             Note that this state is accompanied with a payload, described
-//             below.
-// * Complete - initialization has completed and all future calls should finish
-//              immediately.
-//
-// With 4 states we need 2 bits to encode this, and we use the remaining bits
-// in the word we have allocated as a queue of threads waiting for the thread
-// responsible for entering the RUNNING state. This queue is just a linked list
-// of Waiter nodes which is monotonically increasing in size. Each node is
-// allocated on the stack, and whenever the running closure finishes it will
-// consume the entire queue and notify all waiters they should try again.
-//
-// You'll find a few more details in the implementation, but that's the gist of
-// it!
-//
-// Atomic orderings:
-// When running `Once` we deal with multiple atomics:
-// `Once.state_and_queue` and an unknown number of `Waiter.signaled`.
-// * `state_and_queue` is used (1) as a state flag, (2) for synchronizing the
-//   result of the `Once`, and (3) for synchronizing `Waiter` nodes.
-//     - At the end of the `call` function we have to make sure the result
-//       of the `Once` is acquired. So every load which can be the only one to
-//       load COMPLETED must have at least acquire ordering, which means all
-//       three of them.
-//     - `WaiterQueue::drop` is the only place that may store COMPLETED, and
-//       must do so with release ordering to make the result available.
-//     - `wait` inserts `Waiter` nodes as a pointer in `state_and_queue`, and
-//       needs to make the nodes available with release ordering. The load in
-//       its `compare_exchange` can be relaxed because it only has to compare
-//       the atomic, not to read other data.
-//     - `WaiterQueue::drop` must see the `Waiter` nodes, so it must load
-//       `state_and_queue` with acquire ordering.
-//     - There is just one store where `state_and_queue` is used only as a
-//       state flag, without having to synchronize data: switching the state
-//       from INCOMPLETE to RUNNING in `call`. This store can be Relaxed,
-//       but the read has to be Acquire because of the requirements mentioned
-//       above.
-// * `Waiter.signaled` is both used as a flag, and to protect a field with
-//   interior mutability in `Waiter`. `Waiter.thread` is changed in
-//   `WaiterQueue::drop` which then sets `signaled` with release ordering.
-//   After `wait` loads `signaled` with acquire ordering and sees it is true,
-//   it needs to see the changes to drop the `Waiter` struct correctly.
-// * There is one place where the two atomics `Once.state_and_queue` and
-//   `Waiter.signaled` come together, and might be reordered by the compiler or
-//   processor. Because both use acquire ordering such a reordering is not
-//   allowed, so no need for `SeqCst`.
-
-use crate::cell::Cell;
-use crate::fmt;
-use crate::ptr;
-use crate::sync as public;
-use crate::sync::atomic::{AtomicBool, AtomicPtr, Ordering};
-use crate::thread::{self, Thread};
-
-type Masked = ();
-
-pub struct Once {
-    state_and_queue: AtomicPtr<Masked>,
-}
-
-pub struct OnceState {
-    poisoned: bool,
-    set_state_on_drop_to: Cell<*mut Masked>,
-}
-
-// Four states that a Once can be in, encoded into the lower bits of
-// `state_and_queue` in the Once structure.
-const INCOMPLETE: usize = 0x0;
-const POISONED: usize = 0x1;
-const RUNNING: usize = 0x2;
-const COMPLETE: usize = 0x3;
-
-// Mask to learn about the state. All other bits are the queue of waiters if
-// this is in the RUNNING state.
-const STATE_MASK: usize = 0x3;
-
-// Representation of a node in the linked list of waiters, used while in the
-// RUNNING state.
-// Note: `Waiter` can't hold a mutable pointer to the next thread, because then
-// `wait` would both hand out a mutable reference to its `Waiter` node, and keep
-// a shared reference to check `signaled`. Instead we hold shared references and
-// use interior mutability.
-#[repr(align(4))] // Ensure the two lower bits are free to use as state bits.
-struct Waiter {
-    thread: Cell<Option<Thread>>,
-    signaled: AtomicBool,
-    next: *const Waiter,
-}
-
-// Head of a linked list of waiters.
-// Every node is a struct on the stack of a waiting thread.
-// Will wake up the waiters when it gets dropped, i.e. also on panic.
-struct WaiterQueue<'a> {
-    state_and_queue: &'a AtomicPtr<Masked>,
-    set_state_on_drop_to: *mut Masked,
-}
-
-impl Once {
-    #[inline]
-    #[rustc_const_stable(feature = "const_once_new", since = "1.32.0")]
-    pub const fn new() -> Once {
-        Once { state_and_queue: AtomicPtr::new(ptr::invalid_mut(INCOMPLETE)) }
-    }
-
-    #[inline]
-    pub fn is_completed(&self) -> bool {
-        // An `Acquire` load is enough because that makes all the initialization
-        // operations visible to us, and, this being a fast path, weaker
-        // ordering helps with performance. This `Acquire` synchronizes with
-        // `Release` operations on the slow path.
-        self.state_and_queue.load(Ordering::Acquire).addr() == COMPLETE
-    }
-
-    // This is a non-generic function to reduce the monomorphization cost of
-    // using `call_once` (this isn't exactly a trivial or small implementation).
-    //
-    // Additionally, this is tagged with `#[cold]` as it should indeed be cold
-    // and it helps let LLVM know that calls to this function should be off the
-    // fast path. Essentially, this should help generate more straight line code
-    // in LLVM.
-    //
-    // Finally, this takes an `FnMut` instead of a `FnOnce` because there's
-    // currently no way to take an `FnOnce` and call it via virtual dispatch
-    // without some allocation overhead.
-    #[cold]
-    #[track_caller]
-    pub fn call(&self, ignore_poisoning: bool, init: &mut dyn FnMut(&public::OnceState)) {
-        let mut state_and_queue = self.state_and_queue.load(Ordering::Acquire);
-        loop {
-            match state_and_queue.addr() {
-                COMPLETE => break,
-                POISONED if !ignore_poisoning => {
-                    // Panic to propagate the poison.
-                    panic!("Once instance has previously been poisoned");
-                }
-                POISONED | INCOMPLETE => {
-                    // Try to register this thread as the one RUNNING.
-                    let exchange_result = self.state_and_queue.compare_exchange(
-                        state_and_queue,
-                        ptr::invalid_mut(RUNNING),
-                        Ordering::Acquire,
-                        Ordering::Acquire,
-                    );
-                    if let Err(old) = exchange_result {
-                        state_and_queue = old;
-                        continue;
-                    }
-                    // `waiter_queue` will manage other waiting threads, and
-                    // wake them up on drop.
-                    let mut waiter_queue = WaiterQueue {
-                        state_and_queue: &self.state_and_queue,
-                        set_state_on_drop_to: ptr::invalid_mut(POISONED),
-                    };
-                    // Run the initialization function, letting it know if we're
-                    // poisoned or not.
-                    let init_state = public::OnceState {
-                        inner: OnceState {
-                            poisoned: state_and_queue.addr() == POISONED,
-                            set_state_on_drop_to: Cell::new(ptr::invalid_mut(COMPLETE)),
-                        },
-                    };
-                    init(&init_state);
-                    waiter_queue.set_state_on_drop_to = init_state.inner.set_state_on_drop_to.get();
-                    break;
-                }
-                _ => {
-                    // All other values must be RUNNING with possibly a
-                    // pointer to the waiter queue in the more significant bits.
-                    assert!(state_and_queue.addr() & STATE_MASK == RUNNING);
-                    wait(&self.state_and_queue, state_and_queue);
-                    state_and_queue = self.state_and_queue.load(Ordering::Acquire);
-                }
-            }
-        }
-    }
-}
-
-fn wait(state_and_queue: &AtomicPtr<Masked>, mut current_state: *mut Masked) {
-    // Note: the following code was carefully written to avoid creating a
-    // mutable reference to `node` that gets aliased.
-    loop {
-        // Don't queue this thread if the status is no longer running,
-        // otherwise we will not be woken up.
-        if current_state.addr() & STATE_MASK != RUNNING {
-            return;
-        }
-
-        // Create the node for our current thread.
-        let node = Waiter {
-            thread: Cell::new(Some(thread::current())),
-            signaled: AtomicBool::new(false),
-            next: current_state.with_addr(current_state.addr() & !STATE_MASK) as *const Waiter,
-        };
-        let me = &node as *const Waiter as *const Masked as *mut Masked;
-
-        // Try to slide in the node at the head of the linked list, making sure
-        // that another thread didn't just replace the head of the linked list.
-        let exchange_result = state_and_queue.compare_exchange(
-            current_state,
-            me.with_addr(me.addr() | RUNNING),
-            Ordering::Release,
-            Ordering::Relaxed,
-        );
-        if let Err(old) = exchange_result {
-            current_state = old;
-            continue;
-        }
-
-        // We have enqueued ourselves, now lets wait.
-        // It is important not to return before being signaled, otherwise we
-        // would drop our `Waiter` node and leave a hole in the linked list
-        // (and a dangling reference). Guard against spurious wakeups by
-        // reparking ourselves until we are signaled.
-        while !node.signaled.load(Ordering::Acquire) {
-            // If the managing thread happens to signal and unpark us before we
-            // can park ourselves, the result could be this thread never gets
-            // unparked. Luckily `park` comes with the guarantee that if it got
-            // an `unpark` just before on an unparked thread it does not park.
-            thread::park();
-        }
-        break;
-    }
-}
-
-#[stable(feature = "std_debug", since = "1.16.0")]
-impl fmt::Debug for Once {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("Once").finish_non_exhaustive()
-    }
-}
-
-impl Drop for WaiterQueue<'_> {
-    fn drop(&mut self) {
-        // Swap out our state with however we finished.
-        let state_and_queue =
-            self.state_and_queue.swap(self.set_state_on_drop_to, Ordering::AcqRel);
-
-        // We should only ever see an old state which was RUNNING.
-        assert_eq!(state_and_queue.addr() & STATE_MASK, RUNNING);
-
-        // Walk the entire linked list of waiters and wake them up (in lifo
-        // order, last to register is first to wake up).
-        unsafe {
-            // Right after setting `node.signaled = true` the other thread may
-            // free `node` if there happens to be has a spurious wakeup.
-            // So we have to take out the `thread` field and copy the pointer to
-            // `next` first.
-            let mut queue =
-                state_and_queue.with_addr(state_and_queue.addr() & !STATE_MASK) as *const Waiter;
-            while !queue.is_null() {
-                let next = (*queue).next;
-                let thread = (*queue).thread.take().unwrap();
-                (*queue).signaled.store(true, Ordering::Release);
-                // ^- FIXME (maybe): This is another case of issue #55005
-                // `store()` has a potentially dangling ref to `signaled`.
-                queue = next;
-                thread.unpark();
-            }
-        }
-    }
-}
-
-impl OnceState {
-    #[inline]
-    pub fn is_poisoned(&self) -> bool {
-        self.poisoned
-    }
-
-    #[inline]
-    pub fn poison(&self) {
-        self.set_state_on_drop_to.set(ptr::invalid_mut(POISONED));
-    }
-}
index 8742e68cc7ac5901cb904df5bd2bb8afc3758c66..359697d8313170cc85934788db29e7ebaf6c7d70 100644 (file)
@@ -6,22 +6,6 @@
 // As a result, we end up implementing it ourselves in the standard library.
 // This also gives us the opportunity to optimize the implementation a bit which
 // should help the fast path on call sites.
-//
-// So to recap, the guarantees of a Once are that it will call the
-// initialization closure at most once, and it will never return until the one
-// that's running has finished running. This means that we need some form of
-// blocking here while the custom callback is running at the very least.
-// Additionally, we add on the restriction of **poisoning**. Whenever an
-// initialization closure panics, the Once enters a "poisoned" state which means
-// that all future calls will immediately panic as well.
-//
-// So to implement this, one might first reach for a `Mutex`, but those cannot
-// be put into a `static`. It also gets a lot harder with poisoning to figure
-// out when the mutex needs to be deallocated because it's not after the closure
-// finishes, but after the first successful closure finishes.
-//
-// All in all, this is instead implemented with atomics and lock-free
-// operations! Whee!
 
 cfg_if::cfg_if! {
     if #[cfg(any(
     ))] {
         mod futex;
         pub use futex::{Once, OnceState};
+    } else if #[cfg(any(
+        windows,
+        target_family = "unix",
+        all(target_vendor = "fortanix", target_env = "sgx"),
+        target_os = "solid_asp3",
+    ))] {
+        mod queue;
+        pub use queue::{Once, OnceState};
     } else {
-        mod generic;
-        pub use generic::{Once, OnceState};
+        pub use crate::sys::once::{Once, OnceState};
     }
 }
diff --git a/library/std/src/sys_common/once/queue.rs b/library/std/src/sys_common/once/queue.rs
new file mode 100644 (file)
index 0000000..d953a67
--- /dev/null
@@ -0,0 +1,283 @@
+// Each `Once` has one word of atomic state, and this state is CAS'd on to
+// determine what to do. There are four possible state of a `Once`:
+//
+// * Incomplete - no initialization has run yet, and no thread is currently
+//                using the Once.
+// * Poisoned - some thread has previously attempted to initialize the Once, but
+//              it panicked, so the Once is now poisoned. There are no other
+//              threads currently accessing this Once.
+// * Running - some thread is currently attempting to run initialization. It may
+//             succeed, so all future threads need to wait for it to finish.
+//             Note that this state is accompanied with a payload, described
+//             below.
+// * Complete - initialization has completed and all future calls should finish
+//              immediately.
+//
+// With 4 states we need 2 bits to encode this, and we use the remaining bits
+// in the word we have allocated as a queue of threads waiting for the thread
+// responsible for entering the RUNNING state. This queue is just a linked list
+// of Waiter nodes which is monotonically increasing in size. Each node is
+// allocated on the stack, and whenever the running closure finishes it will
+// consume the entire queue and notify all waiters they should try again.
+//
+// You'll find a few more details in the implementation, but that's the gist of
+// it!
+//
+// Atomic orderings:
+// When running `Once` we deal with multiple atomics:
+// `Once.state_and_queue` and an unknown number of `Waiter.signaled`.
+// * `state_and_queue` is used (1) as a state flag, (2) for synchronizing the
+//   result of the `Once`, and (3) for synchronizing `Waiter` nodes.
+//     - At the end of the `call` function we have to make sure the result
+//       of the `Once` is acquired. So every load which can be the only one to
+//       load COMPLETED must have at least acquire ordering, which means all
+//       three of them.
+//     - `WaiterQueue::drop` is the only place that may store COMPLETED, and
+//       must do so with release ordering to make the result available.
+//     - `wait` inserts `Waiter` nodes as a pointer in `state_and_queue`, and
+//       needs to make the nodes available with release ordering. The load in
+//       its `compare_exchange` can be relaxed because it only has to compare
+//       the atomic, not to read other data.
+//     - `WaiterQueue::drop` must see the `Waiter` nodes, so it must load
+//       `state_and_queue` with acquire ordering.
+//     - There is just one store where `state_and_queue` is used only as a
+//       state flag, without having to synchronize data: switching the state
+//       from INCOMPLETE to RUNNING in `call`. This store can be Relaxed,
+//       but the read has to be Acquire because of the requirements mentioned
+//       above.
+// * `Waiter.signaled` is both used as a flag, and to protect a field with
+//   interior mutability in `Waiter`. `Waiter.thread` is changed in
+//   `WaiterQueue::drop` which then sets `signaled` with release ordering.
+//   After `wait` loads `signaled` with acquire ordering and sees it is true,
+//   it needs to see the changes to drop the `Waiter` struct correctly.
+// * There is one place where the two atomics `Once.state_and_queue` and
+//   `Waiter.signaled` come together, and might be reordered by the compiler or
+//   processor. Because both use acquire ordering such a reordering is not
+//   allowed, so no need for `SeqCst`.
+
+use crate::cell::Cell;
+use crate::fmt;
+use crate::ptr;
+use crate::sync as public;
+use crate::sync::atomic::{AtomicBool, AtomicPtr, Ordering};
+use crate::thread::{self, Thread};
+
+type Masked = ();
+
+pub struct Once {
+    state_and_queue: AtomicPtr<Masked>,
+}
+
+pub struct OnceState {
+    poisoned: bool,
+    set_state_on_drop_to: Cell<*mut Masked>,
+}
+
+// Four states that a Once can be in, encoded into the lower bits of
+// `state_and_queue` in the Once structure.
+const INCOMPLETE: usize = 0x0;
+const POISONED: usize = 0x1;
+const RUNNING: usize = 0x2;
+const COMPLETE: usize = 0x3;
+
+// Mask to learn about the state. All other bits are the queue of waiters if
+// this is in the RUNNING state.
+const STATE_MASK: usize = 0x3;
+
+// Representation of a node in the linked list of waiters, used while in the
+// RUNNING state.
+// Note: `Waiter` can't hold a mutable pointer to the next thread, because then
+// `wait` would both hand out a mutable reference to its `Waiter` node, and keep
+// a shared reference to check `signaled`. Instead we hold shared references and
+// use interior mutability.
+#[repr(align(4))] // Ensure the two lower bits are free to use as state bits.
+struct Waiter {
+    thread: Cell<Option<Thread>>,
+    signaled: AtomicBool,
+    next: *const Waiter,
+}
+
+// Head of a linked list of waiters.
+// Every node is a struct on the stack of a waiting thread.
+// Will wake up the waiters when it gets dropped, i.e. also on panic.
+struct WaiterQueue<'a> {
+    state_and_queue: &'a AtomicPtr<Masked>,
+    set_state_on_drop_to: *mut Masked,
+}
+
+impl Once {
+    #[inline]
+    #[rustc_const_stable(feature = "const_once_new", since = "1.32.0")]
+    pub const fn new() -> Once {
+        Once { state_and_queue: AtomicPtr::new(ptr::invalid_mut(INCOMPLETE)) }
+    }
+
+    #[inline]
+    pub fn is_completed(&self) -> bool {
+        // An `Acquire` load is enough because that makes all the initialization
+        // operations visible to us, and, this being a fast path, weaker
+        // ordering helps with performance. This `Acquire` synchronizes with
+        // `Release` operations on the slow path.
+        self.state_and_queue.load(Ordering::Acquire).addr() == COMPLETE
+    }
+
+    // This is a non-generic function to reduce the monomorphization cost of
+    // using `call_once` (this isn't exactly a trivial or small implementation).
+    //
+    // Additionally, this is tagged with `#[cold]` as it should indeed be cold
+    // and it helps let LLVM know that calls to this function should be off the
+    // fast path. Essentially, this should help generate more straight line code
+    // in LLVM.
+    //
+    // Finally, this takes an `FnMut` instead of a `FnOnce` because there's
+    // currently no way to take an `FnOnce` and call it via virtual dispatch
+    // without some allocation overhead.
+    #[cold]
+    #[track_caller]
+    pub fn call(&self, ignore_poisoning: bool, init: &mut dyn FnMut(&public::OnceState)) {
+        let mut state_and_queue = self.state_and_queue.load(Ordering::Acquire);
+        loop {
+            match state_and_queue.addr() {
+                COMPLETE => break,
+                POISONED if !ignore_poisoning => {
+                    // Panic to propagate the poison.
+                    panic!("Once instance has previously been poisoned");
+                }
+                POISONED | INCOMPLETE => {
+                    // Try to register this thread as the one RUNNING.
+                    let exchange_result = self.state_and_queue.compare_exchange(
+                        state_and_queue,
+                        ptr::invalid_mut(RUNNING),
+                        Ordering::Acquire,
+                        Ordering::Acquire,
+                    );
+                    if let Err(old) = exchange_result {
+                        state_and_queue = old;
+                        continue;
+                    }
+                    // `waiter_queue` will manage other waiting threads, and
+                    // wake them up on drop.
+                    let mut waiter_queue = WaiterQueue {
+                        state_and_queue: &self.state_and_queue,
+                        set_state_on_drop_to: ptr::invalid_mut(POISONED),
+                    };
+                    // Run the initialization function, letting it know if we're
+                    // poisoned or not.
+                    let init_state = public::OnceState {
+                        inner: OnceState {
+                            poisoned: state_and_queue.addr() == POISONED,
+                            set_state_on_drop_to: Cell::new(ptr::invalid_mut(COMPLETE)),
+                        },
+                    };
+                    init(&init_state);
+                    waiter_queue.set_state_on_drop_to = init_state.inner.set_state_on_drop_to.get();
+                    break;
+                }
+                _ => {
+                    // All other values must be RUNNING with possibly a
+                    // pointer to the waiter queue in the more significant bits.
+                    assert!(state_and_queue.addr() & STATE_MASK == RUNNING);
+                    wait(&self.state_and_queue, state_and_queue);
+                    state_and_queue = self.state_and_queue.load(Ordering::Acquire);
+                }
+            }
+        }
+    }
+}
+
+fn wait(state_and_queue: &AtomicPtr<Masked>, mut current_state: *mut Masked) {
+    // Note: the following code was carefully written to avoid creating a
+    // mutable reference to `node` that gets aliased.
+    loop {
+        // Don't queue this thread if the status is no longer running,
+        // otherwise we will not be woken up.
+        if current_state.addr() & STATE_MASK != RUNNING {
+            return;
+        }
+
+        // Create the node for our current thread.
+        let node = Waiter {
+            thread: Cell::new(Some(thread::current())),
+            signaled: AtomicBool::new(false),
+            next: current_state.with_addr(current_state.addr() & !STATE_MASK) as *const Waiter,
+        };
+        let me = &node as *const Waiter as *const Masked as *mut Masked;
+
+        // Try to slide in the node at the head of the linked list, making sure
+        // that another thread didn't just replace the head of the linked list.
+        let exchange_result = state_and_queue.compare_exchange(
+            current_state,
+            me.with_addr(me.addr() | RUNNING),
+            Ordering::Release,
+            Ordering::Relaxed,
+        );
+        if let Err(old) = exchange_result {
+            current_state = old;
+            continue;
+        }
+
+        // We have enqueued ourselves, now lets wait.
+        // It is important not to return before being signaled, otherwise we
+        // would drop our `Waiter` node and leave a hole in the linked list
+        // (and a dangling reference). Guard against spurious wakeups by
+        // reparking ourselves until we are signaled.
+        while !node.signaled.load(Ordering::Acquire) {
+            // If the managing thread happens to signal and unpark us before we
+            // can park ourselves, the result could be this thread never gets
+            // unparked. Luckily `park` comes with the guarantee that if it got
+            // an `unpark` just before on an unparked thread it does not park.
+            thread::park();
+        }
+        break;
+    }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl fmt::Debug for Once {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("Once").finish_non_exhaustive()
+    }
+}
+
+impl Drop for WaiterQueue<'_> {
+    fn drop(&mut self) {
+        // Swap out our state with however we finished.
+        let state_and_queue =
+            self.state_and_queue.swap(self.set_state_on_drop_to, Ordering::AcqRel);
+
+        // We should only ever see an old state which was RUNNING.
+        assert_eq!(state_and_queue.addr() & STATE_MASK, RUNNING);
+
+        // Walk the entire linked list of waiters and wake them up (in lifo
+        // order, last to register is first to wake up).
+        unsafe {
+            // Right after setting `node.signaled = true` the other thread may
+            // free `node` if there happens to be has a spurious wakeup.
+            // So we have to take out the `thread` field and copy the pointer to
+            // `next` first.
+            let mut queue =
+                state_and_queue.with_addr(state_and_queue.addr() & !STATE_MASK) as *const Waiter;
+            while !queue.is_null() {
+                let next = (*queue).next;
+                let thread = (*queue).thread.take().unwrap();
+                (*queue).signaled.store(true, Ordering::Release);
+                // ^- FIXME (maybe): This is another case of issue #55005
+                // `store()` has a potentially dangling ref to `signaled`.
+                queue = next;
+                thread.unpark();
+            }
+        }
+    }
+}
+
+impl OnceState {
+    #[inline]
+    pub fn is_poisoned(&self) -> bool {
+        self.poisoned
+    }
+
+    #[inline]
+    pub fn poison(&self) {
+        self.set_state_on_drop_to.set(ptr::invalid_mut(POISONED));
+    }
+}
index 9f978789a62322c782245759d1cc4d66f0227405..ae11412067b549a719ec243442bd2beb7606c270 100644 (file)
@@ -4,7 +4,9 @@
 use crate::collections::BTreeMap;
 use crate::env;
 use crate::ffi::{OsStr, OsString};
-use crate::sys::process::EnvKey;
+use crate::io;
+use crate::sys::pipe::read2;
+use crate::sys::process::{EnvKey, ExitStatus, Process, StdioPipes};
 
 // Stores a set of changes to an environment
 #[derive(Clone, Debug)]
@@ -117,3 +119,30 @@ fn is_empty(&self) -> bool {
         self.iter.is_empty()
     }
 }
+
+pub fn wait_with_output(
+    mut process: Process,
+    mut pipes: StdioPipes,
+) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
+    drop(pipes.stdin.take());
+
+    let (mut stdout, mut stderr) = (Vec::new(), Vec::new());
+    match (pipes.stdout.take(), pipes.stderr.take()) {
+        (None, None) => {}
+        (Some(out), None) => {
+            let res = out.read_to_end(&mut stdout);
+            res.unwrap();
+        }
+        (None, Some(err)) => {
+            let res = err.read_to_end(&mut stderr);
+            res.unwrap();
+        }
+        (Some(out), Some(err)) => {
+            let res = read2(out, &mut stdout, err, &mut stderr);
+            res.unwrap();
+        }
+    }
+
+    let status = process.wait()?;
+    Ok((status, stdout, stderr))
+}
index 524658bce139d73794a18ca88237241a6aec1dce..796796e07a9c18fe5673961f463753cf980e2763 100644 (file)
@@ -354,8 +354,7 @@ fn get_shuffle_seed(matches: &getopts::Matches, allow_unstable: bool) -> OptPart
             Err(e) => {
                 return Err(format!(
                     "argument for --shuffle-seed must be a number \
-                     (error: {})",
-                    e
+                     (error: {e})"
                 ));
             }
         },
@@ -383,8 +382,7 @@ fn get_test_threads(matches: &getopts::Matches) -> OptPartRes<Option<usize>> {
             Err(e) => {
                 return Err(format!(
                     "argument for --test-threads must be a number > 0 \
-                     (error: {})",
-                    e
+                     (error: {e})"
                 ));
             }
         },
@@ -418,8 +416,7 @@ fn get_format(
         Some(v) => {
             return Err(format!(
                 "argument for --format must be pretty, terse, json or junit (was \
-                 {})",
-                v
+                 {v})"
             ));
         }
     };
@@ -436,8 +433,7 @@ fn get_color_config(matches: &getopts::Matches) -> OptPartRes<ColorConfig> {
         Some(v) => {
             return Err(format!(
                 "argument for --color must be auto, always, or never (was \
-                 {})",
-                v
+                 {v})"
             ));
         }
     };
index c07fdafb167c98871b773d1a35fb898c64096c05..5526aadb67ffb84a4aafab0bd79d8ab4c12a85bf 100644 (file)
@@ -53,7 +53,7 @@ fn write_event(
             self.write_message(&*format!(r#", "stdout": "{}""#, EscapedString(stdout)))?;
         }
         if let Some(extra) = extra {
-            self.write_message(&*format!(r#", {}"#, extra))?;
+            self.write_message(&*format!(r#", {extra}"#))?;
         }
         self.writeln_message(" }")
     }
@@ -62,13 +62,12 @@ fn write_event(
 impl<T: Write> OutputFormatter for JsonFormatter<T> {
     fn write_run_start(&mut self, test_count: usize, shuffle_seed: Option<u64>) -> io::Result<()> {
         let shuffle_seed_json = if let Some(shuffle_seed) = shuffle_seed {
-            format!(r#", "shuffle_seed": {}"#, shuffle_seed)
+            format!(r#", "shuffle_seed": {shuffle_seed}"#)
         } else {
             String::new()
         };
         self.writeln_message(&*format!(
-            r#"{{ "type": "suite", "event": "started", "test_count": {}{} }}"#,
-            test_count, shuffle_seed_json
+            r#"{{ "type": "suite", "event": "started", "test_count": {test_count}{shuffle_seed_json} }}"#
         ))
     }
 
index cb80859759fad7c55968eeb6ec6b194e4cede049..cb67b6491a392286c3821cd3ec1d9089d58a018d 100644 (file)
@@ -38,5 +38,5 @@ pub(crate) fn write_stderr_delimiter(test_output: &mut Vec<u8>, test_name: &Test
         Some(_) => test_output.push(b'\n'),
         None => (),
     }
-    writeln!(test_output, "---- {} stderr ----", test_name).unwrap();
+    writeln!(test_output, "---- {test_name} stderr ----").unwrap();
 }
index 694202229802f832fd5cab66db22c2464f8077e4..0299c8b543359adb3de118bb7f91436e0cf32879 100644 (file)
@@ -47,7 +47,7 @@ pub fn write_failed(&mut self) -> io::Result<()> {
 
     pub fn write_ignored(&mut self, message: Option<&'static str>) -> io::Result<()> {
         if let Some(message) = message {
-            self.write_short_result(&format!("ignored, {}", message), term::color::YELLOW)
+            self.write_short_result(&format!("ignored, {message}"), term::color::YELLOW)
         } else {
             self.write_short_result("ignored", term::color::YELLOW)
         }
index 256c9e8d141e0baa57684ec5ebdb9c74cb5fc7c0..f6a41bbb88c852c8090e95b003e64379cc9759bb 100644 (file)
@@ -213,8 +213,7 @@ pub fn assert_test_result<T: Termination>(result: T) -> Result<(), String> {
     } else {
         Err(format!(
             "the test returned a termination value with a non-zero status code \
-             ({}) which indicates a failure",
-            code
+             ({code}) which indicates a failure"
         ))
     }
 }
@@ -750,7 +749,7 @@ fn spawn_test_subprocess(
         })() {
             Ok(r) => r,
             Err(e) => {
-                write!(&mut test_output, "Unexpected error: {}", e).unwrap();
+                write!(&mut test_output, "Unexpected error: {e}").unwrap();
                 TrFailed
             }
         };
index 7f44d6e3d0f122dff5157cd0d2914f2e2f097499..7c5b0d6c0f721072d0d13c40b3be84d529dee0e0 100644 (file)
@@ -44,9 +44,8 @@ pub fn calc_result<'a>(
             } else if let Some(panic_str) = maybe_panic_str {
                 TestResult::TrFailedMsg(format!(
                     r#"panic did not contain expected string
-      panic message: `{:?}`,
- expected substring: `{:?}`"#,
-                    panic_str, msg
+      panic message: `{panic_str:?}`,
+ expected substring: `{msg:?}`"#
                 ))
             } else {
                 TestResult::TrFailedMsg(format!(
index 8c64e5d1b733944b6b41257ec767e73556d1e97d..7fd69d7f7e73c66ea340f995e9f30be4be890920 100644 (file)
@@ -107,16 +107,14 @@ pub fn from_env_var(env_var_name: &str) -> Option<Self> {
         let durations_str = env::var(env_var_name).ok()?;
         let (warn_str, critical_str) = durations_str.split_once(',').unwrap_or_else(|| {
             panic!(
-                "Duration variable {} expected to have 2 numbers separated by comma, but got {}",
-                env_var_name, durations_str
+                "Duration variable {env_var_name} expected to have 2 numbers separated by comma, but got {durations_str}"
             )
         });
 
         let parse_u64 = |v| {
             u64::from_str(v).unwrap_or_else(|_| {
                 panic!(
-                    "Duration value in variable {} is expected to be a number, but got {}",
-                    env_var_name, v
+                    "Duration value in variable {env_var_name} is expected to be a number, but got {v}"
                 )
             })
         };
index 8ee6d49da8f0e419b4fc9ff2898a4e21f5c47bae..1d37d68c1d4050d807d4e73fe68591d434e05158 100644 (file)
@@ -19,6 +19,7 @@
 use crate::install;
 use crate::native;
 use crate::run;
+use crate::setup;
 use crate::test;
 use crate::tool::{self, SourceType};
 use crate::util::{self, add_dylib_path, add_link_lib_path, exe, libdir, output, t};
@@ -433,8 +434,11 @@ pub(crate) fn crates(mut self, crates: Vec<&Crate>) -> Self {
 
     // single alias, which does not correspond to any on-disk path
     pub fn alias(mut self, alias: &str) -> Self {
+        // exceptional case for `Kind::Setup` because its `library`
+        // and `compiler` options would otherwise naively match with
+        // `compiler` and `library` folders respectively.
         assert!(
-            !self.builder.src.join(alias).exists(),
+            self.kind == Kind::Setup || !self.builder.src.join(alias).exists(),
             "use `builder.path()` for real paths: {}",
             alias
         );
@@ -744,6 +748,7 @@ macro_rules! describe {
                 install::RustDemangler,
                 install::Clippy,
                 install::Miri,
+                install::LlvmTools,
                 install::Analysis,
                 install::Src,
                 install::Rustc
@@ -757,8 +762,9 @@ macro_rules! describe {
                 run::CollectLicenseMetadata,
                 run::GenerateCopyright,
             ),
+            Kind::Setup => describe!(setup::Profile),
             // These commands either don't use paths, or they're special-cased in Build::build()
-            Kind::Clean | Kind::Format | Kind::Setup => vec![],
+            Kind::Clean | Kind::Format => vec![],
         }
     }
 
@@ -821,7 +827,11 @@ pub fn new(build: &Build) -> Builder<'_> {
             Subcommand::Install { ref paths } => (Kind::Install, &paths[..]),
             Subcommand::Run { ref paths, .. } => (Kind::Run, &paths[..]),
             Subcommand::Format { .. } => (Kind::Format, &[][..]),
-            Subcommand::Clean { .. } | Subcommand::Setup { .. } => {
+            Subcommand::Setup { profile: ref path } => (
+                Kind::Setup,
+                path.as_ref().map_or([].as_slice(), |path| std::slice::from_ref(path)),
+            ),
+            Subcommand::Clean { .. } => {
                 panic!()
             }
         };
index 960fbdf75380448983b1f3650b9fd66b95dc3df8..2906616ffad142958e4debc08d55472a7b348971 100644 (file)
@@ -638,6 +638,7 @@ struct Build {
         dist_stage: Option<u32> = "dist-stage",
         bench_stage: Option<u32> = "bench-stage",
         patch_binaries_for_nix: Option<bool> = "patch-binaries-for-nix",
+        // NOTE: only parsed by bootstrap.py, `--feature build-metrics` enables metrics unconditionally
         metrics: Option<bool> = "metrics",
     }
 }
index 37a8eb884efb02beba7ca57c462108a1bca96ae1..851cb5ecf4c2694ee7c77b7b97e4bd92a1c7d6a4 100644 (file)
@@ -143,7 +143,7 @@ pub enum Subcommand {
         args: Vec<String>,
     },
     Setup {
-        profile: Option<Profile>,
+        profile: Option<PathBuf>,
     },
 }
 
@@ -351,7 +351,7 @@ pub fn parse(args: &[String]) -> Flags {
 
         // fn usage()
         let usage = |exit_code: i32, opts: &Options, verbose: bool, subcommand_help: &str| -> ! {
-            let config = Config::parse(&["build".to_string()]);
+            let config = Config::parse(&["setup".to_string()]);
             let build = Build::new(config);
             let paths = Builder::get_help(&build, subcommand);
 
@@ -621,7 +621,7 @@ pub fn parse(args: &[String]) -> Flags {
             }
             Kind::Setup => {
                 let profile = if paths.len() > 1 {
-                    println!("\nat most one profile can be passed to setup\n");
+                    eprintln!("\nerror: At most one profile can be passed to setup\n");
                     usage(1, &opts, verbose, &subcommand_help)
                 } else if let Some(path) = paths.pop() {
                     let profile_string = t!(path.into_os_string().into_string().map_err(
index 5e7264fe765a950ac9980b7ef55b5e05023312d6..b2f6afead798088e12ae27425b354540ea6c302b 100644 (file)
@@ -8,7 +8,7 @@
 use std::process::{Command, Stdio};
 use std::sync::mpsc::SyncSender;
 
-fn rustfmt(src: &Path, rustfmt: &Path, paths: &[PathBuf], check: bool) -> impl FnMut() {
+fn rustfmt(src: &Path, rustfmt: &Path, paths: &[PathBuf], check: bool) -> impl FnMut(bool) -> bool {
     let mut cmd = Command::new(&rustfmt);
     // avoid the submodule config paths from coming into play,
     // we only allow a single global config for the workspace for now
@@ -23,7 +23,13 @@ fn rustfmt(src: &Path, rustfmt: &Path, paths: &[PathBuf], check: bool) -> impl F
     let cmd_debug = format!("{:?}", cmd);
     let mut cmd = cmd.spawn().expect("running rustfmt");
     // poor man's async: return a closure that'll wait for rustfmt's completion
-    move || {
+    move |block: bool| -> bool {
+        if !block {
+            match cmd.try_wait() {
+                Ok(Some(_)) => {}
+                _ => return false,
+            }
+        }
         let status = cmd.wait().unwrap();
         if !status.success() {
             eprintln!(
@@ -34,6 +40,7 @@ fn rustfmt(src: &Path, rustfmt: &Path, paths: &[PathBuf], check: bool) -> impl F
             );
             crate::detail_exit(1);
         }
+        true
     }
 }
 
@@ -146,15 +153,23 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
             let child = rustfmt(&src, &rustfmt_path, paths.as_slice(), check);
             children.push_back(child);
 
+            // poll completion before waiting
+            for i in (0..children.len()).rev() {
+                if children[i](false) {
+                    children.swap_remove_back(i);
+                    break;
+                }
+            }
+
             if children.len() >= max_processes {
                 // await oldest child
-                children.pop_front().unwrap()();
+                children.pop_front().unwrap()(true);
             }
         }
 
         // await remaining children
         for mut child in children {
-            child();
+            child(true);
         }
     });
 
index 7672b7c913594cb9ecc3f2c4f550cbe53e09278b..1815a0973072bd741e4699332268aa3c7ce77f5b 100644 (file)
@@ -200,10 +200,20 @@ fn run($sel, $builder: &Builder<'_>) {
         install_sh(builder, "clippy", self.compiler.stage, Some(self.target), &tarball);
     };
     Miri, alias = "miri", Self::should_build(_config), only_hosts: true, {
+        if let Some(tarball) = builder.ensure(dist::Miri { compiler: self.compiler, target: self.target }) {
+            install_sh(builder, "miri", self.compiler.stage, Some(self.target), &tarball);
+        } else {
+            // Miri is only available on nightly
+            builder.info(
+                &format!("skipping Install miri stage{} ({})", self.compiler.stage, self.target),
+            );
+        }
+    };
+    LlvmTools, alias = "llvm-tools", Self::should_build(_config), only_hosts: true, {
         let tarball = builder
-            .ensure(dist::Miri { compiler: self.compiler, target: self.target })
-            .expect("missing miri");
-        install_sh(builder, "miri", self.compiler.stage, Some(self.target), &tarball);
+            .ensure(dist::LlvmTools { target: self.target })
+            .expect("missing llvm-tools");
+        install_sh(builder, "llvm-tools", self.compiler.stage, Some(self.target), &tarball);
     };
     Rustfmt, alias = "rustfmt", Self::should_build(_config), only_hosts: true, {
         if let Some(tarball) = builder.ensure(dist::Rustfmt {
index 570fe6484e3db32aa436633f4ebde35d369b57a0..47fb4a38d05be381e074f199401b03c7b1de9db4 100644 (file)
 use std::env;
 use std::fs::{self, File};
 use std::io;
+use std::io::ErrorKind;
 use std::path::{Path, PathBuf};
 use std::process::Command;
 use std::str;
 
 use crate::builder::Kind;
 use crate::config::{LlvmLibunwind, TargetSelection};
-use crate::util::{exe, libdir, mtime, output, run, run_suppressed, try_run_suppressed, CiEnv};
+use crate::util::{
+    exe, libdir, mtime, output, run, run_suppressed, symlink_dir, try_run_suppressed, CiEnv,
+};
 
 mod bolt;
 mod builder;
@@ -586,6 +589,20 @@ pub fn new(mut config: Config) -> Build {
             metadata::build(&mut build);
         }
 
+        // Make a symbolic link so we can use a consistent directory in the documentation.
+        let build_triple = build.out.join(&build.build.triple);
+        let host = build.out.join("host");
+        if let Err(e) = symlink_dir(&build.config, &build_triple, &host) {
+            if e.kind() != ErrorKind::AlreadyExists {
+                panic!(
+                    "symlink_dir({} => {}) failed with {}",
+                    host.display(),
+                    build_triple.display(),
+                    e
+                );
+            }
+        }
+
         build
     }
 
@@ -713,10 +730,6 @@ pub fn build(&mut self) {
             return clean::clean(self, all);
         }
 
-        if let Subcommand::Setup { profile } = &self.config.cmd {
-            return setup::setup(&self.config, *profile);
-        }
-
         // Download rustfmt early so that it can be used in rust-analyzer configs.
         let _ = &builder::Builder::new(&self).initial_rustfmt();
 
index 9a08a7be0f5f7198a5efe0c2add00948d3536e76..5b2aba9aa2dc814863c41bc679a1183e5df091b8 100644 (file)
@@ -57,11 +57,6 @@ tidy:
 prepare:
        $(Q)$(BOOTSTRAP) build --stage 2 nonexistent/path/to/trigger/cargo/metadata
 
-check-stage2-T-arm-linux-androideabi-H-x86_64-unknown-linux-gnu:
-       $(Q)$(BOOTSTRAP) test --stage 2 --target arm-linux-androideabi
-check-stage2-T-x86_64-unknown-linux-musl-H-x86_64-unknown-linux-gnu:
-       $(Q)$(BOOTSTRAP) test --stage 2 --target x86_64-unknown-linux-musl
-
 TESTS_IN_2 := \
        src/test/ui \
        src/tools/linkchecker
index f6c453ebe107bd6f6f2309b42065d801528624e6..68f917d3528593e164b6d90b4ceddf44444b06d0 100644 (file)
@@ -600,6 +600,9 @@ fn configure_cmake(
             if target.starts_with("aarch64") {
                 // macOS uses a different name for building arm64
                 cfg.define("CMAKE_OSX_ARCHITECTURES", "arm64");
+            } else if target.starts_with("i686") {
+                // macOS uses a different name for building i386
+                cfg.define("CMAKE_OSX_ARCHITECTURES", "i386");
             } else {
                 cfg.define("CMAKE_OSX_ARCHITECTURES", target.triple.split('-').next().unwrap());
             }
index c7f98a7d0d149ae28c21ad6dadb109034e9bbff6..57426ce3d51094b259f863addc6a3509e098befb 100644 (file)
@@ -1,3 +1,4 @@
+use crate::builder::{Builder, RunConfig, ShouldRun, Step};
 use crate::Config;
 use crate::{t, VERSION};
 use std::env::consts::EXE_SUFFIX;
@@ -9,7 +10,7 @@
 use std::str::FromStr;
 use std::{fmt, fs, io};
 
-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
 pub enum Profile {
     Compiler,
     Codegen,
@@ -48,6 +49,16 @@ pub fn all_for_help(indent: &str) -> String {
         }
         out
     }
+
+    pub fn as_str(&self) -> &'static str {
+        match self {
+            Profile::Compiler => "compiler",
+            Profile::Codegen => "codegen",
+            Profile::Library => "library",
+            Profile::Tools => "tools",
+            Profile::User => "user",
+        }
+    }
 }
 
 impl FromStr for Profile {
@@ -69,24 +80,58 @@ fn from_str(s: &str) -> Result<Self, Self::Err> {
 
 impl fmt::Display for Profile {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self {
-            Profile::Compiler => write!(f, "compiler"),
-            Profile::Codegen => write!(f, "codegen"),
-            Profile::Library => write!(f, "library"),
-            Profile::User => write!(f, "user"),
-            Profile::Tools => write!(f, "tools"),
+        f.write_str(self.as_str())
+    }
+}
+
+impl Step for Profile {
+    type Output = ();
+    const DEFAULT: bool = true;
+
+    fn should_run(mut run: ShouldRun<'_>) -> ShouldRun<'_> {
+        for choice in Profile::all() {
+            run = run.alias(choice.as_str());
         }
+        run
+    }
+
+    fn make_run(run: RunConfig<'_>) {
+        // for Profile, `run.paths` will have 1 and only 1 element
+        // this is because we only accept at most 1 path from user input.
+        // If user calls `x.py setup` without arguments, the interactive TUI
+        // will guide user to provide one.
+        let profile = if run.paths.len() > 1 {
+            // HACK: `builder` runs this step with all paths if no path was passed.
+            t!(interactive_path())
+        } else {
+            run.paths
+                .first()
+                .unwrap()
+                .assert_single_path()
+                .path
+                .as_path()
+                .as_os_str()
+                .to_str()
+                .unwrap()
+                .parse()
+                .unwrap()
+        };
+
+        run.builder.ensure(profile);
+    }
+
+    fn run(self, builder: &Builder<'_>) {
+        setup(&builder.build.config, self)
     }
 }
 
-pub fn setup(config: &Config, profile: Option<Profile>) {
-    let profile = profile.unwrap_or_else(|| t!(interactive_path()));
+pub fn setup(config: &Config, profile: Profile) {
     let stage_path =
         ["build", config.build.rustc_target_arg(), "stage1"].join(&MAIN_SEPARATOR.to_string());
 
     if !rustup_installed() && profile != Profile::User {
         eprintln!("`rustup` is not installed; cannot link `stage1` toolchain");
-    } else if stage_dir_exists(&stage_path[..]) {
+    } else if stage_dir_exists(&stage_path[..]) && !config.dry_run() {
         attempt_toolchain_link(&stage_path[..]);
     }
 
@@ -104,7 +149,9 @@ pub fn setup(config: &Config, profile: Option<Profile>) {
         Profile::User => &["dist", "build"],
     };
 
-    t!(install_git_hook_maybe(&config));
+    if !config.dry_run() {
+        t!(install_git_hook_maybe(&config));
+    }
 
     println!();
 
@@ -144,6 +191,7 @@ fn setup_config_toml(path: &PathBuf, profile: Profile, config: &Config) {
     changelog-seen = {}\n",
         profile, VERSION
     );
+
     t!(fs::write(path, settings));
 
     let include_path = profile.include_path(&config.src);
index 40caa7c50135d31dae92b8331501572436f874dd..9e2568af13f689d07688c03881cfd33cdbbd9f82 100644 (file)
@@ -40,13 +40,13 @@ COPY host-x86_64/mingw-check/validate-error-codes.sh /scripts/
 
 ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1
 ENV SCRIPT python3 ../x.py --stage 2 test src/tools/expand-yaml-anchors && \
+           python3 ../x.py test --stage 0 src/tools/tidy && \
            python3 ../x.py check --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu --all-targets && \
            python3 ../x.py build --stage 0 src/tools/build-manifest && \
            python3 ../x.py test --stage 0 src/tools/compiletest && \
-           python3 ../x.py test --stage 2 src/tools/tidy && \
            python3 ../x.py test --stage 0 core alloc std test proc_macro && \
            # Build both public and internal documentation.
-           RUSTDOCFLAGS="--document-private-items" python3 ../x.py doc --stage 0 library/test && \
+           RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc --stage 0 library/test && \
            /scripts/validate-toolstate.sh && \
            /scripts/validate-error-codes.sh && \
            reuse lint && \
index 3f8dcd03d2db1e396fd994bd43521c76473f02bd..475434e5aef8639abff9ae9cae4b20c84c0df7f6 100644 (file)
@@ -1 +1 @@
-0.13.2
\ No newline at end of file
+0.13.4
\ No newline at end of file
index 5a0397a3d123cf714bb63dbf40b4a87a9ae9f69a..d1ba46ad30de6d08c82176a41b7e894c87358704 100644 (file)
@@ -467,7 +467,7 @@ jobs:
           - name: dist-x86_64-apple
             env:
               SCRIPT: ./x.py dist bootstrap --include-default-paths --host=x86_64-apple-darwin --target=x86_64-apple-darwin
-              RUST_CONFIGURE_ARGS: --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false
+              RUST_CONFIGURE_ARGS: --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false --set rust.lto=thin
               RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
               MACOSX_DEPLOYMENT_TARGET: 10.7
               SELECT_XCODE: /Applications/Xcode_13.4.1.app
index 7de06ec35c36bba75da44543d567f7603835341b..f05bb81d4a1e3b31ba260b357e237911979d8f17 100755 (executable)
@@ -56,6 +56,7 @@ fi
 if ! isCI || isCiBranch auto || isCiBranch beta || isCiBranch try || isCiBranch try-perf; then
     RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set build.print-step-timings --enable-verbose-tests"
     RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set build.metrics"
+    HAS_METRICS=1
 fi
 
 RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-sccache"
@@ -157,13 +158,6 @@ trap datecheck EXIT
 # sccache server at the start of the build, but no need to worry if this fails.
 SCCACHE_IDLE_TIMEOUT=10800 sccache --start-server || true
 
-if [ "$RUN_CHECK_WITH_PARALLEL_QUERIES" != "" ]; then
-  $SRC/configure --set rust.parallel-compiler
-  CARGO_INCREMENTAL=0 $PYTHON ../x.py check
-  rm -f config.toml
-  rm -rf build
-fi
-
 $SRC/configure $RUST_CONFIGURE_ARGS
 
 retry make prepare
@@ -193,4 +187,21 @@ else
   do_make "$RUST_CHECK_TARGET"
 fi
 
+if [ "$RUN_CHECK_WITH_PARALLEL_QUERIES" != "" ]; then
+  rm -f config.toml
+  $SRC/configure --set rust.parallel-compiler
+
+  # Save the build metrics before we wipe the directory
+  if [ $HAS_METRICS = 1 ]; then
+    mv build/metrics.json .
+  fi
+  rm -rf build
+  if [ $HAS_METRICS = 1 ]; then
+    mkdir build
+    mv metrics.json build
+  fi
+
+  CARGO_INCREMENTAL=0 $PYTHON ../x.py check
+fi
+
 sccache --show-stats || true
index ae406aa5287a9e025abb72343aaceec98458c117..dd37e21ccee43918ed18a71581bb2af537ffe4fc 160000 (submodule)
@@ -1 +1 @@
-Subproject commit ae406aa5287a9e025abb72343aaceec98458c117
+Subproject commit dd37e21ccee43918ed18a71581bb2af537ffe4fc
index a9869b4a3c4cac3bc6099b41f088679e268400b8..995df09b65c582eb6290ab7ea5d9485983eb4c37 160000 (submodule)
@@ -1 +1 @@
-Subproject commit a9869b4a3c4cac3bc6099b41f088679e268400b8
+Subproject commit 995df09b65c582eb6290ab7ea5d9485983eb4c37
index e269950a57fa6fcda356426545fb5aa3691a7ced..8b42eb5f57d3d8ed2257a22d0e850d9db52afed3 160000 (submodule)
@@ -1 +1 @@
-Subproject commit e269950a57fa6fcda356426545fb5aa3691a7ced
+Subproject commit 8b42eb5f57d3d8ed2257a22d0e850d9db52afed3
index fa38dd54d60c89bc7730daa6c20b1c501df0d6df..98b49e07171c20c39fcfb11ff004576b34634b20 100644 (file)
@@ -217,7 +217,7 @@ It is recommended that explicit wrapping methods such as `wrapping_add` be
 used when wrapping semantics are intended, and that explicit checking and
 wrapping methods always be used when using Unsafe Rust.
 
-<small id="fn:2">2\. See <https://doc.rust-lang.org/std/primitive.u32.html>
+<small id="fn:2">2\. See [the `u32` docs](../std/primitive.u32.html)
 for more information on the checked, overflowing, saturating, and wrapping
 methods (using u32 as an example). <a href="#fnref:2"
 class="reversefootnote" role="doc-backlink">↩</a></small>
@@ -575,17 +575,17 @@ defaults (unrelated to `READ_IMPLIES_EXEC`).
    <https://hacks.mozilla.org/2019/02/fearless-security-thread-safety/>.
 
 3. S. Klabnik and C. Nichols. “What Is Ownership?.” The Rust Programming
-   Language. <https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html>.
+   Language. [https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html](../book/ch04-01-what-is-ownership.html).
 
 4. S. Klabnik and C. Nichols. “References and Borrowing.” The Rust
    Programming Language.
-   <https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html>.
+   [https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html](../book/ch04-02-references-and-borrowing.html).
 
 5. S. Klabnik and C. Nichols. “The Slice Type.” The Rust Programming
-   Language. <https://doc.rust-lang.org/book/ch04-03-slices.html>.
+   Language. [https://doc.rust-lang.org/book/ch04-03-slices.html](../book/ch04-03-slices.html).
 
 6. S. Klabnik and C. Nichols. “Unsafe Rust.” The Rust Programming Language.
-   <https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html>.
+   [https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html](../book/ch19-01-unsafe-rust.html).
 
 7. S. Davidoff. “How Rust’s standard library was vulnerable for years and
    nobody noticed.” Medium.
@@ -696,4 +696,4 @@ defaults (unrelated to `READ_IMPLIES_EXEC`).
     for Rust #89653.” GitHub. <https://github.com/rust-lang/rust/issues/89653>.
 
 41. “ControlFlowIntegrity.” The Rust Unstable Book.
-    <https://doc.rust-lang.org/beta/unstable-book/compiler-flags/sanitizer.html#controlflowintegrity>.
+    [https://doc.rust-lang.org/unstable-book/compiler-flags/sanitizer.html#controlflowintegrity](../unstable-book/compiler-flags/sanitizer.html#controlflowintegrity).
index 9272b9ac9b2d45be95b2278b97dc36b0b5c00446..858b7bc79c4c86f12e9b82a0008b285319ab7bb8 100644 (file)
@@ -112,7 +112,7 @@ targeting Windows-like targets
 This is fixed if you explicitly set the target, for example
 `cargo build --target x86_64-pc-windows-msvc`
 Without an explicit --target the flags will be passed to all compiler invocations (including build
-scripts and proc macros), see [cargo docs on rustflags](https://doc.rust-lang.org/cargo/reference/config.html#buildrustflags)
+scripts and proc macros), see [cargo docs on rustflags](../cargo/reference/config.html#buildrustflags)
 
 If you have dependencies using the `cc` crate, you will need to set these
 environment variables:
index b2c8e5d4df73601d1113e88c15e8ad41f5d3595b..e351cfaf89c2c985bb645c13d8394766a65419d8 100644 (file)
@@ -42,4 +42,4 @@ edition of the [Android NDK].  Supported Android targets are:
 [Android NDK]: https://developer.android.com/ndk/downloads
 
 A list of all supported targets can be found
-[here](https://doc.rust-lang.org/rustc/platform-support.html)
+[here](../platform-support.html)
index 215290e389843d9279e5049c3269506ab1d4ac9f..2ce0ccb78769c8a2acdcd3343de4deef94ee3f2a 100644 (file)
@@ -111,7 +111,7 @@ to an SD card to be inserted in the device.
 The `cargo-3ds` tool mentioned in [Building Rust programs](#building-rust-programs)
 supports the use of `3dslink` with `cargo 3ds run`. The default Rust test runner
 is not supported, but
-[custom test frameworks](https://doc.rust-lang.org/beta/unstable-book/language-features/custom-test-frameworks.html)
+[custom test frameworks](../../unstable-book/language-features/custom-test-frameworks.html)
 can be used with `cargo 3ds test` to run unit tests on a device.
 
 The Rust test suite for `library/std` is not yet supported.
index fbf999f97151b3e8169a90a5ed476159c6fd601d..cc4ee2e67b14eb7610c7bd9e6b4bbf140c334bb5 100644 (file)
@@ -90,7 +90,7 @@ rustup target add aarch64-fuchsia
 After installing our Fuchsia targets, we can now compile a Rust binary that targets
 Fuchsia.
 
-To create our Rust project, we can issue a standard `cargo` command as follows:
+To create our Rust project, we can use [`cargo`][cargo] as follows:
 
 **From base working directory**
 ```sh
@@ -867,7 +867,7 @@ ${SDK_PATH}/tools/${ARCH}/ffx debug connect -- \
 [Fuchsia]: https://fuchsia.dev/
 [source tree]: https://fuchsia.dev/fuchsia-src/get-started/learn/build
 [rustup]: https://rustup.rs/
-[cargo]: https://doc.rust-lang.org/cargo/
+[cargo]: ../../cargo/index.html
 [Fuchsia SDK]: https://chrome-infra-packages.appspot.com/p/fuchsia/sdk/core
 [overview of CML]: https://fuchsia.dev/fuchsia-src/concepts/components/v2/component_manifests
 [reference for the file format]: https://fuchsia.dev/reference/cml
index 27ef2f49eee58611d6516bf90887d440141d2e85..a67cb10fc75a8b8b9d277ab50f7b4cb6acd52cd1 100644 (file)
@@ -14,4 +14,4 @@ To see it for a different target, add the `--target` flag:
 rustc +nightly -Z unstable-options --target=wasm32-unknown-unknown --print target-spec-json
 ```
 
-To use a custom target, see the (unstable) [`build-std` feature](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#build-std) of `cargo`.
+To use a custom target, see the (unstable) [`build-std` feature](../../cargo/reference/unstable.html#build-std) of `cargo`.
index 85403748e1dcdab014366fea01034f98adf508d2..ca5664835f26fbf55a8b5b352c67da799f82806a 100644 (file)
@@ -1,7 +1,7 @@
 # `branch-protection`
 
 This option lets you enable branch authentication instructions on AArch64.
-This option is ignored for non-AArch64 architectures.
+This option is only accepted when targeting AArch64 architectures.
 It takes some combination of the following values, separated by a `,`.
 
 - `pac-ret` - Enable pointer authentication for non-leaf functions.
@@ -15,4 +15,4 @@ For example, `-Z branch-protection=bti,pac-ret,leaf` is valid, but
 
 Rust's standard library does not ship with BTI or pointer authentication enabled by default.
 In Cargo projects the standard library can be recompiled with pointer authentication using the nightly
-[build-std](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#build-std) feature.
+[build-std](../../cargo/reference/unstable.html#build-std) feature.
index 08c16d95f4670bce556395f3d8e53b5cbb4dc4ab..dbb741422a87508534ddbb9507a4baba26326c15 100644 (file)
@@ -39,7 +39,7 @@ It is strongly recommended to also enable CFG checks for all linked libraries, i
 
 To enable CFG in the standard library, use the [cargo `-Z build-std` functionality][build-std] to recompile the standard library with the same configuration options as the main program.
 
-[build-std]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#build-std
+[build-std]: ../../cargo/reference/unstable.html#build-std
 
 For example:
 ```cmd
index 9bbf9e28fffe2bdec384da186e4f2b1eec2f417b..a9616c34bffcb6be02e464c0b8f915c1b7cc1319 100644 (file)
@@ -420,8 +420,8 @@ flow using an indirect branch/call to a function with different return and
 parameter types than the return type expected and arguments intended/passed in
 the call/branch site, the execution is also terminated (see Fig. 9).
 
-[rust-book-ch19-05]: https://doc.rust-lang.org/book/ch19-05-advanced-functions-and-closures.html
-[rust-book]: https://doc.rust-lang.org/book/title-page.html
+[rust-book-ch19-05]: ../../book/ch19-05-advanced-functions-and-closures.html
+[rust-book]: ../../book/title-page.html
 
 # HWAddressSanitizer
 
@@ -691,7 +691,7 @@ It is strongly recommended to combine sanitizers with recompiled and
 instrumented standard library, for example using [cargo `-Zbuild-std`
 functionality][build-std].
 
-[build-std]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#build-std
+[build-std]: ../../cargo/reference/unstable.html#build-std
 
 # Build scripts and procedural macros
 
index c6516d838ddc8d99bc6c6b9a3446dd0f92442091..5cb9758409a778af004c5430c5f9f38b5003dbb9 100644 (file)
@@ -36,4 +36,4 @@ optimized out, if unused. However, with `make_foo` you can produce a wrapped
 to inlining of `f`, `Foo::foo` can then be called from a foreign crate. This can
 lead to miscompilations.
 
-[Clto]: https://doc.rust-lang.org/rustc/codegen-options/index.html#lto
+[Clto]: ../../rustc/codegen-options/index.html#lto
index f967c11fc4d0895e637e36041bc0271dc3ce7b06..014e15d1ada6833d828961f1e5879cf333611a96 100644 (file)
@@ -13,8 +13,8 @@ that are automatically implemented for every type, unless the type, or a type it
 has explicitly opted out via a negative impl. (Negative impls are separately controlled
 by the `negative_impls` feature.)
 
-[`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html
-[`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
+[`Send`]: ../../std/marker/trait.Send.html
+[`Sync`]: ../../std/marker/trait.Sync.html
 
 ```rust,ignore (partial-example)
 impl !Trait for Type {}
index e4113d72d0914823d1835a8d2a6e8d38d43c11c7..3609e7f52f800ed63680af1095508341dc4266ce 100644 (file)
@@ -12,7 +12,7 @@ The `unboxed_closures` feature allows you to write functions using the `"rust-ca
 required for implementing the [`Fn*`] family of traits. `"rust-call"` functions must have
 exactly one (non self) argument, a tuple representing the argument list.
 
-[`Fn*`]: https://doc.rust-lang.org/std/ops/trait.Fn.html
+[`Fn*`]: ../../std/ops/trait.Fn.html
 
 ```rust
 #![feature(unboxed_closures)]
index d40a27dddf362537a684669241b17ff0656afd84..bafc9ac4d0d966d0743389c1e7466a9624acf99b 100644 (file)
@@ -10,7 +10,7 @@ Adds a free `default()` function to the `std::default` module.  This function
 just forwards to [`Default::default()`], but may remove repetition of the word
 "default" from the call site.
 
-[`Default::default()`]: https://doc.rust-lang.org/nightly/std/default/trait.Default.html#tymethod.default
+[`Default::default()`]: ../../std/default/trait.Default.html#tymethod.default
 
 Here is an example:
 
index 29a8aecee6c2fd26e5420a2c06640823e01b99fa..180184146d1a0506053dab9425b361ee8133e84b 100644 (file)
@@ -11,7 +11,7 @@ See Also: [`unboxed_closures`](../language-features/unboxed-closures.md)
 The `fn_traits` feature allows for implementation of the [`Fn*`] traits
 for creating custom closure-like types.
 
-[`Fn*`]: https://doc.rust-lang.org/std/ops/trait.Fn.html
+[`Fn*`]: ../../std/ops/trait.Fn.html
 
 ```rust
 #![feature(unboxed_closures)]
index 1843a21205cfa65ef3de0f27c2b2391ac0b191b1..f1853f3697df2fe9c20c7ad398e42877263c154e 100644 (file)
@@ -507,7 +507,9 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
                         "openbsd" => "OpenBSD",
                         "redox" => "Redox",
                         "solaris" => "Solaris",
+                        "tvos" => "tvOS",
                         "wasi" => "WASI",
+                        "watchos" => "watchOS",
                         "windows" => "Windows",
                         _ => "",
                     },
index 50caef3553fdaf5f47d8e2248762494b06229750..d1601272af7596e709ab607294aa430b953ca4c0 100644 (file)
@@ -325,7 +325,7 @@ pub(crate) fn build_impls(
     // * https://github.com/rust-lang/rust/pull/99917 — where the feature got used
     // * https://github.com/rust-lang/rust/issues/53487 — overall tracking issue for Error
     if tcx.has_attr(did, sym::rustc_has_incoherent_inherent_impls) {
-        use rustc_middle::ty::fast_reject::SimplifiedTypeGen::*;
+        use rustc_middle::ty::fast_reject::SimplifiedType::*;
         let type_ =
             if tcx.is_trait(did) { TraitSimplifiedType(did) } else { AdtSimplifiedType(did) };
         for &did in tcx.incoherent_impls(type_) {
index 7a7313c4bc99d90e5987fa6d2864d7fedfea3a17..7a13e7e36d169c3c50cb31561469381a9414b651 100644 (file)
@@ -1870,7 +1870,7 @@ pub(crate) fn from_symbol(s: Symbol) -> Option<PrimitiveType> {
     }
 
     pub(crate) fn simplified_types() -> &'static SimplifiedTypes {
-        use ty::fast_reject::SimplifiedTypeGen::*;
+        use ty::fast_reject::SimplifiedType::*;
         use ty::{FloatTy, IntTy, UintTy};
         use PrimitiveType::*;
         static CELL: OnceCell<SimplifiedTypes> = OnceCell::new();
index b141820fe423c549217a41e58745f56d763009b6..aeaee524fd4532b820f130d04ccb7912ceb68411 100644 (file)
@@ -567,11 +567,12 @@ struct SummaryLine<'a, I: Iterator<Item = Event<'a>>> {
     inner: I,
     started: bool,
     depth: u32,
+    skipped_tags: u32,
 }
 
 impl<'a, I: Iterator<Item = Event<'a>>> SummaryLine<'a, I> {
     fn new(iter: I) -> Self {
-        SummaryLine { inner: iter, started: false, depth: 0 }
+        SummaryLine { inner: iter, started: false, depth: 0, skipped_tags: 0 }
     }
 }
 
@@ -601,6 +602,7 @@ fn next(&mut self) -> Option<Self::Item> {
             let is_allowed_tag = match event {
                 Event::Start(ref c) => {
                     if is_forbidden_tag(c) {
+                        self.skipped_tags += 1;
                         return None;
                     }
                     self.depth += 1;
@@ -608,6 +610,7 @@ fn next(&mut self) -> Option<Self::Item> {
                 }
                 Event::End(ref c) => {
                     if is_forbidden_tag(c) {
+                        self.skipped_tags += 1;
                         return None;
                     }
                     self.depth -= 1;
@@ -616,6 +619,9 @@ fn next(&mut self) -> Option<Self::Item> {
                 }
                 _ => true,
             };
+            if !is_allowed_tag {
+                self.skipped_tags += 1;
+            }
             return if !is_allowed_tag {
                 if is_start {
                     Some(Event::Start(Tag::Paragraph))
@@ -1096,11 +1102,11 @@ pub(crate) fn into_string(self) -> String {
 }
 
 impl MarkdownSummaryLine<'_> {
-    pub(crate) fn into_string(self) -> String {
+    pub(crate) fn into_string_with_has_more_content(self) -> (String, bool) {
         let MarkdownSummaryLine(md, links) = self;
         // This is actually common enough to special-case
         if md.is_empty() {
-            return String::new();
+            return (String::new(), false);
         }
 
         let mut replacer = |broken_link: BrokenLink<'_>| {
@@ -1110,17 +1116,26 @@ pub(crate) fn into_string(self) -> String {
                 .map(|link| (link.href.as_str().into(), link.new_text.as_str().into()))
         };
 
-        let p = Parser::new_with_broken_link_callback(md, summary_opts(), Some(&mut replacer));
+        let p = Parser::new_with_broken_link_callback(md, summary_opts(), Some(&mut replacer))
+            .peekable();
+        let mut summary = SummaryLine::new(p);
 
         let mut s = String::new();
 
-        let without_paragraphs = LinkReplacer::new(SummaryLine::new(p), links).filter(|event| {
+        let without_paragraphs = LinkReplacer::new(&mut summary, links).filter(|event| {
             !matches!(event, Event::Start(Tag::Paragraph) | Event::End(Tag::Paragraph))
         });
 
         html::push_html(&mut s, without_paragraphs);
 
-        s
+        let has_more_content =
+            matches!(summary.inner.peek(), Some(Event::Start(_))) || summary.skipped_tags > 0;
+
+        (s, has_more_content)
+    }
+
+    pub(crate) fn into_string(self) -> String {
+        self.into_string_with_has_more_content().0
     }
 }
 
index 80fbe9c1f066c6dbc139027e4235475f15318674..146e5010e4e42827d7743a3ef2e73ae04d15f354 100644 (file)
@@ -467,9 +467,10 @@ fn document_short(
         return;
     }
     if let Some(s) = item.doc_value() {
-        let mut summary_html = MarkdownSummaryLine(&s, &item.links(cx)).into_string();
+        let (mut summary_html, has_more_content) =
+            MarkdownSummaryLine(&s, &item.links(cx)).into_string_with_has_more_content();
 
-        if s.contains('\n') {
+        if has_more_content {
             let link = format!(r#" <a{}>Read more</a>"#, assoc_href_attr(item, link, cx));
 
             if let Some(idx) = summary_html.rfind("</p>") {
index bc1e15b359371be7ae9f83b3861b9bbeaef94697..b2f220b057110b578c2caea9fddb0c9ef284f594 100644 (file)
@@ -322,10 +322,6 @@ main {
        margin-right: auto;
 }
 
-.source .width-limiter {
-       max-width: unset;
-}
-
 details:not(.rustdoc-toggle) summary {
        margin-bottom: .6em;
 }
@@ -342,6 +338,7 @@ code, pre, a.test-arrow, .code-header {
 }
 pre {
        padding: 14px;
+       line-height: 1.5; /* https://github.com/rust-lang/rust/issues/105906 */
 }
 .item-decl pre {
        overflow-x: auto;
@@ -396,15 +393,15 @@ img {
        overflow-y: hidden;
 }
 
-.source .sidebar, #sidebar-toggle, #source-sidebar {
+.source .sidebar, #src-sidebar-toggle, #source-sidebar {
        background-color: var(--sidebar-background-color);
 }
 
-#sidebar-toggle > button:hover, #sidebar-toggle > button:focus {
+#src-sidebar-toggle > button:hover, #src-sidebar-toggle > button:focus {
        background-color: var(--sidebar-background-color-hover);
 }
 
-.source .sidebar > *:not(#sidebar-toggle) {
+.source .sidebar > *:not(#src-sidebar-toggle) {
        visibility: hidden;
 }
 
@@ -413,7 +410,7 @@ img {
        flex-basis: 300px;
 }
 
-.source-sidebar-expanded .source .sidebar > *:not(#sidebar-toggle) {
+.source-sidebar-expanded .source .sidebar > *:not(#src-sidebar-toggle) {
        visibility: visible;
 }
 
@@ -546,6 +543,7 @@ ul.block, .block li {
 .rustdoc .example-wrap > pre.example-line-numbers,
 .rustdoc .example-wrap > pre.src-line-numbers {
        flex-grow: 0;
+       min-width: fit-content; /* prevent collapsing into nothing in truncated scraped examples */
        overflow: initial;
        text-align: right;
        -webkit-user-select: none;
@@ -692,14 +690,10 @@ a {
        position: relative;
 }
 
-.small-section-header:hover > .anchor {
+.small-section-header:hover > .anchor, .impl:hover > .anchor,
+.trait-impl:hover > .anchor, .variant:hover > .anchor {
        display: initial;
 }
-
-.impl:hover > .anchor, .trait-impl:hover > .anchor, .variant:hover > .anchor {
-       display: inline-block;
-       position: absolute;
-}
 .anchor {
        display: none;
        position: absolute;
@@ -1071,6 +1065,10 @@ pre.rust .doccomment {
        color: var(--code-highlight-doc-comment-color);
 }
 
+.rustdoc.source .example-wrap pre.rust a {
+       background: var(--codeblock-link-background);
+}
+
 .example-wrap.compile_fail,
 .example-wrap.should_panic {
        border-left: 2px solid var(--codeblock-error-color);
@@ -1114,8 +1112,7 @@ pre.rust .doccomment {
        top: 5px;
 }
 
-.example-wrap .tooltip::after {
-       display: none;
+.example-wrap .tooltip:hover::after {
        text-align: center;
        padding: 5px 3px 3px 3px;
        border-radius: 6px;
@@ -1130,35 +1127,30 @@ pre.rust .doccomment {
        color: var(--tooltip-color);
 }
 
-.example-wrap .tooltip::before {
+.example-wrap .tooltip:hover::before {
        content: " ";
        position: absolute;
        top: 50%;
        left: 16px;
        margin-top: -5px;
-       display: none;
        z-index: 1;
        border: 5px solid transparent;
        border-right-color: var(--tooltip-background-color);
 }
 
-.example-wrap.ignore .tooltip::after {
+.example-wrap.ignore .tooltip:hover::after {
        content: "This example is not tested";
 }
-.example-wrap.compile_fail .tooltip::after {
+.example-wrap.compile_fail .tooltip:hover::after {
        content: "This example deliberately fails to compile";
 }
-.example-wrap.should_panic .tooltip::after {
+.example-wrap.should_panic .tooltip:hover::after {
        content: "This example panics";
 }
-.example-wrap.edition .tooltip::after {
+.example-wrap.edition .tooltip:hover::after {
        content: "This code runs with edition " attr(data-edition);
 }
 
-.example-wrap .tooltip:hover::before, .example-wrap .tooltip:hover::after {
-       display: inline;
-}
-
 .example-wrap.compile_fail .tooltip,
 .example-wrap.should_panic .tooltip,
 .example-wrap.ignore .tooltip {
@@ -1291,7 +1283,7 @@ a.test-arrow:hover {
        font-size: 1rem;
 }
 
-#sidebar-toggle {
+#src-sidebar-toggle {
        position: sticky;
        top: 0;
        left: 0;
@@ -1320,7 +1312,7 @@ a.test-arrow:hover {
 #source-sidebar div.files > a.selected {
        background-color: var(--source-sidebar-background-selected);
 }
-#sidebar-toggle > button {
+#src-sidebar-toggle > button {
        font-size: inherit;
        font-weight: bold;
        background: none;
@@ -1722,7 +1714,7 @@ in storage.js
                left: -11px;
        }
 
-       #sidebar-toggle {
+       #src-sidebar-toggle {
                position: fixed;
                left: 1px;
                top: 100px;
@@ -1736,7 +1728,7 @@ in storage.js
                border-left: 0;
        }
 
-       .source-sidebar-expanded #sidebar-toggle {
+       .source-sidebar-expanded #src-sidebar-toggle {
                left: unset;
                top: unset;
                width: unset;
@@ -1847,10 +1839,10 @@ in storage.js
                width: 35px;
        }
 
-       #sidebar-toggle {
+       #src-sidebar-toggle {
                top: 10px;
        }
-       .source-sidebar-expanded #sidebar-toggle {
+       .source-sidebar-expanded #src-sidebar-toggle {
                top: unset;
        }
 }
@@ -1978,10 +1970,7 @@ in storage.js
 }
 
 .scraped-example .code-wrapper .example-wrap {
-       display: grid;
-       grid-template-columns: max-content auto;
        width: 100%;
-       overflow-x: auto;
        overflow-y: hidden;
        margin-bottom: 0;
 }
@@ -1990,13 +1979,6 @@ in storage.js
        overflow-x: hidden;
 }
 
-.scraped-example .code-wrapper .example-wrap pre.rust {
-       overflow-x: inherit;
-       width: inherit;
-       overflow-y: hidden;
-}
-
-
 .more-examples-toggle {
        max-width: calc(100% + 25px);
        margin-top: 10px;
@@ -2005,7 +1987,6 @@ in storage.js
 
 .more-examples-toggle .hide-more {
        margin-left: 25px;
-       margin-bottom: 5px;
        cursor: pointer;
 }
 
@@ -2033,16 +2014,12 @@ in storage.js
        height: 100%;
 }
 
-.more-scraped-examples .scraped-example {
-       margin-bottom: 20px;
-}
-
-.more-scraped-examples .scraped-example:last-child {
-       margin-bottom: 0;
+.more-scraped-examples .scraped-example, .example-links {
+       margin-top: 20px;
 }
 
-.example-links a {
-       margin-top: 20px;
+.more-scraped-examples .scraped-example:first-child {
+       margin-top: 5px;
 }
 
 .example-links ul {
index 1f6fb961e918d430a5ad45ba293819769717c982..875a260c8115ebdb849b8f26593ed7d4981cb4ba 100644 (file)
        cursor: pointer;
 }
 
-.setting-line > .sub-settings {
-       padding-left: 42px;
-       width: 100%;
-       display: block;
-}
-
 #settings .setting-line {
        margin: 1.2em 0.6em;
 }
index a4097c456135dad24cd093f23ad34e489de489a9..de0dfcd469045e74c94e3037f60500bfbc2d50e4 100644 (file)
@@ -88,6 +88,7 @@ Original by Dempfi (https://github.com/dempfi/ayu)
        --source-sidebar-background-selected: #14191f;
        --source-sidebar-background-hover: #14191f;
        --table-alt-row-background-color: #191f26;
+       --codeblock-link-background: #333;
 }
 
 h1, h2, h3, h4 {
@@ -154,9 +155,6 @@ pre, .rustdoc.source .example-wrap {
 .sidebar h3 a {
        color: white;
 }
-body.source .example-wrap pre.rust a {
-       background: #333;
-}
 
 .result-name .primitive > i, .result-name .keyword > i {
        color: #788797;
index a11aba12e0ac77a739f3cc0144373e451917b489..dd7fc6892537c35b57a5e12ce63cfc1a71b3e545 100644 (file)
        --source-sidebar-background-selected: #333;
        --source-sidebar-background-hover: #444;
        --table-alt-row-background-color: #2A2A2A;
-}
-
-body.source .example-wrap pre.rust a {
-       background: #333;
+       --codeblock-link-background: #333;
 }
 
 #titles > button:not(.selected) {
index f697724468fb3c647794acfdc31fad0ea2c978fa..b69d8a1cff95753f1255550bc5d87be641af01f0 100644 (file)
        --source-sidebar-background-selected: #fff;
        --source-sidebar-background-hover: #e0e0e0;
        --table-alt-row-background-color: #F5F5F5;
-}
-
-body.source .example-wrap pre.rust a {
-       background: #eee;
+       --codeblock-link-background: #eee;
 }
 
 #titles > button:not(.selected) {
index 5db768c1c5753aa063d1b9f828b67ef76f005660..0e1c864e62d84800243b619e83ba490639e76f00 100644 (file)
@@ -83,7 +83,7 @@ function toggleSidebar() {
 
 function createSidebarToggle() {
     const sidebarToggle = document.createElement("div");
-    sidebarToggle.id = "sidebar-toggle";
+    sidebarToggle.id = "src-sidebar-toggle";
 
     const inner = document.createElement("button");
 
index aa3bf827db4bf5d0c60ab36e98c133105fef4040..bcaff957af2f60aa2ed651a9b464bb8374eca9d1 100644 (file)
@@ -99,7 +99,7 @@
         {{- sidebar|safe -}}
     </nav> {#- -#}
     <main> {#- -#}
-        <div class="width-limiter"> {#- -#}
+        {%- if page.css_class != "source" -%}<div class="width-limiter">{%- endif -%}
             <nav class="sub"> {#- -#}
                 {%- if page.css_class == "source" -%}
                 <a class="sub-logo-container" href="{{page.root_path|safe}}{{krate_with_trailing_slash|safe}}index.html"> {#- -#}
                 </form> {#- -#}
             </nav> {#- -#}
             <section id="main-content" class="content">{{- content|safe -}}</section> {#- -#}
-        </div> {#- -#}
+        {%- if page.css_class != "source" -%}</div>{%- endif -%}
     </main> {#- -#}
     {{- layout.external_html.after_content|safe -}}
     <div id="rustdoc-vars" {# -#}
diff --git a/src/test/assembly/x86_64-no-jump-tables.rs b/src/test/assembly/x86_64-no-jump-tables.rs
new file mode 100644 (file)
index 0000000..007c359
--- /dev/null
@@ -0,0 +1,34 @@
+// Test that jump tables are (not) emitted when the `-Zno-jump-tables`
+// flag is (not) set.
+
+// revisions: unset set
+// assembly-output: emit-asm
+// compile-flags: -O
+// [set] compile-flags: -Zno-jump-tables
+// only-x86_64
+
+#![crate_type = "lib"]
+
+extern "C" {
+    fn bar1();
+    fn bar2();
+    fn bar3();
+    fn bar4();
+    fn bar5();
+    fn bar6();
+}
+
+// CHECK-LABEL: foo:
+#[no_mangle]
+pub unsafe fn foo(x: i32) {
+    // unset: LJTI0_0
+    // set-NOT: LJTI0_0
+    match x {
+        1 => bar1(),
+        2 => bar2(),
+        3 => bar3(),
+        4 => bar4(),
+        5 => bar5(),
+        _ => bar6(),
+    }
+}
index 14c4c3f30f94a1ba07e5f756113c160e79af3d61..54f6e7f992fe65f3bdbdfa3d953ada730ab4b3dd 100644 (file)
@@ -1,6 +1,7 @@
-// compile-flags: -O
+// compile-flags: -O -Z merge-functions=disabled
 
 #![crate_type = "lib"]
+#![feature(core_intrinsics)]
 
 // This test checks that we annotate alignment loads from vtables with nonzero range metadata,
 // and that this allows LLVM to eliminate redundant `align >= 1` checks.
@@ -42,4 +43,19 @@ pub fn does_not_eliminate_runtime_check_when_align_2(
     &x.dst
 }
 
+// CHECK-LABEL: @align_load_from_align_of_val
+#[no_mangle]
+pub fn align_load_from_align_of_val(x: &dyn Trait) -> usize {
+    // CHECK: {{%[0-9]+}} = load [[USIZE]], {{.+}} !range [[RANGE_META]]
+    core::mem::align_of_val(x)
+}
+
+// CHECK-LABEL: @align_load_from_vtable_align_intrinsic
+#[no_mangle]
+pub unsafe fn align_load_from_vtable_align_intrinsic(x: &dyn Trait) -> usize {
+    let (data, vtable): (*const (), *const ()) = core::mem::transmute(x);
+    // CHECK: {{%[0-9]+}} = load [[USIZE]], {{.+}} !range [[RANGE_META]]
+    core::intrinsics::vtable_align(vtable)
+}
+
 // CHECK: [[RANGE_META]] = !{[[USIZE]] 1, [[USIZE]] 0}
diff --git a/src/test/codegen/dst-vtable-size-range.rs b/src/test/codegen/dst-vtable-size-range.rs
new file mode 100644 (file)
index 0000000..671c8ab
--- /dev/null
@@ -0,0 +1,35 @@
+// compile-flags: -O -Z merge-functions=disabled
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+// Check that we annotate size loads from vtables with 0..(isize::MAX + 1) range metadata.
+
+pub trait Trait {
+    fn f(&self);
+}
+
+// Note that rustc uses inclusive bounds, but LLVM uses exclusive bounds for range metadata.
+// CHECK-LABEL: @generate_exclusive_bound
+#[no_mangle]
+pub fn generate_exclusive_bound() -> usize {
+    // CHECK: ret [[USIZE:i[0-9]+]] [[EXCLUSIVE_BOUND:[-0-9]+]]
+    isize::MAX as usize + 1
+}
+
+// CHECK-LABEL: @size_load_from_size_of_val
+#[no_mangle]
+pub fn size_load_from_size_of_val(x: &dyn Trait) -> usize {
+    // CHECK: {{%[0-9]+}} = load [[USIZE]], {{.+}} !range [[RANGE_META:![0-9]+]]
+    core::mem::size_of_val(x)
+}
+
+// CHECK-LABEL: @size_load_from_vtable_size_intrinsic
+#[no_mangle]
+pub unsafe fn size_load_from_vtable_size_intrinsic(x: &dyn Trait) -> usize {
+    let (data, vtable): (*const (), *const ()) = core::mem::transmute(x);
+    // CHECK: {{%[0-9]+}} = load [[USIZE]], {{.+}} !range [[RANGE_META]]
+    core::intrinsics::vtable_size(vtable)
+}
+
+// CHECK: [[RANGE_META]] = !{[[USIZE]] 0, [[USIZE]] [[EXCLUSIVE_BOUND]]}
index 44f1b408d21b8f0ede3c3ceb48cec463f614e142..827eb20154afd0195cc1da957b67aa483444f56b 100644 (file)
@@ -34,8 +34,8 @@ pub enum Enum1 {
 
 // CHECK: define i8 @match1{{.*}}
 // CHECK-NEXT: start:
-// CHECK-NEXT: %1 = {{.*}}call i8 @llvm.usub.sat.i8(i8 %0, i8 1)
-// CHECK-NEXT: switch i8 %1, label {{.*}} [
+// CHECK-NEXT: [[DISCR:%.*]] = {{.*}}call i8 @llvm.usub.sat.i8(i8 %0, i8 1)
+// CHECK-NEXT: switch i8 [[DISCR]], label {{.*}} [
 #[no_mangle]
 pub fn match1(e: Enum1) -> u8 {
     use Enum1::*;
diff --git a/src/test/codegen/no-jump-tables.rs b/src/test/codegen/no-jump-tables.rs
new file mode 100644 (file)
index 0000000..8e2cb47
--- /dev/null
@@ -0,0 +1,22 @@
+// Test that the `no-jump-tables` function attribute are (not) emitted when
+// the `-Zno-jump-tables` flag is (not) set.
+
+// revisions: unset set
+// needs-llvm-components: x86
+// compile-flags: --target x86_64-unknown-linux-gnu
+// [set] compile-flags: -Zno-jump-tables
+
+#![crate_type = "lib"]
+#![feature(no_core, lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+
+#[no_mangle]
+pub fn foo() {
+    // CHECK: @foo() unnamed_addr #0
+
+    // unset-NOT: attributes #0 = { {{.*}}"no-jump-tables"="true"{{.*}} }
+    // set: attributes #0 = { {{.*}}"no-jump-tables"="true"{{.*}} }
+}
diff --git a/src/test/mir-opt/building/custom/enums.rs b/src/test/mir-opt/building/custom/enums.rs
new file mode 100644 (file)
index 0000000..e5cd456
--- /dev/null
@@ -0,0 +1,120 @@
+#![feature(custom_mir, core_intrinsics)]
+
+extern crate core;
+use core::intrinsics::mir::*;
+
+// EMIT_MIR enums.switch_bool.built.after.mir
+#[custom_mir(dialect = "built")]
+pub fn switch_bool(b: bool) -> u32 {
+    mir!(
+        {
+            match b {
+                true => t,
+                false => f,
+                _ => f,
+            }
+        }
+
+        t = {
+            RET = 5;
+            Return()
+        }
+
+        f = {
+            RET = 10;
+            Return()
+        }
+    )
+}
+
+// EMIT_MIR enums.switch_option.built.after.mir
+#[custom_mir(dialect = "built")]
+pub fn switch_option(option: Option<()>) -> bool {
+    mir!(
+        {
+            let discr = Discriminant(option);
+            match discr {
+                0 => n,
+                1 => s,
+                _ => s,
+            }
+        }
+
+        n = {
+            RET = false;
+            Return()
+        }
+
+        s = {
+            RET = true;
+            Return()
+        }
+    )
+}
+
+#[repr(u8)]
+enum Bool {
+    False = 0,
+    True = 1,
+}
+
+// EMIT_MIR enums.switch_option_repr.built.after.mir
+#[custom_mir(dialect = "built")]
+fn switch_option_repr(option: Bool) -> bool {
+    mir!(
+        {
+            let discr = Discriminant(option);
+            match discr {
+                0 => f,
+                _ => t,
+            }
+        }
+
+        t = {
+            RET = true;
+            Return()
+        }
+
+        f = {
+            RET = false;
+            Return()
+        }
+    )
+}
+
+// EMIT_MIR enums.set_discr.built.after.mir
+#[custom_mir(dialect = "runtime", phase = "initial")]
+fn set_discr(option: &mut Option<()>) {
+    mir!({
+        SetDiscriminant(*option, 0);
+        Return()
+    })
+}
+
+// EMIT_MIR enums.set_discr_repr.built.after.mir
+#[custom_mir(dialect = "runtime", phase = "initial")]
+fn set_discr_repr(b: &mut Bool) {
+    mir!({
+        SetDiscriminant(*b, 0);
+        Return()
+    })
+}
+
+fn main() {
+    assert_eq!(switch_bool(true), 5);
+    assert_eq!(switch_bool(false), 10);
+
+    assert_eq!(switch_option(Some(())), true);
+    assert_eq!(switch_option(None), false);
+
+    assert_eq!(switch_option_repr(Bool::True), true);
+    assert_eq!(switch_option_repr(Bool::False), false);
+
+    let mut opt = Some(());
+    set_discr(&mut opt);
+    assert_eq!(opt, None);
+
+    let mut b = Bool::True;
+    set_discr_repr(&mut b);
+    assert!(matches!(b, Bool::False));
+}
diff --git a/src/test/mir-opt/building/custom/enums.set_discr.built.after.mir b/src/test/mir-opt/building/custom/enums.set_discr.built.after.mir
new file mode 100644 (file)
index 0000000..7de9ed0
--- /dev/null
@@ -0,0 +1,10 @@
+// MIR for `set_discr` after built
+
+fn set_discr(_1: &mut Option<()>) -> () {
+    let mut _0: ();                      // return place in scope 0 at $DIR/enums.rs:+0:39: +0:39
+
+    bb0: {
+        discriminant((*_1)) = 0;         // scope 0 at $DIR/enums.rs:+2:9: +2:36
+        return;                          // scope 0 at $DIR/enums.rs:+3:9: +3:17
+    }
+}
diff --git a/src/test/mir-opt/building/custom/enums.set_discr_repr.built.after.mir b/src/test/mir-opt/building/custom/enums.set_discr_repr.built.after.mir
new file mode 100644 (file)
index 0000000..6fdc3d0
--- /dev/null
@@ -0,0 +1,10 @@
+// MIR for `set_discr_repr` after built
+
+fn set_discr_repr(_1: &mut Bool) -> () {
+    let mut _0: ();                      // return place in scope 0 at $DIR/enums.rs:+0:33: +0:33
+
+    bb0: {
+        discriminant((*_1)) = 0;         // scope 0 at $DIR/enums.rs:+2:9: +2:31
+        return;                          // scope 0 at $DIR/enums.rs:+3:9: +3:17
+    }
+}
diff --git a/src/test/mir-opt/building/custom/enums.switch_bool.built.after.mir b/src/test/mir-opt/building/custom/enums.switch_bool.built.after.mir
new file mode 100644 (file)
index 0000000..95c57d2
--- /dev/null
@@ -0,0 +1,19 @@
+// MIR for `switch_bool` after built
+
+fn switch_bool(_1: bool) -> u32 {
+    let mut _0: u32;                     // return place in scope 0 at $DIR/enums.rs:+0:32: +0:35
+
+    bb0: {
+        switchInt(_1) -> [1: bb1, 0: bb2, otherwise: bb2]; // scope 0 at $DIR/enums.rs:+3:13: +7:14
+    }
+
+    bb1: {
+        _0 = const 5_u32;                // scope 0 at $DIR/enums.rs:+11:13: +11:20
+        return;                          // scope 0 at $DIR/enums.rs:+12:13: +12:21
+    }
+
+    bb2: {
+        _0 = const 10_u32;               // scope 0 at $DIR/enums.rs:+16:13: +16:21
+        return;                          // scope 0 at $DIR/enums.rs:+17:13: +17:21
+    }
+}
diff --git a/src/test/mir-opt/building/custom/enums.switch_option.built.after.mir b/src/test/mir-opt/building/custom/enums.switch_option.built.after.mir
new file mode 100644 (file)
index 0000000..a659ba7
--- /dev/null
@@ -0,0 +1,21 @@
+// MIR for `switch_option` after built
+
+fn switch_option(_1: Option<()>) -> bool {
+    let mut _0: bool;                    // return place in scope 0 at $DIR/enums.rs:+0:45: +0:49
+    let mut _2: isize;                   // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+
+    bb0: {
+        _2 = discriminant(_1);           // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+        switchInt(_2) -> [0: bb1, 1: bb2, otherwise: bb2]; // scope 0 at $DIR/enums.rs:+4:13: +8:14
+    }
+
+    bb1: {
+        _0 = const false;                // scope 0 at $DIR/enums.rs:+12:13: +12:24
+        return;                          // scope 0 at $DIR/enums.rs:+13:13: +13:21
+    }
+
+    bb2: {
+        _0 = const true;                 // scope 0 at $DIR/enums.rs:+17:13: +17:23
+        return;                          // scope 0 at $DIR/enums.rs:+18:13: +18:21
+    }
+}
diff --git a/src/test/mir-opt/building/custom/enums.switch_option_repr.built.after.mir b/src/test/mir-opt/building/custom/enums.switch_option_repr.built.after.mir
new file mode 100644 (file)
index 0000000..d60e4b1
--- /dev/null
@@ -0,0 +1,21 @@
+// MIR for `switch_option_repr` after built
+
+fn switch_option_repr(_1: Bool) -> bool {
+    let mut _0: bool;                    // return place in scope 0 at $DIR/enums.rs:+0:40: +0:44
+    let mut _2: u8;                      // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+
+    bb0: {
+        _2 = discriminant(_1);           // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+        switchInt(_2) -> [0: bb2, otherwise: bb1]; // scope 0 at $DIR/enums.rs:+4:13: +7:14
+    }
+
+    bb1: {
+        _0 = const true;                 // scope 0 at $DIR/enums.rs:+11:13: +11:23
+        return;                          // scope 0 at $DIR/enums.rs:+12:13: +12:21
+    }
+
+    bb2: {
+        _0 = const false;                // scope 0 at $DIR/enums.rs:+16:13: +16:24
+        return;                          // scope 0 at $DIR/enums.rs:+17:13: +17:21
+    }
+}
diff --git a/src/test/mir-opt/building/custom/projections.rs b/src/test/mir-opt/building/custom/projections.rs
new file mode 100644 (file)
index 0000000..5e472e5
--- /dev/null
@@ -0,0 +1,85 @@
+#![feature(custom_mir, core_intrinsics)]
+
+extern crate core;
+use core::intrinsics::mir::*;
+
+union U {
+    a: i32,
+    b: u32,
+}
+
+// EMIT_MIR projections.unions.built.after.mir
+#[custom_mir(dialect = "built")]
+fn unions(u: U) -> i32 {
+    mir!({
+        RET = u.a;
+        Return()
+    })
+}
+
+// EMIT_MIR projections.tuples.built.after.mir
+#[custom_mir(dialect = "analysis", phase = "post-cleanup")]
+fn tuples(i: (u32, i32)) -> (u32, i32) {
+    mir!(
+        // FIXME(JakobDegen): This is necessary because we can't give type hints for `RET`
+        let temp: (u32, i32);
+        {
+            temp.0 = i.0;
+            temp.1 = i.1;
+
+            RET = temp;
+            Return()
+        }
+    )
+}
+
+// EMIT_MIR projections.unwrap.built.after.mir
+#[custom_mir(dialect = "built")]
+fn unwrap(opt: Option<i32>) -> i32 {
+    mir!({
+        RET = Field(Variant(opt, 1), 0);
+        Return()
+    })
+}
+
+// EMIT_MIR projections.unwrap_deref.built.after.mir
+#[custom_mir(dialect = "built")]
+fn unwrap_deref(opt: Option<&i32>) -> i32 {
+    mir!({
+        RET = *Field::<&i32>(Variant(opt, 1), 0);
+        Return()
+    })
+}
+
+// EMIT_MIR projections.set.built.after.mir
+#[custom_mir(dialect = "built")]
+fn set(opt: &mut Option<i32>) {
+    mir!({
+        place!(Field(Variant(*opt, 1), 0)) = 10;
+        Return()
+    })
+}
+
+// EMIT_MIR projections.simple_index.built.after.mir
+#[custom_mir(dialect = "built")]
+fn simple_index(a: [i32; 10], b: &[i32]) -> i32 {
+    mir!({
+        let temp = 3;
+        RET = a[temp];
+        RET = (*b)[temp];
+        Return()
+    })
+}
+
+fn main() {
+    assert_eq!(unions(U { a: 5 }), 5);
+    assert_eq!(tuples((5, 6)), (5, 6));
+
+    assert_eq!(unwrap(Some(5)), 5);
+    assert_eq!(unwrap_deref(Some(&5)), 5);
+    let mut o = Some(5);
+    set(&mut o);
+    assert_eq!(o, Some(10));
+
+    assert_eq!(simple_index([0; 10], &[0; 10]), 0);
+}
diff --git a/src/test/mir-opt/building/custom/projections.set.built.after.mir b/src/test/mir-opt/building/custom/projections.set.built.after.mir
new file mode 100644 (file)
index 0000000..2f15176
--- /dev/null
@@ -0,0 +1,10 @@
+// MIR for `set` after built
+
+fn set(_1: &mut Option<i32>) -> () {
+    let mut _0: ();                      // return place in scope 0 at $DIR/projections.rs:+0:31: +0:31
+
+    bb0: {
+        (((*_1) as variant#1).0: i32) = const 10_i32; // scope 0 at $DIR/projections.rs:+2:9: +2:48
+        return;                          // scope 0 at $DIR/projections.rs:+3:9: +3:17
+    }
+}
diff --git a/src/test/mir-opt/building/custom/projections.simple_index.built.after.mir b/src/test/mir-opt/building/custom/projections.simple_index.built.after.mir
new file mode 100644 (file)
index 0000000..fc422e4
--- /dev/null
@@ -0,0 +1,13 @@
+// MIR for `simple_index` after built
+
+fn simple_index(_1: [i32; 10], _2: &[i32]) -> i32 {
+    let mut _0: i32;                     // return place in scope 0 at $DIR/projections.rs:+0:45: +0:48
+    let mut _3: usize;                   // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+
+    bb0: {
+        _3 = const 3_usize;              // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+        _0 = _1[_3];                     // scope 0 at $DIR/projections.rs:+3:9: +3:22
+        _0 = (*_2)[_3];                  // scope 0 at $DIR/projections.rs:+4:9: +4:25
+        return;                          // scope 0 at $DIR/projections.rs:+5:9: +5:17
+    }
+}
diff --git a/src/test/mir-opt/building/custom/projections.tuples.built.after.mir b/src/test/mir-opt/building/custom/projections.tuples.built.after.mir
new file mode 100644 (file)
index 0000000..65487d3
--- /dev/null
@@ -0,0 +1,13 @@
+// MIR for `tuples` after built
+
+fn tuples(_1: (u32, i32)) -> (u32, i32) {
+    let mut _0: (u32, i32);              // return place in scope 0 at $DIR/projections.rs:+0:29: +0:39
+    let mut _2: (u32, i32);              // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+
+    bb0: {
+        (_2.0: u32) = (_1.0: u32);       // scope 0 at $DIR/projections.rs:+5:13: +5:25
+        (_2.1: i32) = (_1.1: i32);       // scope 0 at $DIR/projections.rs:+6:13: +6:25
+        _0 = _2;                         // scope 0 at $DIR/projections.rs:+8:13: +8:23
+        return;                          // scope 0 at $DIR/projections.rs:+9:13: +9:21
+    }
+}
diff --git a/src/test/mir-opt/building/custom/projections.unions.built.after.mir b/src/test/mir-opt/building/custom/projections.unions.built.after.mir
new file mode 100644 (file)
index 0000000..922538a
--- /dev/null
@@ -0,0 +1,10 @@
+// MIR for `unions` after built
+
+fn unions(_1: U) -> i32 {
+    let mut _0: i32;                     // return place in scope 0 at $DIR/projections.rs:+0:20: +0:23
+
+    bb0: {
+        _0 = (_1.0: i32);                // scope 0 at $DIR/projections.rs:+2:9: +2:18
+        return;                          // scope 0 at $DIR/projections.rs:+3:9: +3:17
+    }
+}
diff --git a/src/test/mir-opt/building/custom/projections.unwrap.built.after.mir b/src/test/mir-opt/building/custom/projections.unwrap.built.after.mir
new file mode 100644 (file)
index 0000000..75b03a3
--- /dev/null
@@ -0,0 +1,10 @@
+// MIR for `unwrap` after built
+
+fn unwrap(_1: Option<i32>) -> i32 {
+    let mut _0: i32;                     // return place in scope 0 at $DIR/projections.rs:+0:32: +0:35
+
+    bb0: {
+        _0 = ((_1 as variant#1).0: i32); // scope 0 at $DIR/projections.rs:+2:9: +2:40
+        return;                          // scope 0 at $DIR/projections.rs:+3:9: +3:17
+    }
+}
diff --git a/src/test/mir-opt/building/custom/projections.unwrap_deref.built.after.mir b/src/test/mir-opt/building/custom/projections.unwrap_deref.built.after.mir
new file mode 100644 (file)
index 0000000..c6b0f7e
--- /dev/null
@@ -0,0 +1,10 @@
+// MIR for `unwrap_deref` after built
+
+fn unwrap_deref(_1: Option<&i32>) -> i32 {
+    let mut _0: i32;                     // return place in scope 0 at $DIR/projections.rs:+0:39: +0:42
+
+    bb0: {
+        _0 = (*((_1 as variant#1).0: &i32)); // scope 0 at $DIR/projections.rs:+2:9: +2:49
+        return;                          // scope 0 at $DIR/projections.rs:+3:9: +3:17
+    }
+}
diff --git a/src/test/mir-opt/building/custom/references.raw_pointer.built.after.mir b/src/test/mir-opt/building/custom/references.raw_pointer.built.after.mir
new file mode 100644 (file)
index 0000000..775e5e3
--- /dev/null
@@ -0,0 +1,10 @@
+// MIR for `raw_pointer` after built
+
+fn raw_pointer(_1: *const i32) -> *const i32 {
+    let mut _0: *const i32;              // return place in scope 0 at $DIR/references.rs:+0:38: +0:48
+
+    bb0: {
+        _0 = &raw const (*_1);           // scope 0 at $DIR/references.rs:+4:9: +4:27
+        return;                          // scope 0 at $DIR/references.rs:+5:9: +5:17
+    }
+}
index dee85722e8656daaffc42780c5d8ef5946dc0023..c93f6ec624b3551784c67643d449ce3a4bce8c7c 100644 (file)
@@ -36,8 +36,22 @@ pub fn immut_ref(x: &i32) -> &i32 {
     )
 }
 
+// EMIT_MIR references.raw_pointer.built.after.mir
+#[custom_mir(dialect = "built")]
+pub fn raw_pointer(x: *const i32) -> *const i32 {
+    // Regression test for a bug in which unsafetyck was not correctly turned off for
+    // `dialect = "built"`
+    mir!({
+        RET = addr_of!(*x);
+        Return()
+    })
+}
+
 fn main() {
     let mut x = 5;
     assert_eq!(*mut_ref(&mut x), 5);
     assert_eq!(*immut_ref(&x), 5);
+    unsafe {
+        assert_eq!(*raw_pointer(addr_of!(x)), 5);
+    }
 }
diff --git a/src/test/mir-opt/building/custom/terminators.assert_nonzero.built.after.mir b/src/test/mir-opt/building/custom/terminators.assert_nonzero.built.after.mir
new file mode 100644 (file)
index 0000000..a1a2722
--- /dev/null
@@ -0,0 +1,17 @@
+// MIR for `assert_nonzero` after built
+
+fn assert_nonzero(_1: i32) -> () {
+    let mut _0: ();                      // return place in scope 0 at $DIR/terminators.rs:+0:27: +0:27
+
+    bb0: {
+        switchInt(_1) -> [0: bb1, otherwise: bb2]; // scope 0 at $DIR/terminators.rs:+3:13: +6:14
+    }
+
+    bb1: {
+        unreachable;                     // scope 0 at $DIR/terminators.rs:+10:13: +10:26
+    }
+
+    bb2: {
+        return;                          // scope 0 at $DIR/terminators.rs:+14:13: +14:21
+    }
+}
diff --git a/src/test/mir-opt/building/custom/terminators.direct_call.built.after.mir b/src/test/mir-opt/building/custom/terminators.direct_call.built.after.mir
new file mode 100644 (file)
index 0000000..1b2345a
--- /dev/null
@@ -0,0 +1,16 @@
+// MIR for `direct_call` after built
+
+fn direct_call(_1: i32) -> i32 {
+    let mut _0: i32;                     // return place in scope 0 at $DIR/terminators.rs:+0:27: +0:30
+
+    bb0: {
+        _0 = ident::<i32>(_1) -> bb1;    // scope 0 at $DIR/terminators.rs:+3:13: +3:42
+                                         // mir::Constant
+                                         // + span: $DIR/terminators.rs:15:33: 15:38
+                                         // + literal: Const { ty: fn(i32) -> i32 {ident::<i32>}, val: Value(<ZST>) }
+    }
+
+    bb1: {
+        return;                          // scope 0 at $DIR/terminators.rs:+7:13: +7:21
+    }
+}
diff --git a/src/test/mir-opt/building/custom/terminators.drop_first.built.after.mir b/src/test/mir-opt/building/custom/terminators.drop_first.built.after.mir
new file mode 100644 (file)
index 0000000..c903e59
--- /dev/null
@@ -0,0 +1,13 @@
+// MIR for `drop_first` after built
+
+fn drop_first(_1: WriteOnDrop<'_>, _2: WriteOnDrop<'_>) -> () {
+    let mut _0: ();                      // return place in scope 0 at $DIR/terminators.rs:+0:59: +0:59
+
+    bb0: {
+        replace(_1 <- move _2) -> bb1;   // scope 0 at $DIR/terminators.rs:+3:13: +3:49
+    }
+
+    bb1: {
+        return;                          // scope 0 at $DIR/terminators.rs:+7:13: +7:21
+    }
+}
diff --git a/src/test/mir-opt/building/custom/terminators.drop_second.built.after.mir b/src/test/mir-opt/building/custom/terminators.drop_second.built.after.mir
new file mode 100644 (file)
index 0000000..f14246f
--- /dev/null
@@ -0,0 +1,13 @@
+// MIR for `drop_second` after built
+
+fn drop_second(_1: WriteOnDrop<'_>, _2: WriteOnDrop<'_>) -> () {
+    let mut _0: ();                      // return place in scope 0 at $DIR/terminators.rs:+0:60: +0:60
+
+    bb0: {
+        drop(_2) -> bb1;                 // scope 0 at $DIR/terminators.rs:+3:13: +3:30
+    }
+
+    bb1: {
+        return;                          // scope 0 at $DIR/terminators.rs:+7:13: +7:21
+    }
+}
diff --git a/src/test/mir-opt/building/custom/terminators.indirect_call.built.after.mir b/src/test/mir-opt/building/custom/terminators.indirect_call.built.after.mir
new file mode 100644 (file)
index 0000000..2f1b140
--- /dev/null
@@ -0,0 +1,13 @@
+// MIR for `indirect_call` after built
+
+fn indirect_call(_1: i32, _2: fn(i32) -> i32) -> i32 {
+    let mut _0: i32;                     // return place in scope 0 at $DIR/terminators.rs:+0:48: +0:51
+
+    bb0: {
+        _0 = _2(_1) -> bb1;              // scope 0 at $DIR/terminators.rs:+3:13: +3:38
+    }
+
+    bb1: {
+        return;                          // scope 0 at $DIR/terminators.rs:+7:13: +7:21
+    }
+}
diff --git a/src/test/mir-opt/building/custom/terminators.rs b/src/test/mir-opt/building/custom/terminators.rs
new file mode 100644 (file)
index 0000000..c23233f
--- /dev/null
@@ -0,0 +1,108 @@
+#![feature(custom_mir, core_intrinsics)]
+
+extern crate core;
+use core::intrinsics::mir::*;
+
+fn ident<T>(t: T) -> T {
+    t
+}
+
+// EMIT_MIR terminators.direct_call.built.after.mir
+#[custom_mir(dialect = "built")]
+fn direct_call(x: i32) -> i32 {
+    mir!(
+        {
+            Call(RET, retblock, ident(x))
+        }
+
+        retblock = {
+            Return()
+        }
+    )
+}
+
+// EMIT_MIR terminators.indirect_call.built.after.mir
+#[custom_mir(dialect = "built")]
+fn indirect_call(x: i32, f: fn(i32) -> i32) -> i32 {
+    mir!(
+        {
+            Call(RET, retblock, f(x))
+        }
+
+        retblock = {
+            Return()
+        }
+    )
+}
+
+struct WriteOnDrop<'a>(&'a mut i32, i32);
+
+impl<'a> Drop for WriteOnDrop<'a> {
+    fn drop(&mut self) {
+        *self.0 = self.1;
+    }
+}
+
+// EMIT_MIR terminators.drop_first.built.after.mir
+#[custom_mir(dialect = "built")]
+fn drop_first<'a>(a: WriteOnDrop<'a>, b: WriteOnDrop<'a>) {
+    mir!(
+        {
+            DropAndReplace(a, Move(b), retblock)
+        }
+
+        retblock = {
+            Return()
+        }
+    )
+}
+
+// EMIT_MIR terminators.drop_second.built.after.mir
+#[custom_mir(dialect = "built")]
+fn drop_second<'a>(a: WriteOnDrop<'a>, b: WriteOnDrop<'a>) {
+    mir!(
+        {
+            Drop(b, retblock)
+        }
+
+        retblock = {
+            Return()
+        }
+    )
+}
+
+// EMIT_MIR terminators.assert_nonzero.built.after.mir
+#[custom_mir(dialect = "built")]
+fn assert_nonzero(a: i32) {
+    mir!(
+        {
+            match a {
+                0 => unreachable,
+                _ => retblock
+            }
+        }
+
+        unreachable = {
+            Unreachable()
+        }
+
+        retblock = {
+            Return()
+        }
+    )
+}
+
+fn main() {
+    assert_eq!(direct_call(5), 5);
+    assert_eq!(indirect_call(5, ident), 5);
+
+    let mut a = 0;
+    let mut b = 0;
+    drop_first(WriteOnDrop(&mut a, 1), WriteOnDrop(&mut b, 1));
+    assert_eq!((a, b), (1, 0));
+
+    let mut a = 0;
+    let mut b = 0;
+    drop_second(WriteOnDrop(&mut a, 1), WriteOnDrop(&mut b, 1));
+    assert_eq!((a, b), (0, 1));
+}
index 624376769b70f07143a889a388522b2967141357..44445731e72090a365113c15b0fac97251217604 100644 (file)
@@ -12,7 +12,6 @@
       let mut _7: usize;                   // in scope 0 at $DIR/slice_len.rs:+1:5: +1:33
       let mut _8: bool;                    // in scope 0 at $DIR/slice_len.rs:+1:5: +1:33
       let mut _9: &[u32; 3];               // in scope 0 at $DIR/slice_len.rs:+1:6: +1:19
-      let mut _10: &[u32; 3];              // in scope 0 at $DIR/slice_len.rs:+1:6: +1:19
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
                                            // + literal: Const { ty: &[u32; 3], val: Unevaluated(main, [], Some(promoted[0])) }
           _4 = _9;                         // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
           _3 = _4;                         // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
-          StorageLive(_10);                // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
-          _10 = _3;                        // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
           _2 = move _3 as &[u32] (Pointer(Unsize)); // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
           StorageDead(_3);                 // scope 0 at $DIR/slice_len.rs:+1:18: +1:19
           StorageLive(_6);                 // scope 0 at $DIR/slice_len.rs:+1:31: +1:32
           _6 = const 1_usize;              // scope 0 at $DIR/slice_len.rs:+1:31: +1:32
-          _7 = const 3_usize;              // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
-          StorageDead(_10);                // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
+-         _7 = Len((*_2));                 // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
 -         _8 = Lt(_6, _7);                 // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
 -         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
++         _7 = const 3_usize;              // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
 +         _8 = const true;                 // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
 +         assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> bb1; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
       }
index 624376769b70f07143a889a388522b2967141357..44445731e72090a365113c15b0fac97251217604 100644 (file)
@@ -12,7 +12,6 @@
       let mut _7: usize;                   // in scope 0 at $DIR/slice_len.rs:+1:5: +1:33
       let mut _8: bool;                    // in scope 0 at $DIR/slice_len.rs:+1:5: +1:33
       let mut _9: &[u32; 3];               // in scope 0 at $DIR/slice_len.rs:+1:6: +1:19
-      let mut _10: &[u32; 3];              // in scope 0 at $DIR/slice_len.rs:+1:6: +1:19
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
                                            // + literal: Const { ty: &[u32; 3], val: Unevaluated(main, [], Some(promoted[0])) }
           _4 = _9;                         // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
           _3 = _4;                         // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
-          StorageLive(_10);                // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
-          _10 = _3;                        // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
           _2 = move _3 as &[u32] (Pointer(Unsize)); // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
           StorageDead(_3);                 // scope 0 at $DIR/slice_len.rs:+1:18: +1:19
           StorageLive(_6);                 // scope 0 at $DIR/slice_len.rs:+1:31: +1:32
           _6 = const 1_usize;              // scope 0 at $DIR/slice_len.rs:+1:31: +1:32
-          _7 = const 3_usize;              // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
-          StorageDead(_10);                // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
+-         _7 = Len((*_2));                 // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
 -         _8 = Lt(_6, _7);                 // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
 -         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
++         _7 = const 3_usize;              // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
 +         _8 = const true;                 // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
 +         assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> bb1; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
       }
diff --git a/src/test/mir-opt/dest-prop/unreachable.f.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/unreachable.f.DestinationPropagation.diff
new file mode 100644 (file)
index 0000000..9ea756c
--- /dev/null
@@ -0,0 +1,86 @@
+- // MIR for `f` before DestinationPropagation
++ // MIR for `f` after DestinationPropagation
+  
+  fn f(_1: T) -> () {
+      debug a => _1;                       // in scope 0 at $DIR/unreachable.rs:+0:19: +0:20
+      let mut _0: ();                      // return place in scope 0 at $DIR/unreachable.rs:+0:25: +0:25
+      let _2: T;                           // in scope 0 at $DIR/unreachable.rs:+1:9: +1:10
+      let mut _3: bool;                    // in scope 0 at $DIR/unreachable.rs:+2:8: +2:13
+      let _4: ();                          // in scope 0 at $DIR/unreachable.rs:+3:9: +3:16
+      let mut _5: T;                       // in scope 0 at $DIR/unreachable.rs:+3:11: +3:12
+      let mut _6: T;                       // in scope 0 at $DIR/unreachable.rs:+3:14: +3:15
+      let _7: ();                          // in scope 0 at $DIR/unreachable.rs:+5:9: +5:16
+      let mut _8: T;                       // in scope 0 at $DIR/unreachable.rs:+5:11: +5:12
+      let mut _9: T;                       // in scope 0 at $DIR/unreachable.rs:+5:14: +5:15
+      scope 1 {
+-         debug b => _2;                   // in scope 1 at $DIR/unreachable.rs:+1:9: +1:10
++         debug b => _1;                   // in scope 1 at $DIR/unreachable.rs:+1:9: +1:10
+      }
+  
+      bb0: {
+-         StorageLive(_2);                 // scope 0 at $DIR/unreachable.rs:+1:9: +1:10
+-         _2 = _1;                         // scope 0 at $DIR/unreachable.rs:+1:13: +1:14
++         nop;                             // scope 0 at $DIR/unreachable.rs:+1:9: +1:10
++         nop;                             // scope 0 at $DIR/unreachable.rs:+1:13: +1:14
+          StorageLive(_3);                 // scope 1 at $DIR/unreachable.rs:+2:8: +2:13
+          _3 = const false;                // scope 1 at $DIR/unreachable.rs:+2:8: +2:13
+-         goto -> bb3;                     // scope 1 at $DIR/unreachable.rs:+2:8: +2:13
++         goto -> bb1;                     // scope 1 at $DIR/unreachable.rs:+2:8: +2:13
+      }
+  
+      bb1: {
+-         StorageLive(_4);                 // scope 1 at $DIR/unreachable.rs:+3:9: +3:16
+-         StorageLive(_5);                 // scope 1 at $DIR/unreachable.rs:+3:11: +3:12
+-         _5 = _1;                         // scope 1 at $DIR/unreachable.rs:+3:11: +3:12
+-         StorageLive(_6);                 // scope 1 at $DIR/unreachable.rs:+3:14: +3:15
+-         _6 = _2;                         // scope 1 at $DIR/unreachable.rs:+3:14: +3:15
+-         _4 = g::<T>(move _5, move _6) -> bb2; // scope 1 at $DIR/unreachable.rs:+3:9: +3:16
+-                                          // mir::Constant
+-                                          // + span: $DIR/unreachable.rs:11:9: 11:10
+-                                          // + literal: Const { ty: fn(T, T) {g::<T>}, val: Value(<ZST>) }
+-     }
+- 
+-     bb2: {
+-         StorageDead(_6);                 // scope 1 at $DIR/unreachable.rs:+3:15: +3:16
+-         StorageDead(_5);                 // scope 1 at $DIR/unreachable.rs:+3:15: +3:16
+-         StorageDead(_4);                 // scope 1 at $DIR/unreachable.rs:+3:16: +3:17
+-         _0 = const ();                   // scope 1 at $DIR/unreachable.rs:+2:14: +4:6
+-         goto -> bb5;                     // scope 1 at $DIR/unreachable.rs:+2:5: +6:6
+-     }
+- 
+-     bb3: {
+          StorageLive(_7);                 // scope 1 at $DIR/unreachable.rs:+5:9: +5:16
+-         StorageLive(_8);                 // scope 1 at $DIR/unreachable.rs:+5:11: +5:12
+-         _8 = _2;                         // scope 1 at $DIR/unreachable.rs:+5:11: +5:12
++         nop;                             // scope 1 at $DIR/unreachable.rs:+5:11: +5:12
++         nop;                             // scope 1 at $DIR/unreachable.rs:+5:11: +5:12
+          StorageLive(_9);                 // scope 1 at $DIR/unreachable.rs:+5:14: +5:15
+-         _9 = _2;                         // scope 1 at $DIR/unreachable.rs:+5:14: +5:15
+-         _7 = g::<T>(move _8, move _9) -> bb4; // scope 1 at $DIR/unreachable.rs:+5:9: +5:16
++         _9 = _1;                         // scope 1 at $DIR/unreachable.rs:+5:14: +5:15
++         _7 = g::<T>(move _1, move _9) -> bb2; // scope 1 at $DIR/unreachable.rs:+5:9: +5:16
+                                           // mir::Constant
+                                           // + span: $DIR/unreachable.rs:13:9: 13:10
+                                           // + literal: Const { ty: fn(T, T) {g::<T>}, val: Value(<ZST>) }
+      }
+  
+-     bb4: {
++     bb2: {
+          StorageDead(_9);                 // scope 1 at $DIR/unreachable.rs:+5:15: +5:16
+-         StorageDead(_8);                 // scope 1 at $DIR/unreachable.rs:+5:15: +5:16
++         nop;                             // scope 1 at $DIR/unreachable.rs:+5:15: +5:16
+          StorageDead(_7);                 // scope 1 at $DIR/unreachable.rs:+5:16: +5:17
+          _0 = const ();                   // scope 1 at $DIR/unreachable.rs:+4:12: +6:6
+-         goto -> bb5;                     // scope 1 at $DIR/unreachable.rs:+2:5: +6:6
++         goto -> bb3;                     // scope 1 at $DIR/unreachable.rs:+2:5: +6:6
+      }
+  
+-     bb5: {
++     bb3: {
+          StorageDead(_3);                 // scope 1 at $DIR/unreachable.rs:+6:5: +6:6
+-         StorageDead(_2);                 // scope 0 at $DIR/unreachable.rs:+7:1: +7:2
++         nop;                             // scope 0 at $DIR/unreachable.rs:+7:1: +7:2
+          return;                          // scope 0 at $DIR/unreachable.rs:+7:2: +7:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/dest-prop/unreachable.rs b/src/test/mir-opt/dest-prop/unreachable.rs
new file mode 100644 (file)
index 0000000..32b5def
--- /dev/null
@@ -0,0 +1,18 @@
+// Check that unreachable code is removed after the destination propagation.
+// Regression test for issue #105428.
+//
+// compile-flags: --crate-type=lib -Zmir-opt-level=0
+// compile-flags: -Zmir-enable-passes=+ConstProp,+SimplifyConstCondition-after-const-prop,+DestinationPropagation
+
+// EMIT_MIR unreachable.f.DestinationPropagation.diff
+pub fn f<T: Copy>(a: T) {
+    let b = a;
+    if false {
+        g(a, b);
+    } else {
+        g(b, b);
+    }
+}
+
+#[inline(never)]
+pub fn g<T: Copy>(_: T, _: T) {}
index 2368c021eda574375eb7f87e7212576871e48cef..e97b46f6ecc82b19b29ccddcdd162afb07801192 100644 (file)
@@ -22,7 +22,6 @@
       let mut _20: *const T;               // in scope 0 at $DIR/issue_76432.rs:+3:70: +3:84
       let mut _21: *const T;               // in scope 0 at $DIR/issue_76432.rs:+3:70: +3:84
       let mut _22: !;                      // in scope 0 at $SRC_DIR/core/src/panic.rs:LL:COL
-      let mut _23: &[T; 3];                // in scope 0 at $DIR/issue_76432.rs:+1:19: +1:29
       scope 1 {
           debug v => _2;                   // in scope 1 at $DIR/issue_76432.rs:+1:9: +1:10
           let _13: &T;                     // in scope 1 at $DIR/issue_76432.rs:+3:10: +3:16
           StorageDead(_6);                 // scope 0 at $DIR/issue_76432.rs:+1:28: +1:29
           _4 = &_5;                        // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29
           _3 = _4;                         // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29
-          StorageLive(_23);                // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29
-          _23 = _3;                        // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29
           _2 = move _3 as &[T] (Pointer(Unsize)); // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29
           StorageDead(_3);                 // scope 0 at $DIR/issue_76432.rs:+1:28: +1:29
           StorageDead(_4);                 // scope 0 at $DIR/issue_76432.rs:+1:29: +1:30
           StorageLive(_9);                 // scope 1 at $DIR/issue_76432.rs:+2:5: +5:6
-          _10 = const 3_usize;             // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33
-          StorageDead(_23);                // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33
+          _10 = Len((*_2));                // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33
           _11 = const 3_usize;             // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33
-          _12 = const true;                // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33
-          goto -> bb2;                     // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33
+-         _12 = Eq(move _10, const 3_usize); // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33
+-         switchInt(move _12) -> [0: bb1, otherwise: bb2]; // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33
++         nop;                             // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33
++         switchInt(move _10) -> [3: bb2, otherwise: bb1]; // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33
       }
   
       bb1: {
index 49b35d509f029ee3ae2036e2fee992f399094327..d8e4e521ee6820b91fb3dc9ee41f8f5310bebb71 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -Z mir-opt-level=4
+// compile-flags: -Z mir-opt-level=4 -Zunsound-mir-opts
 
 // EMIT_MIR lower_array_len_e2e.array_bound.PreCodegen.after.mir
 pub fn array_bound<const N: usize>(index: usize, slice: &[u8; N]) -> u8 {
diff --git a/src/test/mir-opt/remove_fake_borrows.match_guard.CleanupNonCodegenStatements.diff b/src/test/mir-opt/remove_fake_borrows.match_guard.CleanupNonCodegenStatements.diff
deleted file mode 100644 (file)
index bb5920b..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-- // MIR for `match_guard` before CleanupNonCodegenStatements
-+ // MIR for `match_guard` after CleanupNonCodegenStatements
-  
-  fn match_guard(_1: Option<&&i32>, _2: bool) -> i32 {
-      debug x => _1;                       // in scope 0 at $DIR/remove_fake_borrows.rs:+0:16: +0:17
-      debug c => _2;                       // in scope 0 at $DIR/remove_fake_borrows.rs:+0:34: +0:35
-      let mut _0: i32;                     // return place in scope 0 at $DIR/remove_fake_borrows.rs:+0:46: +0:49
-      let mut _3: isize;                   // in scope 0 at $DIR/remove_fake_borrows.rs:+2:9: +2:16
-      let mut _4: &std::option::Option<&&i32>; // in scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12
-      let mut _5: &&i32;                   // in scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12
-      let mut _6: &&&i32;                  // in scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12
-      let mut _7: &i32;                    // in scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12
-      let mut _8: bool;                    // in scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21
-  
-      bb0: {
--         FakeRead(ForMatchedPlace(None), _1); // scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12
-+         nop;                             // scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12
-          _3 = discriminant(_1);           // scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12
-          switchInt(move _3) -> [1: bb2, otherwise: bb1]; // scope 0 at $DIR/remove_fake_borrows.rs:+1:5: +1:12
-      }
-  
-      bb1: {
-          _0 = const 1_i32;                // scope 0 at $DIR/remove_fake_borrows.rs:+3:14: +3:15
-          goto -> bb7;                     // scope 0 at $DIR/remove_fake_borrows.rs:+3:14: +3:15
-      }
-  
-      bb2: {
-          switchInt((*(*((_1 as Some).0: &&i32)))) -> [0: bb3, otherwise: bb1]; // scope 0 at $DIR/remove_fake_borrows.rs:+1:5: +1:12
-      }
-  
-      bb3: {
-          goto -> bb4;                     // scope 0 at $DIR/remove_fake_borrows.rs:+2:9: +2:16
-      }
-  
-      bb4: {
--         _4 = &shallow _1;                // scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12
--         _5 = &shallow (*((_1 as Some).0: &&i32)); // scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12
--         _6 = &shallow ((_1 as Some).0: &&i32); // scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12
--         _7 = &shallow (*(*((_1 as Some).0: &&i32))); // scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12
-+         nop;                             // scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12
-+         nop;                             // scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12
-+         nop;                             // scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12
-+         nop;                             // scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12
-          StorageLive(_8);                 // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21
-          _8 = _2;                         // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21
-          switchInt(move _8) -> [0: bb6, otherwise: bb5]; // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21
-      }
-  
-      bb5: {
-          StorageDead(_8);                 // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21
--         FakeRead(ForMatchGuard, _4);     // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21
--         FakeRead(ForMatchGuard, _5);     // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21
--         FakeRead(ForMatchGuard, _6);     // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21
--         FakeRead(ForMatchGuard, _7);     // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21
-+         nop;                             // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21
-+         nop;                             // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21
-+         nop;                             // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21
-+         nop;                             // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21
-          _0 = const 0_i32;                // scope 0 at $DIR/remove_fake_borrows.rs:+2:25: +2:26
-          goto -> bb7;                     // scope 0 at $DIR/remove_fake_borrows.rs:+2:25: +2:26
-      }
-  
-      bb6: {
-          StorageDead(_8);                 // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21
-          goto -> bb1;                     // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21
-      }
-  
-      bb7: {
-          return;                          // scope 0 at $DIR/remove_fake_borrows.rs:+5:2: +5:2
-      }
-  
-      bb8 (cleanup): {
-          resume;                          // scope 0 at $DIR/remove_fake_borrows.rs:+0:1: +5:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/remove_fake_borrows.match_guard.CleanupPostBorrowck.diff b/src/test/mir-opt/remove_fake_borrows.match_guard.CleanupPostBorrowck.diff
new file mode 100644 (file)
index 0000000..0b3da98
--- /dev/null
@@ -0,0 +1,74 @@
+- // MIR for `match_guard` before CleanupPostBorrowck
++ // MIR for `match_guard` after CleanupPostBorrowck
+  
+  fn match_guard(_1: Option<&&i32>, _2: bool) -> i32 {
+      debug x => _1;                       // in scope 0 at $DIR/remove_fake_borrows.rs:+0:16: +0:17
+      debug c => _2;                       // in scope 0 at $DIR/remove_fake_borrows.rs:+0:34: +0:35
+      let mut _0: i32;                     // return place in scope 0 at $DIR/remove_fake_borrows.rs:+0:46: +0:49
+      let mut _3: isize;                   // in scope 0 at $DIR/remove_fake_borrows.rs:+2:9: +2:16
+      let mut _4: &std::option::Option<&&i32>; // in scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12
+      let mut _5: &&i32;                   // in scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12
+      let mut _6: &&&i32;                  // in scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12
+      let mut _7: &i32;                    // in scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12
+      let mut _8: bool;                    // in scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21
+  
+      bb0: {
+-         FakeRead(ForMatchedPlace(None), _1); // scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12
++         nop;                             // scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12
+          _3 = discriminant(_1);           // scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12
+          switchInt(move _3) -> [1: bb2, otherwise: bb1]; // scope 0 at $DIR/remove_fake_borrows.rs:+1:5: +1:12
+      }
+  
+      bb1: {
+          _0 = const 1_i32;                // scope 0 at $DIR/remove_fake_borrows.rs:+3:14: +3:15
+          goto -> bb7;                     // scope 0 at $DIR/remove_fake_borrows.rs:+3:14: +3:15
+      }
+  
+      bb2: {
+          switchInt((*(*((_1 as Some).0: &&i32)))) -> [0: bb3, otherwise: bb1]; // scope 0 at $DIR/remove_fake_borrows.rs:+1:5: +1:12
+      }
+  
+      bb3: {
+-         falseEdge -> [real: bb4, imaginary: bb1]; // scope 0 at $DIR/remove_fake_borrows.rs:+2:9: +2:16
++         goto -> bb4;                     // scope 0 at $DIR/remove_fake_borrows.rs:+2:9: +2:16
+      }
+  
+      bb4: {
+-         _4 = &shallow _1;                // scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12
+-         _5 = &shallow (*((_1 as Some).0: &&i32)); // scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12
+-         _6 = &shallow ((_1 as Some).0: &&i32); // scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12
+-         _7 = &shallow (*(*((_1 as Some).0: &&i32))); // scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12
++         nop;                             // scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12
++         nop;                             // scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12
++         nop;                             // scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12
++         nop;                             // scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12
+          StorageLive(_8);                 // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21
+          _8 = _2;                         // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21
+          switchInt(move _8) -> [0: bb6, otherwise: bb5]; // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21
+      }
+  
+      bb5: {
+          StorageDead(_8);                 // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21
+-         FakeRead(ForMatchGuard, _4);     // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21
+-         FakeRead(ForMatchGuard, _5);     // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21
+-         FakeRead(ForMatchGuard, _6);     // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21
+-         FakeRead(ForMatchGuard, _7);     // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21
++         nop;                             // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21
++         nop;                             // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21
++         nop;                             // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21
++         nop;                             // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21
+          _0 = const 0_i32;                // scope 0 at $DIR/remove_fake_borrows.rs:+2:25: +2:26
+          goto -> bb7;                     // scope 0 at $DIR/remove_fake_borrows.rs:+2:25: +2:26
+      }
+  
+      bb6: {
+          StorageDead(_8);                 // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21
+-         falseEdge -> [real: bb1, imaginary: bb1]; // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21
++         goto -> bb1;                     // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21
+      }
+  
+      bb7: {
+          return;                          // scope 0 at $DIR/remove_fake_borrows.rs:+5:2: +5:2
+      }
+  }
+  
index a980f386b69633dbdbb431d6adfd2ab772d07d34..d26c6f5d7e51bff1a9b462e1bc392892cfbe92df 100644 (file)
@@ -2,7 +2,7 @@
 
 // ignore-wasm32-bare compiled with panic=abort by default
 
-// EMIT_MIR remove_fake_borrows.match_guard.CleanupNonCodegenStatements.diff
+// EMIT_MIR remove_fake_borrows.match_guard.CleanupPostBorrowck.diff
 fn match_guard(x: Option<&&i32>, c: bool) -> i32 {
     match x {
         Some(0) if c => 0,
index d083aaa662005a62e9cfc370ef32f8134c8614de..ec05ebea55582f22894bc7d7e63103e3c1495b4d 100644 (file)
@@ -1,4 +1,4 @@
 include ../tools.mk
 
 all:
-       $(RUSTC) --edition=2021 --crate-type=rlib ../../../../library/core/src/lib.rs --cfg no_fp_fmt_parse
+       $(RUSTC) --edition=2021 -Dwarnings --crate-type=rlib ../../../../library/core/src/lib.rs --cfg no_fp_fmt_parse
index 00a0ea1e1a27ca578ec6cab5838bc5e881ca1940..df665bd46c03b7f5cf053afa41c25d94741935e0 100644 (file)
@@ -1,7 +1,7 @@
 // This test checks that the source code pages sidebar toggle is working as expected.
 goto: "file://" + |DOC_PATH| + "/test_docs/index.html"
 click: ".srclink"
-wait-for: "#sidebar-toggle"
-click: "#sidebar-toggle"
+wait-for: "#src-sidebar-toggle"
+click: "#src-sidebar-toggle"
 fail: true
 assert-css: ("#source-sidebar", { "left": "-300px" })
diff --git a/src/test/rustdoc-gui/codeblock-sub.goml b/src/test/rustdoc-gui/codeblock-sub.goml
new file mode 100644 (file)
index 0000000..cbd314d
--- /dev/null
@@ -0,0 +1,5 @@
+// Test that code blocks nested within <sub> do not have a line height of 0.
+goto: "file://" + |DOC_PATH| + "/test_docs/codeblock_sub/index.html"
+
+store-property: (codeblock_sub_1, "#codeblock-sub-1", "offsetHeight")
+assert-property-false: ("#codeblock-sub-3", { "offsetHeight": |codeblock_sub_1| })
index 4d923be3e786446d12ee8879581cf1d98bdb13fc..aab27394eb1f3b1b50d5ec902aa6a42ae61353eb 100644 (file)
@@ -20,7 +20,7 @@ define-function: (
             {"border-left": "2px solid rgba(255, 0, 0, 0.5)"},
         )),
 
-        ("move-cursor-to", ".docblock .example-wrap.compile_fail"),
+        ("move-cursor-to", ".docblock .example-wrap.compile_fail .tooltip"),
 
         ("assert-css", (
             ".docblock .example-wrap.compile_fail .tooltip",
@@ -60,7 +60,7 @@ define-function: (
             {"border-left": "2px solid rgba(255, 0, 0, 0.5)"},
         )),
 
-        ("move-cursor-to", ".docblock .example-wrap.should_panic"),
+        ("move-cursor-to", ".docblock .example-wrap.should_panic .tooltip"),
 
         ("assert-css", (
             ".docblock .example-wrap.should_panic .tooltip",
@@ -100,7 +100,7 @@ define-function: (
             {"border-left": "2px solid rgba(255, 142, 0, 0.6)"},
         )),
 
-        ("move-cursor-to", ".docblock .example-wrap.ignore"),
+        ("move-cursor-to", ".docblock .example-wrap.ignore .tooltip"),
 
         ("assert-css", (
             ".docblock .example-wrap.ignore .tooltip",
index b2e91cb81fba7495b9e79a1a67204f28263796c9..cb6716a76f5c0d6ae17511dfcd2617ee0d75d398 100644 (file)
@@ -21,4 +21,4 @@ assert-css: (".sidebar-menu-toggle", {"cursor": "pointer"})
 
 // the sidebar toggle button on the source code pages
 goto: "file://" + |DOC_PATH| + "/src/lib2/lib.rs.html"
-assert-css: ("#sidebar-toggle > button", {"cursor": "pointer"})
+assert-css: ("#src-sidebar-toggle > button", {"cursor": "pointer"})
diff --git a/src/test/rustdoc-gui/scrape-examples-layout.goml b/src/test/rustdoc-gui/scrape-examples-layout.goml
new file mode 100644 (file)
index 0000000..988c911
--- /dev/null
@@ -0,0 +1,35 @@
+// Check that the line number column has the correct layout.
+goto: "file://" + |DOC_PATH| + "/scrape_examples/fn.test_many.html"
+
+// Check that it's not zero.
+assert-property-false: (
+    ".more-scraped-examples .scraped-example .code-wrapper .src-line-numbers",
+    {"clientWidth": "0"}
+)
+
+// Check that examples with very long lines have the same width as ones that don't.
+store-property: (
+    clientWidth,
+    ".more-scraped-examples .scraped-example:nth-child(1) .code-wrapper .src-line-numbers",
+    "clientWidth"
+)
+
+assert-property: (
+    ".more-scraped-examples .scraped-example:nth-child(2) .code-wrapper .src-line-numbers",
+    {"clientWidth": |clientWidth|}
+)
+
+assert-property: (
+    ".more-scraped-examples .scraped-example:nth-child(3) .code-wrapper .src-line-numbers",
+    {"clientWidth": |clientWidth|}
+)
+
+assert-property: (
+    ".more-scraped-examples .scraped-example:nth-child(4) .code-wrapper .src-line-numbers",
+    {"clientWidth": |clientWidth|}
+)
+
+assert-property: (
+    ".more-scraped-examples .scraped-example:nth-child(5) .code-wrapper .src-line-numbers",
+    {"clientWidth": |clientWidth|}
+)
index 40ae4af81be45329419f13e007cdf1559d39f178..df4506e1119648a7c76f379170da131cab39d51f 100644 (file)
@@ -2,18 +2,18 @@
 javascript: false
 goto: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html"
 // Since the javascript is disabled, there shouldn't be a toggle.
-assert-false: "#sidebar-toggle"
+assert-false: "#src-sidebar-toggle"
 wait-for-css: (".sidebar", {"display": "none"})
 
 // Let's retry with javascript enabled.
 javascript: true
 reload:
-wait-for: "#sidebar-toggle"
-assert-css: ("#sidebar-toggle", {"visibility": "visible"})
-assert-css: (".sidebar > *:not(#sidebar-toggle)", {"visibility": "hidden"})
+wait-for: "#src-sidebar-toggle"
+assert-css: ("#src-sidebar-toggle", {"visibility": "visible"})
+assert-css: (".sidebar > *:not(#src-sidebar-toggle)", {"visibility": "hidden"})
 // Let's expand the sidebar now.
-click: "#sidebar-toggle"
-wait-for-css: ("#sidebar-toggle", {"visibility": "visible"})
+click: "#src-sidebar-toggle"
+wait-for-css: ("#src-sidebar-toggle", {"visibility": "visible"})
 
 // We now check that opening the sidebar and clicking a link will leave it open.
 // The behavior here on desktop is different than the behavior on mobile,
@@ -38,25 +38,25 @@ define-function: (
     [
         ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
         ("reload"),
-        ("wait-for-css", ("#sidebar-toggle", {"visibility": "visible"})),
+        ("wait-for-css", ("#src-sidebar-toggle", {"visibility": "visible"})),
         ("assert-css", (
             "#source-sidebar details[open] > .files a.selected",
             {"color": |color_hover|, "background-color": |background|},
         )),
 
         // Without hover or focus.
-        ("assert-css", ("#sidebar-toggle > button", {"background-color": |background_toggle|})),
+        ("assert-css", ("#src-sidebar-toggle > button", {"background-color": |background_toggle|})),
         // With focus.
-        ("focus", "#sidebar-toggle > button"),
+        ("focus", "#src-sidebar-toggle > button"),
         ("assert-css", (
-            "#sidebar-toggle > button:focus",
+            "#src-sidebar-toggle > button:focus",
             {"background-color": |background_toggle_hover|},
         )),
         ("focus", ".search-input"),
         // With hover.
-        ("move-cursor-to", "#sidebar-toggle > button"),
+        ("move-cursor-to", "#src-sidebar-toggle > button"),
         ("assert-css", (
-            "#sidebar-toggle > button:hover",
+            "#src-sidebar-toggle > button:hover",
             {"background-color": |background_toggle_hover|},
         )),
 
@@ -151,16 +151,16 @@ call-function: ("check-colors", {
 size: (500, 700)
 reload:
 // Waiting for the sidebar to be displayed...
-wait-for-css: ("#sidebar-toggle", {"visibility": "visible"})
+wait-for-css: ("#src-sidebar-toggle", {"visibility": "visible"})
 
 // We now check it takes the full size of the display.
 assert-property: ("body", {"clientWidth": "500", "clientHeight": "700"})
 assert-property: (".sidebar", {"clientWidth": "500", "clientHeight": "700"})
 
 // We now check the display of the toggle once the sidebar is expanded.
-assert-property: ("#sidebar-toggle", {"clientWidth": "500", "clientHeight": "39"})
+assert-property: ("#src-sidebar-toggle", {"clientWidth": "500", "clientHeight": "39"})
 assert-css: (
-    "#sidebar-toggle",
+    "#src-sidebar-toggle",
     {
         "border-top-width": "0px",
         "border-right-width": "0px",
@@ -170,28 +170,28 @@ assert-css: (
 )
 
 // We now check that the scroll position is kept when opening the sidebar.
-click: "#sidebar-toggle"
+click: "#src-sidebar-toggle"
 wait-for-css: (".sidebar", {"width": "0px"})
 // We scroll to line 117 to change the scroll position.
 scroll-to: '//*[@id="117"]'
 assert-window-property: {"pageYOffset": "2542"}
 // Expanding the sidebar...
-click: "#sidebar-toggle"
+click: "#src-sidebar-toggle"
 wait-for-css: (".sidebar", {"width": "500px"})
-click: "#sidebar-toggle"
+click: "#src-sidebar-toggle"
 wait-for-css: (".sidebar", {"width": "0px"})
 // The "scrollTop" property should be the same.
 assert-window-property: {"pageYOffset": "2542"}
 
 // We now check that the scroll position is restored if the window is resized.
 size: (500, 700)
-click: "#sidebar-toggle"
+click: "#src-sidebar-toggle"
 wait-for-css: ("#source-sidebar", {"visibility": "visible"})
 assert-window-property: {"pageYOffset": "0"}
 size: (900, 900)
 assert-window-property: {"pageYOffset": "2542"}
 size: (500, 700)
-click: "#sidebar-toggle"
+click: "#src-sidebar-toggle"
 wait-for-css: ("#source-sidebar", {"visibility": "hidden"})
 
 // We now check that opening the sidebar and clicking a link will close it.
@@ -199,7 +199,7 @@ wait-for-css: ("#source-sidebar", {"visibility": "hidden"})
 // but common sense dictates that if you have a list of files that fills the entire screen, and
 // you click one of them, you probably want to actually see the file's contents, and not just
 // make it the current selection.
-click: "#sidebar-toggle"
+click: "#src-sidebar-toggle"
 wait-for-css: ("#source-sidebar", {"visibility": "visible"})
 assert-local-storage: {"rustdoc-source-sidebar-show": "true"}
 click: ".sidebar a.selected"
@@ -210,6 +210,6 @@ assert-local-storage: {"rustdoc-source-sidebar-show": "false"}
 size: (1000, 1000)
 wait-for-css: ("#source-sidebar", {"visibility": "hidden"})
 assert-local-storage: {"rustdoc-source-sidebar-show": "false"}
-click: "#sidebar-toggle"
+click: "#src-sidebar-toggle"
 wait-for-css: ("#source-sidebar", {"visibility": "visible"})
 assert-local-storage: {"rustdoc-source-sidebar-show": "true"}
index b3b837ad377c80bb74e8b2a7e81a181e8bb44fa0..25da74e5173eba34e77995a5e0ee083e010a8d24 100644 (file)
@@ -97,7 +97,7 @@ assert-document-property: ({"URL": "/lib.rs.html"}, ENDS_WITH)
 // Checking the source code sidebar.
 
 // First we "open" it.
-click: "#sidebar-toggle"
+click: "#src-sidebar-toggle"
 assert: ".source-sidebar-expanded"
 
 // We check that the first entry of the sidebar is collapsed
index 1d1bc5002aa8f46deea1383390b528faa261557e..81a48ac50c8139fc6f2f0952e1a7c501a7a9868a 100644 (file)
@@ -1,3 +1,13 @@
 fn main() {
+    // all examples have same line count
+    scrape_examples::test_many();
+    scrape_examples::test_many();
+    scrape_examples::test_many();
+    scrape_examples::test_many();
+    scrape_examples::test_many();
+    scrape_examples::test_many();
+    scrape_examples::test_many();
+    scrape_examples::test_many();
+    scrape_examples::test_many();
     scrape_examples::test_many();
 }
index 1d1bc5002aa8f46deea1383390b528faa261557e..c9fdf68d3be0c214bd89958672f5a545ba904dc6 100644 (file)
@@ -1,3 +1,13 @@
 fn main() {
-    scrape_examples::test_many();
+    // ignore-tidy-linelength
+    scrape_examples::test_many(); /* Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. */
+    scrape_examples::test_many(); /* Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. */
+    scrape_examples::test_many(); /* Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. */
+    scrape_examples::test_many(); /* Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. */
+    scrape_examples::test_many(); /* Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. */
+    scrape_examples::test_many(); /* Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. */
+    scrape_examples::test_many(); /* Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. */
+    scrape_examples::test_many(); /* Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. */
+    scrape_examples::test_many(); /* Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. */
+    scrape_examples::test_many(); /* Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. */
 }
index 1d1bc5002aa8f46deea1383390b528faa261557e..c9fdf68d3be0c214bd89958672f5a545ba904dc6 100644 (file)
@@ -1,3 +1,13 @@
 fn main() {
-    scrape_examples::test_many();
+    // ignore-tidy-linelength
+    scrape_examples::test_many(); /* Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. */
+    scrape_examples::test_many(); /* Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. */
+    scrape_examples::test_many(); /* Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. */
+    scrape_examples::test_many(); /* Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. */
+    scrape_examples::test_many(); /* Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. */
+    scrape_examples::test_many(); /* Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. */
+    scrape_examples::test_many(); /* Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. */
+    scrape_examples::test_many(); /* Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. */
+    scrape_examples::test_many(); /* Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. */
+    scrape_examples::test_many(); /* Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. */
 }
index 1d1bc5002aa8f46deea1383390b528faa261557e..81a48ac50c8139fc6f2f0952e1a7c501a7a9868a 100644 (file)
@@ -1,3 +1,13 @@
 fn main() {
+    // all examples have same line count
+    scrape_examples::test_many();
+    scrape_examples::test_many();
+    scrape_examples::test_many();
+    scrape_examples::test_many();
+    scrape_examples::test_many();
+    scrape_examples::test_many();
+    scrape_examples::test_many();
+    scrape_examples::test_many();
+    scrape_examples::test_many();
     scrape_examples::test_many();
 }
index 1d1bc5002aa8f46deea1383390b528faa261557e..81a48ac50c8139fc6f2f0952e1a7c501a7a9868a 100644 (file)
@@ -1,3 +1,13 @@
 fn main() {
+    // all examples have same line count
+    scrape_examples::test_many();
+    scrape_examples::test_many();
+    scrape_examples::test_many();
+    scrape_examples::test_many();
+    scrape_examples::test_many();
+    scrape_examples::test_many();
+    scrape_examples::test_many();
+    scrape_examples::test_many();
+    scrape_examples::test_many();
     scrape_examples::test_many();
 }
index 1d1bc5002aa8f46deea1383390b528faa261557e..81a48ac50c8139fc6f2f0952e1a7c501a7a9868a 100644 (file)
@@ -1,3 +1,13 @@
 fn main() {
+    // all examples have same line count
+    scrape_examples::test_many();
+    scrape_examples::test_many();
+    scrape_examples::test_many();
+    scrape_examples::test_many();
+    scrape_examples::test_many();
+    scrape_examples::test_many();
+    scrape_examples::test_many();
+    scrape_examples::test_many();
+    scrape_examples::test_many();
     scrape_examples::test_many();
 }
index 1d1bc5002aa8f46deea1383390b528faa261557e..81a48ac50c8139fc6f2f0952e1a7c501a7a9868a 100644 (file)
@@ -1,3 +1,13 @@
 fn main() {
+    // all examples have same line count
+    scrape_examples::test_many();
+    scrape_examples::test_many();
+    scrape_examples::test_many();
+    scrape_examples::test_many();
+    scrape_examples::test_many();
+    scrape_examples::test_many();
+    scrape_examples::test_many();
+    scrape_examples::test_many();
+    scrape_examples::test_many();
     scrape_examples::test_many();
 }
index f1b69d4dc1d40ba174e47ff29422f24033ce7279..51250439694b054d85f3c85110ac67ac3692a5da 100644 (file)
@@ -455,3 +455,22 @@ impl TypeWithImplDoc {
     /// fn doc
     pub fn test_fn() {}
 }
+
+/// <sub id="codeblock-sub-1">
+///
+/// ```
+/// one
+/// ```
+///
+/// </sub>
+///
+/// <sub id="codeblock-sub-3">
+///
+/// ```
+/// one
+/// two
+/// three
+/// ```
+///
+/// </sub>
+pub mod codeblock_sub {}
index 3ec60b58cfde82ffd8861e3a9014c759f7a6e5e5..fa3e16cb81ef8240675de6416be3e2007131a935 100644 (file)
@@ -1,5 +1,5 @@
+// This test ensures that each field is on its own line (In other words, they have display: block).
 goto: "file://" + |DOC_PATH| + "/test_docs/struct.StructWithPublicUndocumentedFields.html"
 
-// Both fields must be on their own line. In other words, they have display: block.
 store-property: (first_top, "//*[@id='structfield.first']", "offsetTop")
 assert-property-false: ("//*[@id='structfield.second']", { "offsetTop": |first_top| })
index 94cf7b94241df8d79144969b852f538de8ccfa88..53677b18377098bbf77089472e3a1d8513528c21 100644 (file)
@@ -35,6 +35,7 @@
     -Z            dump-mir-exclude-pass-number=val -- exclude the pass number when dumping MIR (used in tests) (default: no)
     -Z                       dump-mir-graphviz=val -- in addition to `.mir` files, create graphviz `.dot` files (and with `-Z instrument-coverage`, also create a `.dot` file for the MIR-derived coverage graph) (default: no)
     -Z                       dump-mir-spanview=val -- in addition to `.mir` files, create `.html` files to view spans for all `statement`s (including terminators), only `terminator` spans, or computed `block` spans (one span encompassing a block's terminator and all statements). If `-Z instrument-coverage` is also enabled, create an additional `.html` file showing the computed coverage spans.
+    -Z                         dump-mono-stats=val -- output statistics about monomorphization collection (format: markdown)
     -Z                           dwarf-version=val -- version of DWARF debug information to emit (default: 2 or 4, depending on platform)
     -Z                               dylib-lto=val -- enables LTO for dylib crate type
     -Z                        emit-stack-sizes=val -- emit a section containing stack size metadata (default: no)
@@ -91,6 +92,7 @@
     -Z                             no-analysis=val -- parse and expand the source, but run no analysis
     -Z                              no-codegen=val -- run all passes except codegen; no output
     -Z              no-generate-arange-section=val -- omit DWARF address ranges that give faster lookups
+    -Z                          no-jump-tables=val -- disable the jump tables and lookup tables that can be generated from a switch case lowering
     -Z                           no-leak-check=val -- disable the 'leak check' for subtyping; unsound, but useful for tests
     -Z                                 no-link=val -- compile without linking
     -Z                        no-parallel-llvm=val -- run LLVM in non-parallel mode (while keeping codegen-units and ThinLTO)
diff --git a/src/test/rustdoc/read-more-unneeded.rs b/src/test/rustdoc/read-more-unneeded.rs
new file mode 100644 (file)
index 0000000..0303e44
--- /dev/null
@@ -0,0 +1,34 @@
+// Regression test for https://github.com/rust-lang/rust/issues/105677.
+// This test ensures that the "Read more" link is only generated when
+// there is actually more documentation to read after the short summary.
+
+#![crate_name = "foo"]
+
+pub trait MyFrom {
+    /// # Hello
+    /// ## Yolo
+    /// more!
+    fn try_from1();
+    /// a
+    /// b
+    /// c
+    fn try_from2();
+    /// a
+    ///
+    /// b
+    ///
+    /// c
+    fn try_from3();
+}
+
+pub struct NonZero;
+
+// @has 'foo/struct.NonZero.html'
+impl MyFrom for NonZero {
+    // @matches - '//*[@class="docblock"]' '^Hello Read more$'
+    fn try_from1() {}
+    // @matches - '//*[@class="docblock"]' '^a\sb\sc$'
+    fn try_from2() {}
+    // @matches - '//*[@class="docblock"]' '^a Read more$'
+    fn try_from3() {}
+}
index 195cdf009b9937f37d355f15702347a69942fe7b..9cf3226f738c804da6357ecf5e058eee0e568280 100644 (file)
@@ -30,8 +30,6 @@ fn a() {}
     // @has - '//*[@id="method.b"]/../../div[@class="docblock"]' 'These docs contain'
     // @has - '//*[@id="method.b"]/../../div[@class="docblock"]/a' 'reference link'
     // @has - '//*[@id="method.b"]/../../div[@class="docblock"]/a/@href' 'https://example.com'
-    // @has - '//*[@id="method.b"]/../../div[@class="docblock"]/a' 'Read more'
-    // @has - '//*[@id="method.b"]/../../div[@class="docblock"]/a/@href' 'trait.Trait.html#tymethod.b'
     fn b() {}
 
     // @!has - '//*[@id="method.c"]/../../div[@class="docblock"]' 'code block'
index 7b31f28a26e7d3555411b265c23af8d0fd6fb50c..9c2b992b7655849d0096cc789b83ef1d2d3c2296 100644 (file)
@@ -6,3 +6,4 @@ LL | #![plugin(rlib_crate_test)]
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0457`.
index 851da231a73441708317aabc4c681f92e967f2dc..28926243390932390a6873f0c85fea9b707e6493 100644 (file)
@@ -7,9 +7,10 @@
 // compile-flags:-C panic=abort
 // aux-build:helper.rs
 
-#![feature(start, rustc_private, new_uninit, panic_info_message, lang_items)]
+#![feature(rustc_private, lang_items)]
 #![feature(alloc_error_handler)]
 #![no_std]
+#![no_main]
 
 extern crate alloc;
 extern crate libc;
@@ -21,35 +22,30 @@ pub fn __aeabi_unwind_cpp_pr0() {}
 #[no_mangle]
 pub fn __aeabi_unwind_cpp_pr1() {}
 
-use core::ptr::null_mut;
-use core::alloc::{GlobalAlloc, Layout};
 use alloc::boxed::Box;
+use alloc::string::ToString;
+use core::alloc::{GlobalAlloc, Layout};
+use core::ptr::null_mut;
 
 extern crate helper;
 
 struct MyAllocator;
 
 #[alloc_error_handler]
-fn my_oom(layout: Layout) -> !
-{
+fn my_oom(layout: Layout) -> ! {
     use alloc::fmt::write;
     unsafe {
         let size = layout.size();
         let mut s = alloc::string::String::new();
         write(&mut s, format_args!("My OOM: failed to allocate {} bytes!\n", size)).unwrap();
-        let s = s.as_str();
-        libc::write(libc::STDERR_FILENO, s as *const _ as _, s.len());
+        libc::write(libc::STDERR_FILENO, s.as_ptr() as *const _, s.len());
         libc::exit(0)
     }
 }
 
 unsafe impl GlobalAlloc for MyAllocator {
     unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
-        if layout.size() < 4096 {
-            libc::malloc(layout.size()) as _
-        } else {
-            null_mut()
-        }
+        if layout.size() < 4096 { libc::malloc(layout.size()) as _ } else { null_mut() }
     }
     unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
 }
@@ -60,26 +56,12 @@ unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
 #[panic_handler]
 fn panic(panic_info: &core::panic::PanicInfo) -> ! {
     unsafe {
-        if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
-            const PSTR: &str = "panic occurred: ";
-            const CR: &str = "\n";
-            libc::write(libc::STDERR_FILENO, PSTR as *const _ as _, PSTR.len());
-            libc::write(libc::STDERR_FILENO, s as *const _ as _, s.len());
-            libc::write(libc::STDERR_FILENO, CR as *const _ as _, CR.len());
-        }
-        if let Some(args) = panic_info.message() {
-            let mut s = alloc::string::String::new();
-            alloc::fmt::write(&mut s, *args).unwrap();
-            let s = s.as_str();
-            const PSTR: &str = "panic occurred: ";
-            const CR: &str = "\n";
-            libc::write(libc::STDERR_FILENO, PSTR as *const _ as _, PSTR.len());
-            libc::write(libc::STDERR_FILENO, s as *const _ as _, s.len());
-            libc::write(libc::STDERR_FILENO, CR as *const _ as _, CR.len());
-        } else {
-            const PSTR: &str = "panic occurred\n";
-            libc::write(libc::STDERR_FILENO, PSTR as *const _ as _, PSTR.len());
-        }
+        let s = panic_info.to_string();
+        const PSTR: &str = "panic occurred: ";
+        const CR: &str = "\n";
+        libc::write(libc::STDERR_FILENO, PSTR.as_ptr() as *const _, PSTR.len());
+        libc::write(libc::STDERR_FILENO, s.as_ptr() as *const _, s.len());
+        libc::write(libc::STDERR_FILENO, CR.as_ptr() as *const _, CR.len());
         libc::exit(1)
     }
 }
@@ -89,15 +71,14 @@ fn panic(panic_info: &core::panic::PanicInfo) -> ! {
 // in these libraries will refer to `rust_eh_personality` if LLVM can not *prove* the contents won't
 // unwind. So, for this test case we will define the symbol.
 #[lang = "eh_personality"]
-extern fn rust_eh_personality() {}
+extern "C" fn rust_eh_personality() {}
 
-#[derive(Debug)]
+#[derive(Default, Debug)]
 struct Page(#[allow(unused_tuple_struct_fields)] [[u64; 32]; 16]);
 
-#[start]
-pub fn main(_argc: isize, _argv: *const *const u8) -> isize {
-    let zero = Box::<Page>::new_zeroed();
-    let zero = unsafe { zero.assume_init() };
+#[no_mangle]
+fn main(_argc: i32, _argv: *const *const u8) -> isize {
+    let zero = Box::<Page>::new(Default::default());
     helper::work_with(&zero);
     1
 }
index 30ce0f162c7ac55d21b1e362078abbee6f8c22dd..56409e71339148d845199c63a58bf0d601db5a1d 100644 (file)
@@ -6,11 +6,10 @@
 // only-linux
 // compile-flags:-C panic=abort
 // aux-build:helper.rs
-// gate-test-default_alloc_error_handler
 
-#![feature(start, rustc_private, new_uninit, panic_info_message, lang_items)]
-#![feature(default_alloc_error_handler)]
+#![feature(rustc_private, lang_items)]
 #![no_std]
+#![no_main]
 
 extern crate alloc;
 extern crate libc;
@@ -23,6 +22,7 @@ pub fn __aeabi_unwind_cpp_pr0() {}
 pub fn __aeabi_unwind_cpp_pr1() {}
 
 use alloc::boxed::Box;
+use alloc::string::ToString;
 use core::alloc::{GlobalAlloc, Layout};
 use core::ptr::null_mut;
 
@@ -32,11 +32,7 @@ pub fn __aeabi_unwind_cpp_pr1() {}
 
 unsafe impl GlobalAlloc for MyAllocator {
     unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
-        if layout.size() < 4096 {
-            libc::malloc(layout.size()) as _
-        } else {
-            null_mut()
-        }
+        if layout.size() < 4096 { libc::malloc(layout.size()) as _ } else { null_mut() }
     }
     unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
 }
@@ -47,26 +43,12 @@ unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
 #[panic_handler]
 fn panic(panic_info: &core::panic::PanicInfo) -> ! {
     unsafe {
-        if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
-            const PSTR: &str = "panic occurred: ";
-            const CR: &str = "\n";
-            libc::write(libc::STDERR_FILENO, PSTR as *const _ as _, PSTR.len());
-            libc::write(libc::STDERR_FILENO, s as *const _ as _, s.len());
-            libc::write(libc::STDERR_FILENO, CR as *const _ as _, CR.len());
-        }
-        if let Some(args) = panic_info.message() {
-            let mut s = alloc::string::String::new();
-            alloc::fmt::write(&mut s, *args).unwrap();
-            let s = s.as_str();
-            const PSTR: &str = "panic occurred: ";
-            const CR: &str = "\n";
-            libc::write(libc::STDERR_FILENO, PSTR as *const _ as _, PSTR.len());
-            libc::write(libc::STDERR_FILENO, s as *const _ as _, s.len());
-            libc::write(libc::STDERR_FILENO, CR as *const _ as _, CR.len());
-        } else {
-            const PSTR: &str = "panic occurred\n";
-            libc::write(libc::STDERR_FILENO, PSTR as *const _ as _, PSTR.len());
-        }
+        let s = panic_info.to_string();
+        const PSTR: &str = "panic occurred: ";
+        const CR: &str = "\n";
+        libc::write(libc::STDERR_FILENO, PSTR.as_ptr() as *const _, PSTR.len());
+        libc::write(libc::STDERR_FILENO, s.as_ptr() as *const _, s.len());
+        libc::write(libc::STDERR_FILENO, CR.as_ptr() as *const _, CR.len());
         libc::exit(0)
     }
 }
@@ -76,15 +58,14 @@ fn panic(panic_info: &core::panic::PanicInfo) -> ! {
 // in these libraries will refer to `rust_eh_personality` if LLVM can not *prove* the contents won't
 // unwind. So, for this test case we will define the symbol.
 #[lang = "eh_personality"]
-extern fn rust_eh_personality() {}
+extern "C" fn rust_eh_personality() {}
 
-#[derive(Debug)]
+#[derive(Default, Debug)]
 struct Page(#[allow(unused_tuple_struct_fields)] [[u64; 32]; 16]);
 
-#[start]
-pub fn main(_argc: isize, _argv: *const *const u8) -> isize {
-    let zero = Box::<Page>::new_zeroed();
-    let zero = unsafe { zero.assume_init() };
+#[no_mangle]
+fn main(_argc: i32, _argv: *const *const u8) -> isize {
+    let zero = Box::<Page>::new(Default::default());
     helper::work_with(&zero);
     1
 }
index b118ce1bd0ea95e433aa1a4e7824b87d0a632bb5..062b3768858dda362aa894cc03428c42b283e495 100644 (file)
@@ -94,8 +94,8 @@ LL |     let closure = |x| x;
    |                   ^^^
 help: provide the argument
    |
-LL |     closure(/* value */);
-   |            ~~~~~~~~~~~~~
+LL |     closure(/* x */);
+   |            ~~~~~~~~~
 
 error: aborting due to 6 previous errors
 
index 4aa27180758e28f5473152941f0f4988cbde1652..d7af296152f7904fe13c9c316f2c00223746864e 100644 (file)
@@ -14,3 +14,4 @@ LL | global_asm!("");
 
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0472`.
index 4aa27180758e28f5473152941f0f4988cbde1652..d7af296152f7904fe13c9c316f2c00223746864e 100644 (file)
@@ -14,3 +14,4 @@ LL | global_asm!("");
 
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0472`.
diff --git a/src/test/ui/associated-inherent-types/style.rs b/src/test/ui/associated-inherent-types/style.rs
new file mode 100644 (file)
index 0000000..8775bd1
--- /dev/null
@@ -0,0 +1,12 @@
+#![feature(inherent_associated_types)]
+#![allow(incomplete_features, dead_code)]
+#![deny(non_camel_case_types)]
+
+struct S;
+
+impl S {
+    type typ = ();
+    //~^ ERROR associated type `typ` should have an upper camel case name
+}
+
+fn main() {}
diff --git a/src/test/ui/associated-inherent-types/style.stderr b/src/test/ui/associated-inherent-types/style.stderr
new file mode 100644 (file)
index 0000000..f83061f
--- /dev/null
@@ -0,0 +1,14 @@
+error: associated type `typ` should have an upper camel case name
+  --> $DIR/style.rs:8:10
+   |
+LL |     type typ = ();
+   |          ^^^ help: convert the identifier to upper camel case: `Typ`
+   |
+note: the lint level is defined here
+  --> $DIR/style.rs:3:9
+   |
+LL | #![deny(non_camel_case_types)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
index 26b9f4b3a92660ea78b923adb3884545ea4eb81a..fed60ccf089d05c85288a7ef3774506f7d2dbd96 100644 (file)
@@ -4,5 +4,5 @@
 
 fn main() {
     let _: &dyn I32Iterator<Item = u32> = &vec![42].into_iter();
-    //~^ ERROR expected `std::vec::IntoIter<u32>` to be an iterator that yields `i32`, but it yields `u32`
+    //~^ ERROR expected `IntoIter<u32>` to be an iterator that yields `i32`, but it yields `u32`
 }
index 2d25f68de44ad1c34a7c36976ce21a9300699deb..a28a0b74e4accd98c47bbf6f001d9562560f4ff8 100644 (file)
@@ -1,4 +1,4 @@
-error[E0271]: expected `std::vec::IntoIter<u32>` to be an iterator that yields `i32`, but it yields `u32`
+error[E0271]: expected `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 e51a8f3bd1a3ae05363f2db0ff0862ae66d0956d..ef9b7cae01bbd4c00290ff2dd006e5562335662d 100644 (file)
@@ -6,6 +6,11 @@ LL |     fn bar() -> isize;
 ...
 LL |     let x: isize = Foo::bar();
    |                    ^^^^^^^^ cannot call associated function of trait
+   |
+help: use the fully-qualified path to the only available implementation
+   |
+LL |     let x: isize = <isize as Foo>::bar();
+   |                    +++++++++    +
 
 error: aborting due to previous error
 
index f0f5245a3b42ba5d395058ed9bad1037146056b0..fb83ca90a37873dcbcb572a25e6ff5c676dc5f55 100644 (file)
@@ -40,7 +40,7 @@ LL |   async fn bar2<T>(_: T) -> ! {
 LL | |     panic!()
 LL | | }
    | |_^
-   = note: required because it captures the following types: `&mut Context<'_>`, `Option<bool>`, `impl Future<Output = !>`, `()`
+   = note: required because it captures the following types: `ResumeTy`, `Option<bool>`, `impl Future<Output = !>`, `()`
 note: required because it's used within this `async fn` body
   --> $DIR/async-await-let-else.rs:21:32
    |
diff --git a/src/test/ui/async-await/in-trait/bad-signatures.rs b/src/test/ui/async-await/in-trait/bad-signatures.rs
new file mode 100644 (file)
index 0000000..b86f1d1
--- /dev/null
@@ -0,0 +1,16 @@
+// edition:2021
+
+#![feature(async_fn_in_trait)]
+//~^ WARN the feature `async_fn_in_trait` is incomplete
+
+trait MyTrait {
+    async fn bar(&abc self);
+    //~^ ERROR expected identifier, found keyword `self`
+    //~| ERROR expected one of `:`, `@`, or `|`, found keyword `self`
+}
+
+impl MyTrait for () {
+    async fn bar(&self) {}
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/in-trait/bad-signatures.stderr b/src/test/ui/async-await/in-trait/bad-signatures.stderr
new file mode 100644 (file)
index 0000000..e0ba7b5
--- /dev/null
@@ -0,0 +1,26 @@
+error: expected identifier, found keyword `self`
+  --> $DIR/bad-signatures.rs:7:23
+   |
+LL |     async fn bar(&abc self);
+   |                       ^^^^ expected identifier, found keyword
+
+error: expected one of `:`, `@`, or `|`, found keyword `self`
+  --> $DIR/bad-signatures.rs:7:23
+   |
+LL |     async fn bar(&abc self);
+   |                  -----^^^^
+   |                  |    |
+   |                  |    expected one of `:`, `@`, or `|`
+   |                  help: declare the type after the parameter binding: `<identifier>: <type>`
+
+warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/bad-signatures.rs:3:12
+   |
+LL | #![feature(async_fn_in_trait)]
+   |            ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error: aborting due to 2 previous errors; 1 warning emitted
+
index 1c90bedae790c66259bc6c47e956ebb90907e003..f2802698fd5b646fdd3e993df175ae58705b5abe 100644 (file)
@@ -57,7 +57,7 @@ note: required because it appears within the type `impl Future<Output = Arc<RefC
    |
 LL | fn make_non_send_future2() -> impl Future<Output = Arc<RefCell<i32>>> {
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: required because it captures the following types: `&mut Context<'_>`, `impl Future<Output = Arc<RefCell<i32>>>`, `()`, `Ready<i32>`
+   = note: required because it captures the following types: `ResumeTy`, `impl Future<Output = Arc<RefCell<i32>>>`, `()`, `Ready<i32>`
 note: required because it's used within this `async` block
   --> $DIR/issue-68112.rs:60:20
    |
index e09ae7fedd8055f1f636f711bbe1fdd619048213..38eb85b302fd588abbeb8e8f4b82f84338fa21bb 100644 (file)
@@ -57,7 +57,7 @@ note: required because it appears within the type `impl Future<Output = Arc<RefC
    |
 LL | fn make_non_send_future2() -> impl Future<Output = Arc<RefCell<i32>>> {
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: required because it captures the following types: `&mut Context<'_>`, `impl Future<Output = Arc<RefCell<i32>>>`, `()`, `i32`, `Ready<i32>`
+   = note: required because it captures the following types: `ResumeTy`, `impl Future<Output = Arc<RefCell<i32>>>`, `()`, `i32`, `Ready<i32>`
 note: required because it's used within this `async` block
   --> $DIR/issue-68112.rs:60:20
    |
index e6ad2f0d444bb7e8faa44cd6cc6f4a787fc87b80..3d2b0402bc52c614564988f0e53b8705b0691acf 100644 (file)
@@ -14,9 +14,6 @@ LL | |     });
    |
    = note: `FnMut` closures only have access to their captured variables while they are executing...
    = note: ...therefore, they cannot allow references to captured variables to escape
-   = note: requirement occurs because of a mutable reference to `Context<'_>`
-   = note: mutable references are invariant over their type parameter
-   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: aborting due to previous error
 
index a8fd97cde8f7a8bd7b9f64c71b96179ed7658dce..721234aa4a782875a2e90e32d4c2f5bea168c7f0 100644 (file)
@@ -18,7 +18,7 @@ LL |   async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> {
    |  ___________________________________________________________________^
 LL | | }
    | |_^
-   = note: required because it captures the following types: `&mut Context<'_>`, `impl Future<Output = ()>`, `()`
+   = note: required because it captures the following types: `ResumeTy`, `impl Future<Output = ()>`, `()`
 note: required because it's used within this `async` block
   --> $DIR/issue-70935-complex-spans.rs:16:5
    |
diff --git a/src/test/ui/async-await/issues/issue-102206.rs b/src/test/ui/async-await/issues/issue-102206.rs
new file mode 100644 (file)
index 0000000..a3a2ebc
--- /dev/null
@@ -0,0 +1,8 @@
+// edition:2021
+
+async fn foo() {}
+
+fn main() {
+    std::mem::size_of_val(foo());
+    //~^ ERROR: mismatched types
+}
diff --git a/src/test/ui/async-await/issues/issue-102206.stderr b/src/test/ui/async-await/issues/issue-102206.stderr
new file mode 100644 (file)
index 0000000..2ab790a
--- /dev/null
@@ -0,0 +1,23 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-102206.rs:6:27
+   |
+LL |     std::mem::size_of_val(foo());
+   |     --------------------- ^^^^^
+   |     |                     |
+   |     |                     expected reference, found opaque type
+   |     |                     help: consider borrowing here: `&foo()`
+   |     arguments to this function are incorrect
+   |
+note: while checking the return type of the `async fn`
+  --> $DIR/issue-102206.rs:3:16
+   |
+LL | async fn foo() {}
+   |                ^ checked the `Output` of this `async fn`, found opaque type
+   = note: expected reference `&_`
+            found opaque type `impl Future<Output = ()>`
+note: function defined here
+  --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
index 25876d5084015f6720a31293c78bce0bb7c67a77..17b4ef7bdc671705abd27ca37e8423cb94878cc2 100644 (file)
@@ -11,7 +11,7 @@ LL | async fn foo() {
    |
    = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `NotSend`
    = note: required because it appears within the type `(NotSend,)`
-   = note: required because it captures the following types: `&mut Context<'_>`, `(NotSend,)`, `()`, `impl Future<Output = ()>`
+   = note: required because it captures the following types: `ResumeTy`, `(NotSend,)`, `()`, `impl Future<Output = ()>`
 note: required because it's used within this `async fn` body
   --> $DIR/partial-drop-partial-reinit.rs:31:16
    |
index dba2a620779f0f446f537663fc8995a40037baaf..34d8a159f1064bf05c1e448b9be5303830be108f 100644 (file)
@@ -11,7 +11,7 @@ LL | async fn foo() {
    |
    = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `NotSend`
    = note: required because it appears within the type `(NotSend,)`
-   = note: required because it captures the following types: `&mut Context<'_>`, `(NotSend,)`, `impl Future<Output = ()>`, `()`
+   = note: required because it captures the following types: `ResumeTy`, `(NotSend,)`, `impl Future<Output = ()>`, `()`
 note: required because it's used within this `async fn` body
   --> $DIR/partial-drop-partial-reinit.rs:31:16
    |
diff --git a/src/test/ui/borrowck/issue-103095.rs b/src/test/ui/borrowck/issue-103095.rs
new file mode 100644 (file)
index 0000000..0340f39
--- /dev/null
@@ -0,0 +1,30 @@
+// check-pass
+
+trait FnOnceForGenericRef<T>: FnOnce(&T) -> Self::FnOutput {
+    type FnOutput;
+}
+
+impl<T, R, F: FnOnce(&T) -> R> FnOnceForGenericRef<T> for F {
+    type FnOutput = R;
+}
+
+struct Data<T, D: FnOnceForGenericRef<T>> {
+    value: Option<T>,
+    output: Option<D::FnOutput>,
+}
+
+impl<T, D: FnOnceForGenericRef<T>> Data<T, D> {
+    fn new(value: T, f: D) -> Self {
+        let output = f(&value);
+        Self {
+            value: Some(value),
+            output: Some(output),
+        }
+    }
+}
+
+fn test() {
+    Data::new(String::new(), |_| {});
+}
+
+fn main() {}
diff --git a/src/test/ui/codegen/issue-55976.rs b/src/test/ui/codegen/issue-55976.rs
new file mode 100644 (file)
index 0000000..3142704
--- /dev/null
@@ -0,0 +1,13 @@
+// run-pass
+// ^-- The above is needed as this issue is related to LLVM/codegen.
+// min-llvm-version:15.0.0
+// ^-- The above is needed as this issue is fixed by the opaque pointers.
+
+fn main() {
+    type_error(|x| &x);
+}
+
+fn type_error<T>(
+    _selector: for<'a> fn(&'a Vec<Box<dyn for<'b> Fn(&'b u8)>>) -> &'a Vec<Box<dyn Fn(T)>>,
+) {
+}
index 34debb6831734568330e7b6d8ccfaa32ae753e3f..3906d64c9462453682f8edf42d47332c5619b14f 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `closure` found for reference `&Obj<[closure@$DIR/issue-33784.rs:25:43: 25:45]>` in the current scope
+error[E0599]: no method named `closure` found for reference `&Obj<[closure@issue-33784.rs:25:43]>` in the current scope
   --> $DIR/issue-33784.rs:27:7
    |
 LL |     p.closure();
@@ -9,7 +9,7 @@ help: to call the function stored in `closure`, surround the field access with p
 LL |     (p.closure)();
    |     +         +
 
-error[E0599]: no method named `fn_ptr` found for reference `&&Obj<[closure@$DIR/issue-33784.rs:25:43: 25:45]>` in the current scope
+error[E0599]: no method named `fn_ptr` found for reference `&&Obj<[closure@issue-33784.rs:25:43]>` in the current scope
   --> $DIR/issue-33784.rs:29:7
    |
 LL |     q.fn_ptr();
diff --git a/src/test/ui/const-generics/defaults/complex-unord-param.min.stderr b/src/test/ui/const-generics/defaults/complex-unord-param.min.stderr
deleted file mode 100644 (file)
index 8e8d26a..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-error: type parameters must be declared prior to const parameters
-  --> $DIR/complex-unord-param.rs:8:41
-   |
-LL | struct NestedArrays<'a, const N: usize, A: 'a, const M: usize, T:'a =u32> {
-   |                    ---------------------^----------------------^--------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, A: 'a, T: 'a = u32, const N: usize, const M: usize>`
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/const-generics/issue-105689.rs b/src/test/ui/const-generics/issue-105689.rs
new file mode 100644 (file)
index 0000000..4237b3c
--- /dev/null
@@ -0,0 +1,14 @@
+// check-pass
+// edition:2021
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+#[allow(unused)]
+async fn foo<'a>() {
+    let _data = &mut [0u8; { 1 + 4 }];
+    bar().await
+}
+
+async fn bar() {}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/type-after-const-ok.min.stderr b/src/test/ui/const-generics/type-after-const-ok.min.stderr
deleted file mode 100644 (file)
index ad38754..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-error: type parameters must be declared prior to const parameters
-  --> $DIR/type-after-const-ok.rs:8:26
-   |
-LL | struct A<const N: usize, T>(T);
-   |         -----------------^- help: reorder the parameters: lifetimes, then types, then consts: `<T, const N: usize>`
-
-error: aborting due to previous error
-
index 3a58a7cd7ef05b5670b01b8514e158b0e3dd528f..0079bb3aad6df5b72e8fb68ff9f1d7844c5a581b 100644 (file)
@@ -27,7 +27,7 @@ LL | pub static S1: &[()] = unsafe { from_raw_parts(ptr::null(), 0) };
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-   = note: dereferencing pointer failed: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
+   = note: dereferencing pointer failed: allocN has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
    |
 note: inside `std::slice::from_raw_parts::<'_, u32>`
   --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
@@ -45,7 +45,7 @@ LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾─ALLOC_ID─╼ 01 00 00 00                         │ ╾──╼....
+               ╾ALLOC_ID╼ 01 00 00 00                         │ ╾──╼....
            }
 
 error[E0080]: it is undefined behavior to use this value
@@ -57,7 +57,7 @@ LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾─ALLOC_ID─╼ 04 00 00 00                         │ ╾──╼....
+               ╾ALLOC_ID╼ 04 00 00 00                         │ ╾──╼....
            }
 
 error[E0080]: it is undefined behavior to use this value
@@ -68,24 +68,24 @@ LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4)
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾─ALLOC_ID─╼ 04 00 00 00                         │ ╾──╼....
+               ╾ALLOC_ID╼ 04 00 00 00                         │ ╾──╼....
            }
 
 error[E0080]: it is undefined behavior to use this value
   --> $DIR/forbidden_slices.rs:32:1
    |
 LL | pub static S7: &[u16] = unsafe {
-   | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
+   | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[1]: encountered uninitialized bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾─A_ID+0x1─╼ 04 00 00 00                         │ ╾──╼....
+               ╾ALLOC_ID+0x2╼ 04 00 00 00                         │ ╾──╼....
            }
 
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-   = note: dereferencing pointer failed: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
+   = note: dereferencing pointer failed: allocN has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
    |
 note: inside `std::slice::from_raw_parts::<'_, u64>`
   --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
@@ -129,7 +129,7 @@ LL | pub static R1: &[()] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-   = note: out-of-bounds pointer arithmetic: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
+   = note: out-of-bounds pointer arithmetic: allocN has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
    |
 note: inside `ptr::const_ptr::<impl *const u32>::offset`
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
@@ -149,7 +149,7 @@ LL | pub static R4: &[u8] = unsafe {
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               â\95¾ALLOC_IDâ\94\80â\95¼ 01 00 00 00                         â\94\82 â\95¾â\94\80â\94\80â\95¼....
+               ╾ALLOC_ID╼ 01 00 00 00                         │ ╾──╼....
            }
 
 error[E0080]: it is undefined behavior to use this value
@@ -161,7 +161,7 @@ LL | pub static R5: &[u8] = unsafe {
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               â\95¾ALLOC_IDâ\94\80â\95¼ 04 00 00 00                         â\94\82 â\95¾â\94\80â\94\80â\95¼....
+               ╾ALLOC_ID╼ 04 00 00 00                         │ ╾──╼....
            }
 
 error[E0080]: it is undefined behavior to use this value
@@ -172,31 +172,35 @@ LL | pub static R6: &[bool] = unsafe {
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               â\95¾ALLOC_IDâ\94\80â\95¼ 04 00 00 00                         â\94\82 â\95¾â\94\80â\94\80â\95¼....
+               ╾ALLOC_ID╼ 04 00 00 00                         │ ╾──╼....
            }
 
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/forbidden_slices.rs:67:1
+error[E0080]: could not evaluate static initializer
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-LL | pub static R7: &[u16] = unsafe {
-   | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
+   = note: accessing memory with alignment 1, but alignment 2 is required
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾A_ID+0x1─╼ 04 00 00 00                         │ ╾──╼....
-           }
+note: inside `std::slice::from_raw_parts::<'_, u16>`
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `from_ptr_range::<'_, u16>`
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `R7`
+  --> $DIR/forbidden_slices.rs:69:5
+   |
+LL |     from_ptr_range(ptr..ptr.add(4))
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-   = note: out-of-bounds pointer arithmetic: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
+   = note: out-of-bounds pointer arithmetic: allocN has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
    |
 note: inside `ptr::const_ptr::<impl *const u64>::offset`
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
 note: inside `ptr::const_ptr::<impl *const u64>::add`
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
 note: inside `R8`
-  --> $DIR/forbidden_slices.rs:74:25
+  --> $DIR/forbidden_slices.rs:73:25
    |
 LL |     from_ptr_range(ptr..ptr.add(1))
    |                         ^^^^^^^^^^
@@ -211,7 +215,7 @@ note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr`
 note: inside `from_ptr_range::<'_, u32>`
   --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
 note: inside `R9`
-  --> $DIR/forbidden_slices.rs:79:34
+  --> $DIR/forbidden_slices.rs:78:34
    |
 LL | pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).add(1)) };
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -226,7 +230,7 @@ note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr`
 note: inside `from_ptr_range::<'_, u32>`
   --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
 note: inside `R10`
-  --> $DIR/forbidden_slices.rs:80:35
+  --> $DIR/forbidden_slices.rs:79:35
    |
 LL | pub static R10: &[u32] = unsafe { from_ptr_range(&D0..&D0) };
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^
index 4e929e3525c20dc78aec81d9af1ac7a5e5efbd86..f4f9fe69516a6a258a1abb022c7c35b5b135d37a 100644 (file)
@@ -27,7 +27,7 @@ LL | pub static S1: &[()] = unsafe { from_raw_parts(ptr::null(), 0) };
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-   = note: dereferencing pointer failed: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
+   = note: dereferencing pointer failed: allocN has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
    |
 note: inside `std::slice::from_raw_parts::<'_, u32>`
   --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
@@ -45,7 +45,7 @@ LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾───────ALLOC_ID───────╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
+               ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
            }
 
 error[E0080]: it is undefined behavior to use this value
@@ -57,7 +57,7 @@ LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾───────ALLOC_ID───────╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........
+               ╾ALLOC_ID╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........
            }
 
 error[E0080]: it is undefined behavior to use this value
@@ -68,24 +68,24 @@ LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4)
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾───────ALLOC_ID───────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
+               ╾ALLOC_ID╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
            }
 
 error[E0080]: it is undefined behavior to use this value
   --> $DIR/forbidden_slices.rs:32:1
    |
 LL | pub static S7: &[u16] = unsafe {
-   | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
+   | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[1]: encountered uninitialized bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾─────ALLOC_ID+0x1─────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
+               ╾ALLOC_ID+0x2╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
            }
 
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-   = note: dereferencing pointer failed: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
+   = note: dereferencing pointer failed: allocN has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
    |
 note: inside `std::slice::from_raw_parts::<'_, u64>`
   --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
@@ -129,7 +129,7 @@ LL | pub static R1: &[()] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-   = note: out-of-bounds pointer arithmetic: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
+   = note: out-of-bounds pointer arithmetic: allocN has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
    |
 note: inside `ptr::const_ptr::<impl *const u32>::offset`
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
@@ -149,7 +149,7 @@ LL | pub static R4: &[u8] = unsafe {
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾──────ALLOC_ID───────╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
+               ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
            }
 
 error[E0080]: it is undefined behavior to use this value
@@ -161,7 +161,7 @@ LL | pub static R5: &[u8] = unsafe {
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾──────ALLOC_ID───────╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........
+               ╾ALLOC_ID╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........
            }
 
 error[E0080]: it is undefined behavior to use this value
@@ -172,31 +172,35 @@ LL | pub static R6: &[bool] = unsafe {
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾──────ALLOC_ID───────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
+               ╾ALLOC_ID╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
            }
 
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/forbidden_slices.rs:67:1
+error[E0080]: could not evaluate static initializer
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-LL | pub static R7: &[u16] = unsafe {
-   | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
+   = note: accessing memory with alignment 1, but alignment 2 is required
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾────ALLOC_ID+0x1─────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
-           }
+note: inside `std::slice::from_raw_parts::<'_, u16>`
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `from_ptr_range::<'_, u16>`
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `R7`
+  --> $DIR/forbidden_slices.rs:69:5
+   |
+LL |     from_ptr_range(ptr..ptr.add(4))
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-   = note: out-of-bounds pointer arithmetic: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
+   = note: out-of-bounds pointer arithmetic: allocN has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
    |
 note: inside `ptr::const_ptr::<impl *const u64>::offset`
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
 note: inside `ptr::const_ptr::<impl *const u64>::add`
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
 note: inside `R8`
-  --> $DIR/forbidden_slices.rs:74:25
+  --> $DIR/forbidden_slices.rs:73:25
    |
 LL |     from_ptr_range(ptr..ptr.add(1))
    |                         ^^^^^^^^^^
@@ -211,7 +215,7 @@ note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr`
 note: inside `from_ptr_range::<'_, u32>`
   --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
 note: inside `R9`
-  --> $DIR/forbidden_slices.rs:79:34
+  --> $DIR/forbidden_slices.rs:78:34
    |
 LL | pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).add(1)) };
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -226,7 +230,7 @@ note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr`
 note: inside `from_ptr_range::<'_, u32>`
   --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
 note: inside `R10`
-  --> $DIR/forbidden_slices.rs:80:35
+  --> $DIR/forbidden_slices.rs:79:35
    |
 LL | pub static R10: &[u32] = unsafe { from_ptr_range(&D0..&D0) };
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^
index e2184911f422c47cfe2318fd641c688e7d4cc90a..cc6100226dc1c00794ec90bbaf9524e9489f5f88 100644 (file)
@@ -1,6 +1,6 @@
 // stderr-per-bitwidth
-// normalize-stderr-test "alloc[0-9]+" -> "ALLOC_ID"
-// normalize-stderr-test "a[0-9]+\+0x" -> "A_ID+0x"
+// normalize-stderr-test "╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼" -> "╾ALLOC_ID$2╼"
+// normalize-stderr-test "alloc\d+" -> "allocN"
 // error-pattern: could not evaluate static initializer
 #![feature(
     slice_from_ptr_range,
@@ -31,7 +31,7 @@
 // Reading padding is not ok
 pub static S7: &[u16] = unsafe {
     //~^ ERROR: it is undefined behavior to use this value
-    let ptr = (&D2 as *const Struct as *const u16).byte_add(1);
+    let ptr = (&D2 as *const Struct as *const u16).add(1);
 
     from_raw_parts(ptr, 4)
 };
     from_ptr_range(ptr..ptr.add(4))
 };
 pub static R7: &[u16] = unsafe {
-    //~^ ERROR: it is undefined behavior to use this value
     let ptr = (&D2 as *const Struct as *const u16).byte_add(1);
-    from_ptr_range(ptr..ptr.add(4))
+    from_ptr_range(ptr..ptr.add(4)) //~ inside `R7`
 };
 pub static R8: &[u64] = unsafe {
     let ptr = (&D4 as *const [u32; 2] as *const u32).byte_add(1).cast::<u64>();
-    from_ptr_range(ptr..ptr.add(1))
+    from_ptr_range(ptr..ptr.add(1)) //~ inside `R8`
 };
 
 // This is sneaky: &D0 and &D0 point to different objects
index e5b5c7a846c116f0cd6092036eed1473f323254c..a0a8d76d10d2d9b86e6fbd6733ddd3662f0b6026 100644 (file)
@@ -1,5 +1,5 @@
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:13:1
+  --> $DIR/ub-ref-ptr.rs:14:1
    |
 LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) };
    | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
@@ -10,7 +10,7 @@ LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) };
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:17:1
+  --> $DIR/ub-ref-ptr.rs:18:1
    |
 LL | const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1)
@@ -21,7 +21,7 @@ LL | const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) };
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:21:1
+  --> $DIR/ub-ref-ptr.rs:22:1
    |
 LL | const NULL: &u16 = unsafe { mem::transmute(0usize) };
    | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference
@@ -32,7 +32,7 @@ LL | const NULL: &u16 = unsafe { mem::transmute(0usize) };
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:24:1
+  --> $DIR/ub-ref-ptr.rs:25:1
    |
 LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null box
@@ -43,7 +43,7 @@ LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
            }
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-ref-ptr.rs:31:1
+  --> $DIR/ub-ref-ptr.rs:32:1
    |
 LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -52,7 +52,7 @@ LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-ref-ptr.rs:34:39
+  --> $DIR/ub-ref-ptr.rs:35:39
    |
 LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
    |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -61,13 +61,13 @@ LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 note: erroneous constant used
-  --> $DIR/ub-ref-ptr.rs:34:38
+  --> $DIR/ub-ref-ptr.rs:35:38
    |
 LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-ref-ptr.rs:37:86
+  --> $DIR/ub-ref-ptr.rs:38:86
    |
 LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
    |                                                                                      ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -76,13 +76,13 @@ LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[us
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 note: erroneous constant used
-  --> $DIR/ub-ref-ptr.rs:37:85
+  --> $DIR/ub-ref-ptr.rs:38:85
    |
 LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
    |                                                                                     ^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:40:1
+  --> $DIR/ub-ref-ptr.rs:41:1
    |
 LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (address 0x539 is unallocated)
@@ -93,7 +93,7 @@ LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:43:1
+  --> $DIR/ub-ref-ptr.rs:44:1
    |
 LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (address 0x539 is unallocated)
@@ -104,13 +104,13 @@ LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) };
            }
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-ref-ptr.rs:46:41
+  --> $DIR/ub-ref-ptr.rs:47:41
    |
 LL | const UNINIT_PTR: *const i32 = unsafe { MaybeUninit { uninit: () }.init };
    |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:50:1
+  --> $DIR/ub-ref-ptr.rs:51:1
    |
 LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a function pointer
@@ -121,13 +121,13 @@ LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) };
            }
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-ref-ptr.rs:52:38
+  --> $DIR/ub-ref-ptr.rs:53:38
    |
 LL | const UNINIT_FN_PTR: fn() = unsafe { MaybeUninit { uninit: () }.init };
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:55:1
+  --> $DIR/ub-ref-ptr.rs:56:1
    |
 LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xd[noalloc], but expected a function pointer
@@ -138,7 +138,7 @@ LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:57:1
+  --> $DIR/ub-ref-ptr.rs:58:1
    |
 LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
    | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered alloc41, but expected a function pointer
@@ -148,6 +148,39 @@ LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
                ╾─alloc41─╼                                     │ ╾──╼
            }
 
-error: aborting due to 14 previous errors
+error: accessing memory with alignment 1, but alignment 4 is required
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+   |
+   = 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 #68585 <https://github.com/rust-lang/rust/issues/104616>
+note: inside `std::ptr::read::<u32>`
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+note: inside `ptr::const_ptr::<impl *const u32>::read`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `UNALIGNED_READ`
+  --> $DIR/ub-ref-ptr.rs:65:5
+   |
+LL |     ptr.read();
+   |     ^^^^^^^^^^
+   = note: `#[deny(invalid_alignment)]` on by default
+
+error: aborting due to 15 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+error: accessing memory with alignment 1, but alignment 4 is required
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+   |
+   = 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 #68585 <https://github.com/rust-lang/rust/issues/104616>
+note: inside `std::ptr::read::<u32>`
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+note: inside `ptr::const_ptr::<impl *const u32>::read`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `UNALIGNED_READ`
+  --> $DIR/ub-ref-ptr.rs:65:5
+   |
+LL |     ptr.read();
+   |     ^^^^^^^^^^
+   = note: `#[deny(invalid_alignment)]` on by default
+
index 607366cabc4e9d30c5a2ba70964fe4eb69854d61..d53b44671e3f48eb53a2c6f1c3a085cb95b92d7b 100644 (file)
@@ -1,5 +1,5 @@
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:13:1
+  --> $DIR/ub-ref-ptr.rs:14:1
    |
 LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) };
    | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
@@ -10,7 +10,7 @@ LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) };
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:17:1
+  --> $DIR/ub-ref-ptr.rs:18:1
    |
 LL | const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1)
@@ -21,7 +21,7 @@ LL | const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) };
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:21:1
+  --> $DIR/ub-ref-ptr.rs:22:1
    |
 LL | const NULL: &u16 = unsafe { mem::transmute(0usize) };
    | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference
@@ -32,7 +32,7 @@ LL | const NULL: &u16 = unsafe { mem::transmute(0usize) };
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:24:1
+  --> $DIR/ub-ref-ptr.rs:25:1
    |
 LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null box
@@ -43,7 +43,7 @@ LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
            }
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-ref-ptr.rs:31:1
+  --> $DIR/ub-ref-ptr.rs:32:1
    |
 LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -52,7 +52,7 @@ LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-ref-ptr.rs:34:39
+  --> $DIR/ub-ref-ptr.rs:35:39
    |
 LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
    |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -61,13 +61,13 @@ LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 note: erroneous constant used
-  --> $DIR/ub-ref-ptr.rs:34:38
+  --> $DIR/ub-ref-ptr.rs:35:38
    |
 LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-ref-ptr.rs:37:86
+  --> $DIR/ub-ref-ptr.rs:38:86
    |
 LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
    |                                                                                      ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -76,13 +76,13 @@ LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[us
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 note: erroneous constant used
-  --> $DIR/ub-ref-ptr.rs:37:85
+  --> $DIR/ub-ref-ptr.rs:38:85
    |
 LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
    |                                                                                     ^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:40:1
+  --> $DIR/ub-ref-ptr.rs:41:1
    |
 LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (address 0x539 is unallocated)
@@ -93,7 +93,7 @@ LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:43:1
+  --> $DIR/ub-ref-ptr.rs:44:1
    |
 LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (address 0x539 is unallocated)
@@ -104,13 +104,13 @@ LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) };
            }
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-ref-ptr.rs:46:41
+  --> $DIR/ub-ref-ptr.rs:47:41
    |
 LL | const UNINIT_PTR: *const i32 = unsafe { MaybeUninit { uninit: () }.init };
    |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:50:1
+  --> $DIR/ub-ref-ptr.rs:51:1
    |
 LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a function pointer
@@ -121,13 +121,13 @@ LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) };
            }
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-ref-ptr.rs:52:38
+  --> $DIR/ub-ref-ptr.rs:53:38
    |
 LL | const UNINIT_FN_PTR: fn() = unsafe { MaybeUninit { uninit: () }.init };
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:55:1
+  --> $DIR/ub-ref-ptr.rs:56:1
    |
 LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xd[noalloc], but expected a function pointer
@@ -138,7 +138,7 @@ LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:57:1
+  --> $DIR/ub-ref-ptr.rs:58:1
    |
 LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
    | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered alloc41, but expected a function pointer
@@ -148,6 +148,39 @@ LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
                ╾───────alloc41───────╼                         │ ╾──────╼
            }
 
-error: aborting due to 14 previous errors
+error: accessing memory with alignment 1, but alignment 4 is required
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+   |
+   = 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 #68585 <https://github.com/rust-lang/rust/issues/104616>
+note: inside `std::ptr::read::<u32>`
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+note: inside `ptr::const_ptr::<impl *const u32>::read`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `UNALIGNED_READ`
+  --> $DIR/ub-ref-ptr.rs:65:5
+   |
+LL |     ptr.read();
+   |     ^^^^^^^^^^
+   = note: `#[deny(invalid_alignment)]` on by default
+
+error: aborting due to 15 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+error: accessing memory with alignment 1, but alignment 4 is required
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+   |
+   = 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 #68585 <https://github.com/rust-lang/rust/issues/104616>
+note: inside `std::ptr::read::<u32>`
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+note: inside `ptr::const_ptr::<impl *const u32>::read`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `UNALIGNED_READ`
+  --> $DIR/ub-ref-ptr.rs:65:5
+   |
+LL |     ptr.read();
+   |     ^^^^^^^^^^
+   = note: `#[deny(invalid_alignment)]` on by default
+
index a1c81239009ac0569e45d8217764ccf07ad9c81a..b0fc3c196a49fc3457915955dd277d352d6154c0 100644 (file)
@@ -1,6 +1,7 @@
 // ignore-tidy-linelength
 // stderr-per-bitwidth
 #![allow(invalid_value)]
+#![feature(const_ptr_read)]
 
 use std::mem;
 
@@ -57,4 +58,12 @@ union MaybeUninit<T: Copy> {
 const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
 //~^ ERROR it is undefined behavior to use this value
 
+
+const UNALIGNED_READ: () = unsafe {
+    let x = &[0u8; 4];
+    let ptr = x.as_ptr().cast::<u32>();
+    ptr.read(); //~ inside `UNALIGNED_READ`
+};
+
+
 fn main() {}
index 9994c2e5a83458c27cb6e3ad8ee66071eeabad14..90a3dcada058d691ec0dfee66edc0e1e87ad53da 100644 (file)
@@ -1,27 +1,27 @@
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:36:1
+  --> $DIR/ub-wide-ptr.rs:37:1
    |
 LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation)
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾─allocN──╼ e7 03 00 00                         │ ╾──╼....
+               ╾ALLOC_ID╼ e7 03 00 00                         │ ╾──╼....
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:38:1
+  --> $DIR/ub-wide-ptr.rs:39:1
    |
 LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid reference metadata: slice is bigger than largest supported object
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾─allocN─╼ ff ff ff ff                         │ ╾──╼....
+               ╾ALLOC_ID╼ ff ff ff ff                         │ ╾──╼....
            }
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:41:1
+  --> $DIR/ub-wide-ptr.rs:42:1
    |
 LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -30,7 +30,7 @@ LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:44:1
+  --> $DIR/ub-wide-ptr.rs:45:1
    |
 LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -39,68 +39,68 @@ LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:46:1
+  --> $DIR/ub-wide-ptr.rs:47:1
    |
 LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾─allocN─╼ ff ff ff ff                         │ ╾──╼....
+               ╾ALLOC_ID╼ ff ff ff ff                         │ ╾──╼....
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:50:1
+  --> $DIR/ub-wide-ptr.rs:51:1
    |
 LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
    | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered uninitialized data in `str`
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾─allocN─╼ 01 00 00 00                         │ ╾──╼....
+               ╾ALLOC_ID╼ 01 00 00 00                         │ ╾──╼....
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:53:1
+  --> $DIR/ub-wide-ptr.rs:54:1
    |
 LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered uninitialized data in `str`
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾─allocN─╼ 01 00 00 00                         │ ╾──╼....
+               ╾ALLOC_ID╼ 01 00 00 00                         │ ╾──╼....
            }
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:60:1
+  --> $DIR/ub-wide-ptr.rs:61:1
    |
 LL | const SLICE_LENGTH_UNINIT: &[u8] = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:67:1
+  --> $DIR/ub-wide-ptr.rs:68:1
    |
 LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation)
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾─allocN─╼ e7 03 00 00                         │ ╾──╼....
+               ╾ALLOC_ID╼ e7 03 00 00                         │ ╾──╼....
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:70:1
+  --> $DIR/ub-wide-ptr.rs:71:1
    |
 LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾─allocN─╼ ff ff ff 7f                         │ ╾──╼....
+               ╾ALLOC_ID╼ ff ff ff 7f                         │ ╾──╼....
            }
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:73:1
+  --> $DIR/ub-wide-ptr.rs:74:1
    |
 LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -109,18 +109,18 @@ LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:76:1
+  --> $DIR/ub-wide-ptr.rs:77:1
    |
 LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (going beyond the bounds of its allocation)
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾─allocN─╼ e7 03 00 00                         │ ╾──╼....
+               ╾ALLOC_ID╼ e7 03 00 00                         │ ╾──╼....
            }
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:79:1
+  --> $DIR/ub-wide-ptr.rs:80:1
    |
 LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -129,165 +129,165 @@ LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:83:1
+  --> $DIR/ub-wide-ptr.rs:84:1
    |
 LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x03, but expected a boolean
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
-               ╾─allocN─╼                                     │ ╾──╼
+               ╾ALLOC_ID╼                                     │ ╾──╼
            }
 
 note: erroneous constant used
-  --> $DIR/ub-wide-ptr.rs:83:40
+  --> $DIR/ub-wide-ptr.rs:84:40
    |
 LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
    |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:90:1
+  --> $DIR/ub-wide-ptr.rs:91:1
    |
 LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered 0x03, but expected a boolean
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
-               ╾allocN─╼                                     │ ╾──╼
+               ╾ALLOC_ID╼                                     │ ╾──╼
            }
 
 note: erroneous constant used
-  --> $DIR/ub-wide-ptr.rs:90:42
+  --> $DIR/ub-wide-ptr.rs:91:42
    |
 LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
    |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:94:1
+  --> $DIR/ub-wide-ptr.rs:95:1
    |
 LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.1[0]: encountered 0x03, but expected a boolean
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
-               ╾allocN─╼                                     │ ╾──╼
+               ╾ALLOC_ID╼                                     │ ╾──╼
            }
 
 note: erroneous constant used
-  --> $DIR/ub-wide-ptr.rs:94:42
+  --> $DIR/ub-wide-ptr.rs:95:42
    |
 LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
    |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:102:1
+  --> $DIR/ub-wide-ptr.rs:103:1
    |
 LL | const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:111:1
+  --> $DIR/ub-wide-ptr.rs:112:1
    |
 LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾allocN─╼ ╾allocN─╼                         │ ╾──╼╾──╼
+               ╾ALLOC_ID╼ ╾ALLOC_ID╼                         │ ╾──╼╾──╼
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:115:1
+  --> $DIR/ub-wide-ptr.rs:116:1
    |
 LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾allocN─╼ ╾allocN─╼                         │ ╾──╼╾──╼
+               ╾ALLOC_ID╼ ╾ALLOC_ID╼                         │ ╾──╼╾──╼
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:119:1
+  --> $DIR/ub-wide-ptr.rs:120:1
    |
 LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾allocN─╼ 04 00 00 00                         │ ╾──╼....
+               ╾ALLOC_ID╼ 04 00 00 00                         │ ╾──╼....
            }
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:122:57
+  --> $DIR/ub-wide-ptr.rs:123:57
    |
 LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) };
    |                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:125:57
+  --> $DIR/ub-wide-ptr.rs:126:57
    |
 LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) };
    |                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:128:56
+  --> $DIR/ub-wide-ptr.rs:129:56
    |
 LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) };
    |                                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:131:1
+  --> $DIR/ub-wide-ptr.rs:132:1
    |
 LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾allocN─╼ ╾allocN─╼                         │ ╾──╼╾──╼
+               ╾ALLOC_ID╼ ╾ALLOC_ID╼                         │ ╾──╼╾──╼
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:136:1
+  --> $DIR/ub-wide-ptr.rs:137:1
    |
 LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾allocN─╼ ╾allocN─╼                         │ ╾──╼╾──╼
+               ╾ALLOC_ID╼ ╾ALLOC_ID╼                         │ ╾──╼╾──╼
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:141:1
+  --> $DIR/ub-wide-ptr.rs:142:1
    |
 LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾allocN─╼ 00 00 00 00                         │ ╾──╼....
+               ╾ALLOC_ID╼ 00 00 00 00                         │ ╾──╼....
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:143:1
+  --> $DIR/ub-wide-ptr.rs:144:1
    |
 LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered allocN, but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾allocN─╼ ╾allocN─╼                         │ ╾──╼╾──╼
+               ╾ALLOC_ID╼ ╾ALLOC_ID╼                         │ ╾──╼╾──╼
            }
 
 error[E0080]: could not evaluate static initializer
-  --> $DIR/ub-wide-ptr.rs:149:5
+  --> $DIR/ub-wide-ptr.rs:150:5
    |
 LL |     mem::transmute::<_, &dyn Trait>((&92u8, 0usize))
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance)
 
 error[E0080]: could not evaluate static initializer
-  --> $DIR/ub-wide-ptr.rs:153:5
+  --> $DIR/ub-wide-ptr.rs:154:5
    |
 LL |     mem::transmute::<_, &dyn Trait>((&92u8, &3u64))
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
index 06a377d9f7c97982b8d7c29cac7a628b6eee2832..ab25303ddc0cf611df2a306a549d4fde936f52e0 100644 (file)
@@ -1,27 +1,27 @@
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:36:1
+  --> $DIR/ub-wide-ptr.rs:37:1
    |
 LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation)
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾───────allocN────────╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........
+               ╾ALLOC_ID╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:38:1
+  --> $DIR/ub-wide-ptr.rs:39:1
    |
 LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid reference metadata: slice is bigger than largest supported object
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾───────allocN───────╼ ff ff ff ff ff ff ff ff │ ╾──────╼........
+               ╾ALLOC_ID╼ ff ff ff ff ff ff ff ff │ ╾──────╼........
            }
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:41:1
+  --> $DIR/ub-wide-ptr.rs:42:1
    |
 LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -30,7 +30,7 @@ LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:44:1
+  --> $DIR/ub-wide-ptr.rs:45:1
    |
 LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -39,68 +39,68 @@ LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:46:1
+  --> $DIR/ub-wide-ptr.rs:47:1
    |
 LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾───────allocN───────╼ ff ff ff ff ff ff ff ff │ ╾──────╼........
+               ╾ALLOC_ID╼ ff ff ff ff ff ff ff ff │ ╾──────╼........
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:50:1
+  --> $DIR/ub-wide-ptr.rs:51:1
    |
 LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
    | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered uninitialized data in `str`
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾───────allocN───────╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
+               ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:53:1
+  --> $DIR/ub-wide-ptr.rs:54:1
    |
 LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered uninitialized data in `str`
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾───────allocN───────╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
+               ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
            }
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:60:1
+  --> $DIR/ub-wide-ptr.rs:61:1
    |
 LL | const SLICE_LENGTH_UNINIT: &[u8] = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:67:1
+  --> $DIR/ub-wide-ptr.rs:68:1
    |
 LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation)
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾───────allocN───────╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........
+               ╾ALLOC_ID╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:70:1
+  --> $DIR/ub-wide-ptr.rs:71:1
    |
 LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾───────allocN───────╼ ff ff ff ff ff ff ff 7f │ ╾──────╼........
+               ╾ALLOC_ID╼ ff ff ff ff ff ff ff 7f │ ╾──────╼........
            }
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:73:1
+  --> $DIR/ub-wide-ptr.rs:74:1
    |
 LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -109,18 +109,18 @@ LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:76:1
+  --> $DIR/ub-wide-ptr.rs:77:1
    |
 LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (going beyond the bounds of its allocation)
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾───────allocN───────╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........
+               ╾ALLOC_ID╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........
            }
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:79:1
+  --> $DIR/ub-wide-ptr.rs:80:1
    |
 LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -129,165 +129,165 @@ LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:83:1
+  --> $DIR/ub-wide-ptr.rs:84:1
    |
 LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x03, but expected a boolean
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
-               ╾───────allocN───────╼                         │ ╾──────╼
+               ╾ALLOC_ID╼                         │ ╾──────╼
            }
 
 note: erroneous constant used
-  --> $DIR/ub-wide-ptr.rs:83:40
+  --> $DIR/ub-wide-ptr.rs:84:40
    |
 LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
    |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:90:1
+  --> $DIR/ub-wide-ptr.rs:91:1
    |
 LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered 0x03, but expected a boolean
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
-               ╾──────allocN───────╼                         │ ╾──────╼
+               ╾ALLOC_ID╼                         │ ╾──────╼
            }
 
 note: erroneous constant used
-  --> $DIR/ub-wide-ptr.rs:90:42
+  --> $DIR/ub-wide-ptr.rs:91:42
    |
 LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
    |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:94:1
+  --> $DIR/ub-wide-ptr.rs:95:1
    |
 LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.1[0]: encountered 0x03, but expected a boolean
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
-               ╾──────allocN───────╼                         │ ╾──────╼
+               ╾ALLOC_ID╼                         │ ╾──────╼
            }
 
 note: erroneous constant used
-  --> $DIR/ub-wide-ptr.rs:94:42
+  --> $DIR/ub-wide-ptr.rs:95:42
    |
 LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
    |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:102:1
+  --> $DIR/ub-wide-ptr.rs:103:1
    |
 LL | const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:111:1
+  --> $DIR/ub-wide-ptr.rs:112:1
    |
 LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾──────allocN───────╼ ╾──────allocN───────╼ │ ╾──────╼╾──────╼
+               ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:115:1
+  --> $DIR/ub-wide-ptr.rs:116:1
    |
 LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾──────allocN───────╼ ╾──────allocN───────╼ │ ╾──────╼╾──────╼
+               ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:119:1
+  --> $DIR/ub-wide-ptr.rs:120:1
    |
 LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾──────allocN───────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
+               ╾ALLOC_ID╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
            }
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:122:57
+  --> $DIR/ub-wide-ptr.rs:123:57
    |
 LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) };
    |                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:125:57
+  --> $DIR/ub-wide-ptr.rs:126:57
    |
 LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) };
    |                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:128:56
+  --> $DIR/ub-wide-ptr.rs:129:56
    |
 LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) };
    |                                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:131:1
+  --> $DIR/ub-wide-ptr.rs:132:1
    |
 LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾──────allocN───────╼ ╾──────allocN───────╼ │ ╾──────╼╾──────╼
+               ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:136:1
+  --> $DIR/ub-wide-ptr.rs:137:1
    |
 LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾──────allocN───────╼ ╾──────allocN───────╼ │ ╾──────╼╾──────╼
+               ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:141:1
+  --> $DIR/ub-wide-ptr.rs:142:1
    |
 LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾──────allocN───────╼ 00 00 00 00 00 00 00 00 │ ╾──────╼........
+               ╾ALLOC_ID╼ 00 00 00 00 00 00 00 00 │ ╾──────╼........
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:143:1
+  --> $DIR/ub-wide-ptr.rs:144:1
    |
 LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered allocN, but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾──────allocN───────╼ ╾──────allocN───────╼ │ ╾──────╼╾──────╼
+               ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
            }
 
 error[E0080]: could not evaluate static initializer
-  --> $DIR/ub-wide-ptr.rs:149:5
+  --> $DIR/ub-wide-ptr.rs:150:5
    |
 LL |     mem::transmute::<_, &dyn Trait>((&92u8, 0usize))
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance)
 
 error[E0080]: could not evaluate static initializer
-  --> $DIR/ub-wide-ptr.rs:153:5
+  --> $DIR/ub-wide-ptr.rs:154:5
    |
 LL |     mem::transmute::<_, &dyn Trait>((&92u8, &3u64))
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
index 2894ef831884cda462a4acbf9bbd9d643bd9fb6d..d12e5e2bed93ef20daa6f5b98b4cb27b3920146a 100644 (file)
@@ -4,6 +4,7 @@
 
 use std::mem;
 
+// normalize-stderr-test "╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼" -> "╾ALLOC_ID$2╼"
 // normalize-stderr-test "offset \d+" -> "offset N"
 // normalize-stderr-test "alloc\d+" -> "allocN"
 // normalize-stderr-test "size \d+" -> "size N"
index 249bbb5991cc98dc6da6f19feff3bdb06b4bff36..94d7bdc6bae9ff6222411821a5a3b912f6728fbf 100644 (file)
@@ -17,7 +17,7 @@
     // Since we are not copying anything, this should be allowed.
     let src = ();
     let mut dst = ();
-    copy_nonoverlapping(&src as *const _ as *const i32, &mut dst as *mut _ as *mut i32, 0);
+    copy_nonoverlapping(&src as *const _ as *const u8, &mut dst as *mut _ as *mut u8, 0);
 };
 
 const COPY_OOB_1: () = unsafe {
index 9c239c8a100f991e60176a3364a15478940bf252..e2f8149883b1d980978e431889112462f1dd4e85 100644 (file)
     //[with_flag]~| invalid value
 };
 
-const UNALIGNED_READ: () = {
-    INNER; //[with_flag]~ constant
-    // There is an error here but its span is in the standard library so we cannot match it...
-    // so we have this in a *nested* const, such that the *outer* const fails to use it.
-    const INNER: () = unsafe {
-        let x = &[0u8; 4];
-        let ptr = x.as_ptr().cast::<u32>();
-        ptr.read();
-    };
-};
-
 fn main() {}
index 51eec78336565ac9b518ff1b1c875507f74be822..b2a5fd90149a3eee815afc6625507556b9a01c45 100644 (file)
@@ -28,27 +28,6 @@ error[E0080]: evaluation of constant value failed
 LL |     let _x: &u32 = transmute(&[0u8; 4]);
    |                    ^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 4 byte alignment but found 1)
 
-error[E0080]: evaluation of constant value failed
-  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-   |
-   = note: accessing memory with alignment 1, but alignment 4 is required
-   |
-note: inside `std::ptr::read::<u32>`
-  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-note: inside `ptr::const_ptr::<impl *const u32>::read`
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `INNER`
-  --> $DIR/detect-extra-ub.rs:38:9
-   |
-LL |         ptr.read();
-   |         ^^^^^^^^^^
-
-note: erroneous constant used
-  --> $DIR/detect-extra-ub.rs:32:5
-   |
-LL |     INNER;
-   |     ^^^^^
-
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
index c447e2f7987cc869c64127a8e984e2ad3f55a8c9..3e39d15f9b0cd3e665c7ab133de94995f189314c 100644 (file)
@@ -8,3 +8,4 @@ LL |     let ft =
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0320`.
index cd4706dd903f41612be335cb2259a38f6978008c..dbb74354471385a053ebb957dc187ca2064afea0 100644 (file)
@@ -8,3 +8,4 @@ LL |     let ft =
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0320`.
index 18cd1b6cd413ba42b0d1e9dd79ebe194df12cc94..deaf116b647afe421a327ecc5c7472225f21a87c 100644 (file)
@@ -16,3 +16,4 @@ LL |         Some(Wrapper::Simple::<u32>);
 
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0320`.
diff --git a/src/test/ui/dyn-star/dyn-to-rigid.rs b/src/test/ui/dyn-star/dyn-to-rigid.rs
new file mode 100644 (file)
index 0000000..e80ee15
--- /dev/null
@@ -0,0 +1,11 @@
+#![feature(dyn_star)]
+#![allow(incomplete_features)]
+
+trait Tr {}
+
+fn f(x: dyn* Tr) -> usize {
+    x as usize
+    //~^ ERROR casting `(dyn* Tr + 'static)` as `usize` is invalid
+}
+
+fn main() {}
diff --git a/src/test/ui/dyn-star/dyn-to-rigid.stderr b/src/test/ui/dyn-star/dyn-to-rigid.stderr
new file mode 100644 (file)
index 0000000..588e6d9
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0606]: casting `(dyn* Tr + 'static)` as `usize` is invalid
+  --> $DIR/dyn-to-rigid.rs:7:5
+   |
+LL |     x as usize
+   |     ^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0606`.
index e1a7a02a56869ad056ca3a15f05c57805b31c2eb..0e580aedeaa921e7fd548624dc075a660864600d 100644 (file)
@@ -100,22 +100,22 @@ help: a unit struct with a similar name exists
 LL |     let xe1 = XEmpty2();
    |               ~~~~~~~
 
-error[E0599]: no variant or associated item named `Empty3` found for enum `empty_struct::XE` in the current scope
+error[E0599]: no variant or associated item named `Empty3` found for enum `XE` in the current scope
   --> $DIR/empty-struct-braces-expr.rs:25:19
    |
 LL |     let xe3 = XE::Empty3;
    |                   ^^^^^^
    |                   |
-   |                   variant or associated item not found in `empty_struct::XE`
+   |                   variant or associated item not found in `XE`
    |                   help: there is a variant with a similar name: `XEmpty3`
 
-error[E0599]: no variant or associated item named `Empty3` found for enum `empty_struct::XE` in the current scope
+error[E0599]: no variant or associated item named `Empty3` found for enum `XE` in the current scope
   --> $DIR/empty-struct-braces-expr.rs:26:19
    |
 LL |     let xe3 = XE::Empty3();
    |                   ^^^^^^
    |                   |
-   |                   variant or associated item not found in `empty_struct::XE`
+   |                   variant or associated item not found in `XE`
    |                   help: there is a variant with a similar name: `XEmpty3`
 
 error[E0599]: no variant named `Empty1` found for enum `empty_struct::XE`
index bea226f09dcb9186bba62843099c1aac454b889e..163737895fea2219c7cd6b70687f3bd7ecd78abc 100644 (file)
@@ -11,8 +11,8 @@ LL |     let f = |x| x * 3;
    |             ^^^
 help: provide the argument
    |
-LL |     let a = f(/* value */);
-   |              ~~~~~~~~~~~~~
+LL |     let a = f(/* x */);
+   |              ~~~~~~~~~
 
 error[E0057]: this function takes 1 argument but 2 arguments were supplied
   --> $DIR/E0057.rs:5:13
diff --git a/src/test/ui/error-codes/E0377.rs b/src/test/ui/error-codes/E0377.rs
new file mode 100644 (file)
index 0000000..6da2c20
--- /dev/null
@@ -0,0 +1,14 @@
+#![feature(coerce_unsized)]
+use std::ops::CoerceUnsized;
+
+pub struct Foo<T: ?Sized> {
+    field_with_unsized_type: T,
+}
+
+pub struct Bar<T: ?Sized> {
+    field_with_unsized_type: T,
+}
+
+impl<T, U> CoerceUnsized<Bar<U>> for Foo<T> where T: CoerceUnsized<U> {} //~ ERROR E0377
+
+fn main() {}
diff --git a/src/test/ui/error-codes/E0377.stderr b/src/test/ui/error-codes/E0377.stderr
new file mode 100644 (file)
index 0000000..bf7d8c8
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0377]: the trait `CoerceUnsized` may only be implemented for a coercion between structures with the same definition; expected `Foo`, found `Bar`
+  --> $DIR/E0377.rs:12:1
+   |
+LL | impl<T, U> CoerceUnsized<Bar<U>> for Foo<T> where T: CoerceUnsized<U> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0377`.
index f68c0e7d220f369d4409d59e26baa99ecd954b7d..fc025a3fca2bfc47b4df9629ee8145e907878550 100644 (file)
@@ -37,8 +37,8 @@ LL |     inner::MyTrait::my_fn();
    |
 help: use the fully-qualified path to the only available implementation
    |
-LL |     inner::<MyStruct as MyTrait>::my_fn();
-   |            ++++++++++++        +
+LL |     <MyStruct as inner::MyTrait>::my_fn();
+   |     ++++++++++++               +
 
 error[E0790]: cannot refer to the associated constant on trait without specifying the corresponding `impl` type
   --> $DIR/E0790.rs:30:13
@@ -51,8 +51,8 @@ LL |     let _ = inner::MyTrait::MY_ASSOC_CONST;
    |
 help: use the fully-qualified path to the only available implementation
    |
-LL |     let _ = inner::<MyStruct as MyTrait>::MY_ASSOC_CONST;
-   |                    ++++++++++++        +
+LL |     let _ = <MyStruct as inner::MyTrait>::MY_ASSOC_CONST;
+   |             ++++++++++++               +
 
 error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type
   --> $DIR/E0790.rs:50:5
index 9b868ed7a9e93868b712ac46ca19482e99839947..c04e57843d4b21f4d16e5205630273d4f199cc37 100644 (file)
@@ -1,5 +1,5 @@
+#![allow(unused, bare_trait_objects)]
 #[repr(align(256))]
-#[allow(dead_code)]
 struct A {
     v: u8,
 }
@@ -14,13 +14,17 @@ fn foo(&self) {
     }
 }
 
-fn foo(x: dyn Foo) {
-    //~^ ERROR [E0277]
+fn foo(x: dyn Foo) { //~ ERROR [E0277]
     x.foo()
 }
 
+fn bar(x: Foo) { //~ ERROR [E0277]
+    x.foo()
+}
+
+fn qux(_: [()]) {} //~ ERROR [E0277]
+
 fn main() {
     let x: Box<dyn Foo> = Box::new(A { v: 22 });
-    foo(*x);
-    //~^ ERROR [E0277]
+    foo(*x); //~ ERROR [E0277]
 }
index 0f7520ef7f8a95a80644466eedf36a0a5902a143..92c71392672e197537c6a72525b9059a31c19852 100644 (file)
@@ -6,13 +6,47 @@ LL | fn foo(x: dyn Foo) {
    |
    = help: the trait `Sized` is not implemented for `(dyn Foo + 'static)`
    = help: unsized fn params are gated as an unstable feature
+help: you can use `impl Trait` as the argument type
+   |
+LL | fn foo(x: impl Foo) {
+   |           ~~~~
 help: function arguments must have a statically known size, borrowed types always have a known size
    |
 LL | fn foo(x: &dyn Foo) {
    |           +
 
 error[E0277]: the size for values of type `(dyn Foo + 'static)` cannot be known at compilation time
-  --> $DIR/feature-gate-unsized_fn_params.rs:24:9
+  --> $DIR/feature-gate-unsized_fn_params.rs:21:8
+   |
+LL | fn bar(x: Foo) {
+   |        ^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `(dyn Foo + 'static)`
+   = help: unsized fn params are gated as an unstable feature
+help: you can use `impl Trait` as the argument type
+   |
+LL | fn bar(x: impl Foo) {
+   |           ++++
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn bar(x: &Foo) {
+   |           +
+
+error[E0277]: the size for values of type `[()]` cannot be known at compilation time
+  --> $DIR/feature-gate-unsized_fn_params.rs:25:8
+   |
+LL | fn qux(_: [()]) {}
+   |        ^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[()]`
+   = help: unsized fn params are gated as an unstable feature
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn qux(_: &[()]) {}
+   |           +
+
+error[E0277]: the size for values of type `(dyn Foo + 'static)` cannot be known at compilation time
+  --> $DIR/feature-gate-unsized_fn_params.rs:29:9
    |
 LL |     foo(*x);
    |         ^^ doesn't have a size known at compile-time
@@ -21,6 +55,6 @@ LL |     foo(*x);
    = note: all function arguments must have a statically known size
    = help: unsized fn params are gated as an unstable feature
 
-error: aborting due to 2 previous errors
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
index c4507843e366e06896824d284114ac97951075ed..9aeeb88cf04f2befd08f101afdb57860769e220d 100644 (file)
@@ -6,6 +6,10 @@ LL | fn f(f: dyn FnOnce()) {}
    |
    = help: the trait `Sized` is not implemented for `(dyn FnOnce() + 'static)`
    = help: unsized fn params are gated as an unstable feature
+help: you can use `impl Trait` as the argument type
+   |
+LL | fn f(f: impl FnOnce()) {}
+   |         ~~~~
 help: function arguments must have a statically known size, borrowed types always have a known size
    |
 LL | fn f(f: &dyn FnOnce()) {}
index 2296666219eef2fbb284e11e7699db91b4adb20d..463ac7684ecdfea3a73122953e24915249278b66 100644 (file)
@@ -17,11 +17,11 @@ note: `Bar` defines an item `bar`, perhaps you need to implement it
 LL | trait Bar {
    | ^^^^^^^^^
 
-error[E0599]: no method named `bar` found for struct `Arc<[closure@$DIR/fn-help-with-err.rs:22:36: 22:38]>` in the current scope
+error[E0599]: no method named `bar` found for struct `Arc<[closure@fn-help-with-err.rs:22:36]>` in the current scope
   --> $DIR/fn-help-with-err.rs:23:10
    |
 LL |     arc2.bar();
-   |          ^^^ method not found in `Arc<[closure@$DIR/fn-help-with-err.rs:22:36: 22:38]>`
+   |          ^^^ method not found in `Arc<[closure@fn-help-with-err.rs:22:36]>`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `Bar` defines an item `bar`, perhaps you need to implement it
diff --git a/src/test/ui/generator/ref-upvar-not-send.rs b/src/test/ui/generator/ref-upvar-not-send.rs
new file mode 100644 (file)
index 0000000..eb9ef63
--- /dev/null
@@ -0,0 +1,31 @@
+// For `Send` generators, suggest a `T: Sync` requirement for `&T` upvars,
+// and suggest a `T: Send` requirement for `&mut T` upvars.
+
+#![feature(generators)]
+
+fn assert_send<T: Send>(_: T) {}
+//~^ NOTE required by a bound in `assert_send`
+//~| NOTE required by this bound in `assert_send`
+//~| NOTE required by a bound in `assert_send`
+//~| NOTE required by this bound in `assert_send`
+
+fn main() {
+    let x: &*mut () = &std::ptr::null_mut();
+    let y: &mut *mut () = &mut std::ptr::null_mut();
+    assert_send(move || {
+        //~^ ERROR generator cannot be sent between threads safely
+        //~| NOTE generator is not `Send`
+        yield;
+        let _x = x;
+    });
+    //~^^ NOTE captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync`
+    //~| NOTE has type `&*mut ()` which is not `Send`, because `*mut ()` is not `Sync`
+    assert_send(move || {
+        //~^ ERROR generator cannot be sent between threads safely
+        //~| NOTE generator is not `Send`
+        yield;
+        let _y = y;
+    });
+    //~^^ NOTE captured value is not `Send` because `&mut` references cannot be sent unless their referent is `Send`
+    //~| NOTE has type `&mut *mut ()` which is not `Send`, because `*mut ()` is not `Send`
+}
diff --git a/src/test/ui/generator/ref-upvar-not-send.stderr b/src/test/ui/generator/ref-upvar-not-send.stderr
new file mode 100644 (file)
index 0000000..689ace6
--- /dev/null
@@ -0,0 +1,50 @@
+error: generator cannot be sent between threads safely
+  --> $DIR/ref-upvar-not-send.rs:15:17
+   |
+LL |       assert_send(move || {
+   |  _________________^
+LL | |
+LL | |
+LL | |         yield;
+LL | |         let _x = x;
+LL | |     });
+   | |_____^ generator is not `Send`
+   |
+   = help: the trait `Sync` is not implemented for `*mut ()`
+note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync`
+  --> $DIR/ref-upvar-not-send.rs:19:18
+   |
+LL |         let _x = x;
+   |                  ^ has type `&*mut ()` which is not `Send`, because `*mut ()` is not `Sync`
+note: required by a bound in `assert_send`
+  --> $DIR/ref-upvar-not-send.rs:6:19
+   |
+LL | fn assert_send<T: Send>(_: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+
+error: generator cannot be sent between threads safely
+  --> $DIR/ref-upvar-not-send.rs:23:17
+   |
+LL |       assert_send(move || {
+   |  _________________^
+LL | |
+LL | |
+LL | |         yield;
+LL | |         let _y = y;
+LL | |     });
+   | |_____^ generator is not `Send`
+   |
+   = help: within `[generator@$DIR/ref-upvar-not-send.rs:23:17: 23:24]`, the trait `Send` is not implemented for `*mut ()`
+note: captured value is not `Send` because `&mut` references cannot be sent unless their referent is `Send`
+  --> $DIR/ref-upvar-not-send.rs:27:18
+   |
+LL |         let _y = y;
+   |                  ^ has type `&mut *mut ()` which is not `Send`, because `*mut ()` is not `Send`
+note: required by a bound in `assert_send`
+  --> $DIR/ref-upvar-not-send.rs:6:19
+   |
+LL | fn assert_send<T: Send>(_: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+
+error: aborting due to 2 previous errors
+
index d1d76916b263905045a0d398206cff93e75040ef..0458d2535f2f56ad83eac2b0d3be6ceaaf28c22b 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: the method `filterx` exists for struct `Map<Repeat, [closure@$DIR/issue-30786.rs:117:27: 117:34]>`, but its trait bounds were not satisfied
+error[E0599]: the method `filterx` exists for struct `Map<Repeat, [closure@issue-30786.rs:117:27]>`, but its trait bounds were not satisfied
   --> $DIR/issue-30786.rs:118:22
    |
 LL | pub struct Map<S, F> {
@@ -8,7 +8,7 @@ LL | pub struct Map<S, F> {
    | doesn't satisfy `_: StreamExt`
 ...
 LL |     let filter = map.filterx(|x: &_| true);
-   |                      ^^^^^^^ method cannot be called due to unsatisfied trait bounds
+   |                      ^^^^^^^ method cannot be called on `Map<Repeat, [closure@issue-30786.rs:117:27]>` due to unsatisfied trait bounds
    |
 note: the following trait bounds were not satisfied:
       `&'a mut &Map<Repeat, [closure@$DIR/issue-30786.rs:117:27: 117:34]>: Stream`
@@ -19,7 +19,7 @@ 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
 
-error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>`, but its trait bounds were not satisfied
+error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, [closure@issue-30786.rs:129:30]>`, but its trait bounds were not satisfied
   --> $DIR/issue-30786.rs:130:24
    |
 LL | pub struct Filter<S, F> {
index 09e25f4dc9668eb226a675d56e09e3c637c945a2..0f051be2128b0486cfcda81f474e94ac8f563db3 100644 (file)
@@ -11,8 +11,8 @@ LL | fn f<I>(i: I)
    |    ^    ----
 help: provide the argument
    |
-LL |     f(&[f(/* value */)]);
-   |          ~~~~~~~~~~~~~
+LL |     f(&[f(/* i */)]);
+   |          ~~~~~~~~~
 
 error: aborting due to previous error
 
index ab5598e364fc4f522b95e66080a7196a1c0cba93..fdd192f43137067a274ebe008c03d2641a9fad0b 100644 (file)
@@ -30,7 +30,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]: expected `[closure@$DIR/issue-62203-hrtb-ice.rs:42:16: 42:19]` to be a closure that returns `Unit3`, but it returns `Unit4`
+error[E0271]: expected `[closure@issue-62203-hrtb-ice.rs:42:16]` to be a closure that returns `Unit3`, but it returns `Unit4`
   --> $DIR/issue-62203-hrtb-ice.rs:39:9
    |
 LL |       let v = Unit2.m(
index f90399b6b945888bad12c687d671387595b81093..7f73d5e12d1962a9288eb62d472d632b983b1ae4 100644 (file)
@@ -70,10 +70,6 @@ error[E0746]: return type cannot have an unboxed trait object
 LL | fn bak() -> dyn Trait { unimplemented!() }
    |             ^^^^^^^^^ doesn't have a size known at compile-time
    |
-help: use some type `T` that is `T: Sized` as the return type if all return paths have the same type
-   |
-LL | fn bak() -> T { unimplemented!() }
-   |             ~
 help: use `impl Trait` as the return type if all return paths have the same type but you want to expose only the trait in the signature
    |
 LL | fn bak() -> impl Trait { unimplemented!() }
index 3d4ae11e5767039ab3659d58f60c79c32545ad86..548c89d0a3871372e87270fd08b5ad3b2e1421a4 100644 (file)
@@ -145,11 +145,11 @@ note: `foo::Bar` defines an item `method2`, perhaps you need to implement it
 LL |     pub trait Bar {
    |     ^^^^^^^^^^^^^
 
-error[E0599]: no method named `method2` found for struct `no_method_suggested_traits::Foo` in the current scope
+error[E0599]: no method named `method2` found for struct `Foo` in the current scope
   --> $DIR/no-method-suggested-traits.rs:50:37
    |
 LL |     no_method_suggested_traits::Foo.method2();
-   |                                     ^^^^^^^ method not found in `no_method_suggested_traits::Foo`
+   |                                     ^^^^^^^ method not found in `Foo`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `foo::Bar` defines an item `method2`, perhaps you need to implement it
@@ -158,11 +158,11 @@ note: `foo::Bar` defines an item `method2`, perhaps you need to implement it
 LL |     pub trait Bar {
    |     ^^^^^^^^^^^^^
 
-error[E0599]: no method named `method2` found for struct `Rc<&mut Box<&no_method_suggested_traits::Foo>>` in the current scope
+error[E0599]: no method named `method2` found for struct `Rc<&mut Box<&Foo>>` in the current scope
   --> $DIR/no-method-suggested-traits.rs:52:71
    |
 LL |     std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Foo)).method2();
-   |                                                                       ^^^^^^^ method not found in `Rc<&mut Box<&no_method_suggested_traits::Foo>>`
+   |                                                                       ^^^^^^^ method not found in `Rc<&mut Box<&Foo>>`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `foo::Bar` defines an item `method2`, perhaps you need to implement it
@@ -171,11 +171,11 @@ note: `foo::Bar` defines an item `method2`, perhaps you need to implement it
 LL |     pub trait Bar {
    |     ^^^^^^^^^^^^^
 
-error[E0599]: no method named `method2` found for enum `no_method_suggested_traits::Bar` in the current scope
+error[E0599]: no method named `method2` found for enum `Bar` in the current scope
   --> $DIR/no-method-suggested-traits.rs:54:40
    |
 LL |     no_method_suggested_traits::Bar::X.method2();
-   |                                        ^^^^^^^ method not found in `no_method_suggested_traits::Bar`
+   |                                        ^^^^^^^ method not found in `Bar`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `foo::Bar` defines an item `method2`, perhaps you need to implement it
@@ -184,11 +184,11 @@ note: `foo::Bar` defines an item `method2`, perhaps you need to implement it
 LL |     pub trait Bar {
    |     ^^^^^^^^^^^^^
 
-error[E0599]: no method named `method2` found for struct `Rc<&mut Box<&no_method_suggested_traits::Bar>>` in the current scope
+error[E0599]: no method named `method2` found for struct `Rc<&mut Box<&Bar>>` in the current scope
   --> $DIR/no-method-suggested-traits.rs:56:74
    |
 LL |     std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Bar::X)).method2();
-   |                                                                          ^^^^^^^ method not found in `Rc<&mut Box<&no_method_suggested_traits::Bar>>`
+   |                                                                          ^^^^^^^ method not found in `Rc<&mut Box<&Bar>>`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `foo::Bar` defines an item `method2`, perhaps you need to implement it
@@ -255,29 +255,29 @@ error[E0599]: no method named `method3` found for struct `Rc<&mut Box<&usize>>`
 LL |     std::rc::Rc::new(&mut Box::new(&1_usize)).method3();
    |                                               ^^^^^^^ method not found in `Rc<&mut Box<&usize>>`
 
-error[E0599]: no method named `method3` found for struct `no_method_suggested_traits::Foo` in the current scope
+error[E0599]: no method named `method3` found for struct `Foo` in the current scope
   --> $DIR/no-method-suggested-traits.rs:71:37
    |
 LL |     no_method_suggested_traits::Foo.method3();
-   |                                     ^^^^^^^ method not found in `no_method_suggested_traits::Foo`
+   |                                     ^^^^^^^ method not found in `Foo`
 
-error[E0599]: no method named `method3` found for struct `Rc<&mut Box<&no_method_suggested_traits::Foo>>` in the current scope
+error[E0599]: no method named `method3` found for struct `Rc<&mut Box<&Foo>>` in the current scope
   --> $DIR/no-method-suggested-traits.rs:72:71
    |
 LL |     std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Foo)).method3();
-   |                                                                       ^^^^^^^ method not found in `Rc<&mut Box<&no_method_suggested_traits::Foo>>`
+   |                                                                       ^^^^^^^ method not found in `Rc<&mut Box<&Foo>>`
 
-error[E0599]: no method named `method3` found for enum `no_method_suggested_traits::Bar` in the current scope
+error[E0599]: no method named `method3` found for enum `Bar` in the current scope
   --> $DIR/no-method-suggested-traits.rs:74:40
    |
 LL |     no_method_suggested_traits::Bar::X.method3();
-   |                                        ^^^^^^^ method not found in `no_method_suggested_traits::Bar`
+   |                                        ^^^^^^^ method not found in `Bar`
 
-error[E0599]: no method named `method3` found for struct `Rc<&mut Box<&no_method_suggested_traits::Bar>>` in the current scope
+error[E0599]: no method named `method3` found for struct `Rc<&mut Box<&Bar>>` in the current scope
   --> $DIR/no-method-suggested-traits.rs:75:74
    |
 LL |     std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Bar::X)).method3();
-   |                                                                          ^^^^^^^ method not found in `Rc<&mut Box<&no_method_suggested_traits::Bar>>`
+   |                                                                          ^^^^^^^ method not found in `Rc<&mut Box<&Bar>>`
 
 error: aborting due to 24 previous errors
 
diff --git a/src/test/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.rs b/src/test/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.rs
new file mode 100644 (file)
index 0000000..6ccbb5b
--- /dev/null
@@ -0,0 +1,22 @@
+#![deny(implied_bounds_entailment)]
+
+trait Project {
+    type Ty;
+}
+impl Project for &'_ &'_ () {
+    type Ty = ();
+}
+trait Trait {
+    fn get<'s>(s: &'s str, _: ()) -> &'static str;
+}
+impl Trait for () {
+    fn get<'s>(s: &'s str, _: <&'static &'s () as Project>::Ty) -> &'static str {
+        //~^ ERROR impl method assumes more implied bounds than the corresponding trait method
+        //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+        s
+    }
+}
+fn main() {
+    let val = <() as Trait>::get(&String::from("blah blah blah"), ());
+    println!("{}", val);
+}
diff --git a/src/test/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.stderr b/src/test/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.stderr
new file mode 100644 (file)
index 0000000..0ac31c6
--- /dev/null
@@ -0,0 +1,16 @@
+error: impl method assumes more implied bounds than the corresponding trait method
+  --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:13:5
+   |
+LL |     fn get<'s>(s: &'s str, _: <&'static &'s () as Project>::Ty) -> &'static str {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 #105572 <https://github.com/rust-lang/rust/issues/105572>
+note: the lint level is defined here
+  --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:1:9
+   |
+LL | #![deny(implied_bounds_entailment)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/implied-bounds/impl-implied-bounds-compatibility.rs b/src/test/ui/implied-bounds/impl-implied-bounds-compatibility.rs
new file mode 100644 (file)
index 0000000..d097bc1
--- /dev/null
@@ -0,0 +1,21 @@
+#![deny(implied_bounds_entailment)]
+
+use std::cell::RefCell;
+
+pub struct MessageListeners<'a> {
+    listeners: RefCell<Vec<Box<dyn FnMut(()) + 'a>>>,
+}
+
+pub trait MessageListenersInterface {
+    fn listeners<'c>(&'c self) -> &'c MessageListeners<'c>;
+}
+
+impl<'a> MessageListenersInterface for MessageListeners<'a> {
+    fn listeners<'b>(&'b self) -> &'a MessageListeners<'b> {
+        //~^ ERROR impl method assumes more implied bounds than the corresponding trait method
+        //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+        self
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/implied-bounds/impl-implied-bounds-compatibility.stderr b/src/test/ui/implied-bounds/impl-implied-bounds-compatibility.stderr
new file mode 100644 (file)
index 0000000..0dfa816
--- /dev/null
@@ -0,0 +1,16 @@
+error: impl method assumes more implied bounds than the corresponding trait method
+  --> $DIR/impl-implied-bounds-compatibility.rs:14:5
+   |
+LL |     fn listeners<'b>(&'b self) -> &'a MessageListeners<'b> {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 #105572 <https://github.com/rust-lang/rust/issues/105572>
+note: the lint level is defined here
+  --> $DIR/impl-implied-bounds-compatibility.rs:1:9
+   |
+LL | #![deny(implied_bounds_entailment)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/inference/issue-80816.rs b/src/test/ui/inference/issue-80816.rs
new file mode 100644 (file)
index 0000000..ead320a
--- /dev/null
@@ -0,0 +1,54 @@
+#![allow(unreachable_code)]
+
+use std::marker::PhantomData;
+use std::ops::Deref;
+use std::sync::Arc;
+
+pub struct Guard<T> {
+    _phantom: PhantomData<T>,
+}
+impl<T> Deref for Guard<T> {
+    type Target = T;
+    fn deref(&self) -> &T {
+        unimplemented!()
+    }
+}
+
+pub struct DirectDeref<T>(T);
+impl<T> Deref for DirectDeref<Arc<T>> {
+    type Target = T;
+    fn deref(&self) -> &T {
+        unimplemented!()
+    }
+}
+
+pub trait Access<T> {
+    type Guard: Deref<Target = T>;
+    fn load(&self) -> Self::Guard {
+        unimplemented!()
+    }
+}
+impl<T, A: Access<T>, P: Deref<Target = A>> Access<T> for P {
+    //~^ NOTE: required for `Arc<ArcSwapAny<Arc<usize>>>` to implement `Access<_>`
+    type Guard = A::Guard;
+}
+impl<T> Access<T> for ArcSwapAny<T> {
+    //~^ NOTE: multiple `impl`s satisfying `ArcSwapAny<Arc<usize>>: Access<_>` found
+    type Guard = Guard<T>;
+}
+impl<T> Access<T> for ArcSwapAny<Arc<T>> {
+    type Guard = DirectDeref<Arc<T>>;
+}
+
+pub struct ArcSwapAny<T> {
+    _phantom_arc: PhantomData<T>,
+}
+
+pub fn foo() {
+    let s: Arc<ArcSwapAny<Arc<usize>>> = unimplemented!();
+    let guard: Guard<Arc<usize>> = s.load();
+    //~^ ERROR: type annotations needed
+    //~| HELP: try using a fully qualified path to specify the expected types
+}
+
+fn main() {}
diff --git a/src/test/ui/inference/issue-80816.stderr b/src/test/ui/inference/issue-80816.stderr
new file mode 100644 (file)
index 0000000..bd83334
--- /dev/null
@@ -0,0 +1,27 @@
+error[E0283]: type annotations needed
+  --> $DIR/issue-80816.rs:49:38
+   |
+LL |     let guard: Guard<Arc<usize>> = s.load();
+   |                                      ^^^^
+   |
+note: multiple `impl`s satisfying `ArcSwapAny<Arc<usize>>: Access<_>` found
+  --> $DIR/issue-80816.rs:35:1
+   |
+LL | impl<T> Access<T> for ArcSwapAny<T> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl<T> Access<T> for ArcSwapAny<Arc<T>> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: required for `Arc<ArcSwapAny<Arc<usize>>>` to implement `Access<_>`
+  --> $DIR/issue-80816.rs:31:45
+   |
+LL | impl<T, A: Access<T>, P: Deref<Target = A>> Access<T> for P {
+   |                                             ^^^^^^^^^     ^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     let guard: Guard<Arc<usize>> = <Arc<ArcSwapAny<Arc<usize>>> as Access<T>>::load(&s);
+   |                                    ++++++++++++++++++++++++++++++++++++++++++++++++++ ~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/src/test/ui/infinite/issue-41731-infinite-macro-print.rs b/src/test/ui/infinite/issue-41731-infinite-macro-print.rs
new file mode 100644 (file)
index 0000000..d52e6e7
--- /dev/null
@@ -0,0 +1,15 @@
+// compile-flags: -Z trace-macros
+
+#![recursion_limit = "5"]
+
+fn main() {
+    macro_rules! stack {
+        ($overflow:expr) => {
+            print!(stack!($overflow));
+            //~^ ERROR recursion limit reached while expanding
+            //~| ERROR format argument must be a string literal
+        };
+    }
+
+    stack!("overflow");
+}
diff --git a/src/test/ui/infinite/issue-41731-infinite-macro-print.stderr b/src/test/ui/infinite/issue-41731-infinite-macro-print.stderr
new file mode 100644 (file)
index 0000000..e30b203
--- /dev/null
@@ -0,0 +1,38 @@
+error: recursion limit reached while expanding `$crate::format_args!`
+  --> $DIR/issue-41731-infinite-macro-print.rs:14:5
+   |
+LL |     stack!("overflow");
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "10"]` attribute to your crate (`issue_41731_infinite_macro_print`)
+   = note: this error originates in the macro `print` which comes from the expansion of the macro `stack` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: trace_macro
+  --> $DIR/issue-41731-infinite-macro-print.rs:14:5
+   |
+LL |     stack!("overflow");
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = note: expanding `stack! { "overflow" }`
+   = note: to `print! (stack! ("overflow")) ;`
+   = note: expanding `print! { stack! ("overflow") }`
+   = note: to `{ $crate :: io :: _print($crate :: format_args! (stack! ("overflow"))) ; }`
+   = note: expanding `stack! { "overflow" }`
+   = note: to `print! (stack! ("overflow")) ;`
+   = note: expanding `print! { stack! ("overflow") }`
+   = note: to `{ $crate :: io :: _print($crate :: format_args! (stack! ("overflow"))) ; }`
+
+error: format argument must be a string literal
+  --> $DIR/issue-41731-infinite-macro-print.rs:14:5
+   |
+LL |     stack!("overflow");
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = note: this error originates in the macro `print` which comes from the expansion of the macro `stack` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: you might be missing a string literal to format with
+   |
+LL |             print!("{}", stack!($overflow));
+   |                    +++++
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/infinite/issue-41731-infinite-macro-println.rs b/src/test/ui/infinite/issue-41731-infinite-macro-println.rs
new file mode 100644 (file)
index 0000000..3c2b7ee
--- /dev/null
@@ -0,0 +1,15 @@
+// compile-flags: -Z trace-macros
+
+#![recursion_limit = "5"]
+
+fn main() {
+    macro_rules! stack {
+        ($overflow:expr) => {
+            println!(stack!($overflow));
+            //~^ ERROR recursion limit reached while expanding
+            //~| ERROR format argument must be a string literal
+        };
+    }
+
+    stack!("overflow");
+}
diff --git a/src/test/ui/infinite/issue-41731-infinite-macro-println.stderr b/src/test/ui/infinite/issue-41731-infinite-macro-println.stderr
new file mode 100644 (file)
index 0000000..66b466d
--- /dev/null
@@ -0,0 +1,38 @@
+error: recursion limit reached while expanding `$crate::format_args_nl!`
+  --> $DIR/issue-41731-infinite-macro-println.rs:14:5
+   |
+LL |     stack!("overflow");
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "10"]` attribute to your crate (`issue_41731_infinite_macro_println`)
+   = note: this error originates in the macro `println` which comes from the expansion of the macro `stack` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: trace_macro
+  --> $DIR/issue-41731-infinite-macro-println.rs:14:5
+   |
+LL |     stack!("overflow");
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = note: expanding `stack! { "overflow" }`
+   = note: to `println! (stack! ("overflow")) ;`
+   = note: expanding `println! { stack! ("overflow") }`
+   = note: to `{ $crate :: io :: _print($crate :: format_args_nl! (stack! ("overflow"))) ; }`
+   = note: expanding `stack! { "overflow" }`
+   = note: to `println! (stack! ("overflow")) ;`
+   = note: expanding `println! { stack! ("overflow") }`
+   = note: to `{ $crate :: io :: _print($crate :: format_args_nl! (stack! ("overflow"))) ; }`
+
+error: format argument must be a string literal
+  --> $DIR/issue-41731-infinite-macro-println.rs:14:5
+   |
+LL |     stack!("overflow");
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = note: this error originates in the macro `println` which comes from the expansion of the macro `stack` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: you might be missing a string literal to format with
+   |
+LL |             println!("{}", stack!($overflow));
+   |                      +++++
+
+error: aborting due to 2 previous errors
+
index 6bd9c6a0276f835418eaa0e7966390403e7ec22f..52a5919026463074199f87a216e1f8fc98723f15 100644 (file)
@@ -1,4 +1,4 @@
-error: -Zbranch-protection is only supported on aarch64
+error: `-Zbranch-protection` is only supported on aarch64
 
 error: aborting due to previous error
 
index 4bc4919bc935b2c8a61fc808ae27e1e4292cb068..1d7ec5cba17ca71ebf37a4478771d1836918e2a8 100644 (file)
@@ -3,7 +3,7 @@
 // [BADFLAGS] check-fail
 // [BADFLAGS] needs-llvm-components: aarch64
 // [BADTARGET] compile-flags: --target=x86_64-unknown-linux-gnu -Zbranch-protection=bti
-// [BADTARGET] build-fail
+// [BADTARGET] check-fail
 // [BADTARGET] needs-llvm-components: x86
 
 #![crate_type = "lib"]
index 28478457b296db68779f5227322583c657f518b9..1669b550a9bafe26442e406d91bb02a980d135e7 100644 (file)
@@ -4,10 +4,6 @@ error[E0746]: return type cannot have an unboxed trait object
 LL |     dyn AbstractRenderer
    |     ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-help: use some type `T` that is `T: Sized` as the return type if all return paths have the same type
-   |
-LL |     T
-   |
 help: use `impl AbstractRenderer` as the return type if all return paths have the same type but you want to expose only the trait in the signature
    |
 LL |     impl AbstractRenderer
index e9d934332f171f6402a5f296c5bc780903aef40a..7808cbf8aa10840644bb7e85e8c9a81045adb8fc 100644 (file)
@@ -1,8 +1,8 @@
-error[E0599]: no function or associated item named `new_undirected` found for struct `issue_30123_aux::Graph<i32, i32>` in the current scope
+error[E0599]: no function or associated item named `new_undirected` found for struct `Graph<i32, i32>` in the current scope
   --> $DIR/issue-30123.rs:7:33
    |
 LL |     let ug = Graph::<i32, i32>::new_undirected();
-   |                                 ^^^^^^^^^^^^^^ function or associated item not found in `issue_30123_aux::Graph<i32, i32>`
+   |                                 ^^^^^^^^^^^^^^ function or associated item not found in `Graph<i32, i32>`
    |
    = note: the function or associated item was found for
            - `issue_30123_aux::Graph<N, E, Undirected>`
index 2b142f688ecb9dcc8b844d6840767393999bc579..1232b83c39171af52a5702476cc7823ef1e50816 100644 (file)
@@ -13,7 +13,7 @@ help: provide the argument
    |
 LL ~     needlesArr.iter().fold(|x, y| {
 LL +
-LL ~     }, /* value */);
+LL ~     }, /* f */);
    |
 
 error: aborting due to previous error
index a32359c2b9f79d726039dbb259a003d047b06ba1..f3be99f9bcb4b3e09efcd9029b355d188c5ba5ec 100644 (file)
@@ -1,4 +1,4 @@
-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`
+error[E0271]: expected `TakeWhile<&mut IntoIter<u8>, [closure@issue-31173.rs:7:21]>` to be an iterator that yields `&_`, but it yields `u8`
   --> $DIR/issue-31173.rs:11:10
    |
 LL |         .cloned()
@@ -6,10 +6,22 @@ LL |         .cloned()
    |
    = note: expected reference `&_`
                    found type `u8`
+note: the method call chain might not have had the expected associated types
+  --> $DIR/issue-31173.rs:3:20
+   |
+LL |   pub fn get_tok(it: &mut IntoIter<u8>) {
+   |                      ^^^^^^^^^^^^^^^^^ `Iterator::Item` is `u8` here
+...
+LL |           .take_while(|&x| {
+   |  __________-
+LL | |             found_e = true;
+LL | |             false
+LL | |         })
+   | |__________- `Iterator::Item` remains `u8` here
 note: required by a bound in `cloned`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
 
-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
+error[E0599]: the method `collect` exists for struct `Cloned<TakeWhile<&mut IntoIter<u8>, [closure@issue-31173.rs:7:21]>>`, but its trait bounds were not satisfied
   --> $DIR/issue-31173.rs:12:10
    |
 LL |         .collect();
index 8430e85df871514f1269f49b6c7b9bccfe2b6efa..e3b6dcf55a7448296ea39c39de2c428b40e59ff2 100644 (file)
@@ -3,7 +3,7 @@
 use std::collections::HashMap;
 
 fn main() {
-    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 `(&_, &_)`
+    for _ in HashMap::new().iter().cloned() {} //~ ERROR expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
+    //~^ ERROR expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
+    //~| ERROR expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
 }
index 49702c47658638bd28315df55d7b44ff327b5667..668eaabca4c463d450fbe59ed71e04280dd0c1e4 100644 (file)
@@ -1,4 +1,4 @@
-error[E0271]: expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
+error[E0271]: expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
   --> $DIR/issue-33941.rs:6:36
    |
 LL |     for _ in HashMap::new().iter().cloned() {}
@@ -6,10 +6,17 @@ LL |     for _ in HashMap::new().iter().cloned() {}
    |
    = note: expected reference `&_`
                   found tuple `(&_, &_)`
+note: the method call chain might not have had the expected associated types
+  --> $DIR/issue-33941.rs:6:29
+   |
+LL |     for _ in HashMap::new().iter().cloned() {}
+   |              -------------- ^^^^^^ `Iterator::Item` is `(&_, &_)` here
+   |              |
+   |              this expression has type `HashMap<_, _>`
 note: required by a bound in `cloned`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
 
-error[E0271]: expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
+error[E0271]: expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
   --> $DIR/issue-33941.rs:6:14
    |
 LL |     for _ in HashMap::new().iter().cloned() {}
@@ -20,7 +27,7 @@ LL |     for _ in HashMap::new().iter().cloned() {}
    = note: required for `Cloned<std::collections::hash_map::Iter<'_, _, _>>` to implement `Iterator`
    = note: required for `Cloned<std::collections::hash_map::Iter<'_, _, _>>` to implement `IntoIterator`
 
-error[E0271]: expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
+error[E0271]: expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
   --> $DIR/issue-33941.rs:6:14
    |
 LL |     for _ in HashMap::new().iter().cloned() {}
index fd694df30457ec11998188b8c0d61946cfaab133..00c375f8d2acfaad1da084e0f1b1e5a43c87b9e3 100644 (file)
@@ -5,7 +5,7 @@ LL | pub struct Iterate<T, F> {
    | ------------------------ method `iter` not found for this struct
 ...
 LL |     println!("{:?}", a.iter().take(10).collect::<Vec<usize>>());
-   |                        ^^^^ method not found in `Iterate<{integer}, [closure@$DIR/issue-41880.rs:26:24: 26:27]>`
+   |                        ^^^^ method not found in `Iterate<{integer}, [closure@issue-41880.rs:26:24]>`
 
 error: aborting due to previous error
 
index 6fe151622433a83050286b46287dd1d5d0b2b1b5..3ca6a2957e14b91768b6c421dc222634f5886677 100644 (file)
@@ -23,6 +23,10 @@ LL | pub fn f(_: dyn ToString) {}
    |
    = help: the trait `Sized` is not implemented for `(dyn ToString + 'static)`
    = help: unsized fn params are gated as an unstable feature
+help: you can use `impl Trait` as the argument type
+   |
+LL | pub fn f(_: impl ToString) {}
+   |             ~~~~
 help: function arguments must have a statically known size, borrowed types always have a known size
    |
 LL | pub fn f(_: &dyn ToString) {}
index 8a20a60853a63a3e952988cb055779c786cd8fc9..ffff403e0d4656508d4dbdbf3c4e7b32f6bb749f 100644 (file)
@@ -6,6 +6,10 @@ LL |     r: dyn A + 'static
    |
    = help: the trait `Sized` is not implemented for `(dyn A + 'static)`
    = help: unsized fn params are gated as an unstable feature
+help: you can use `impl Trait` as the argument type
+   |
+LL |     r: impl A + 'static
+   |        ~~~~
 help: function arguments must have a statically known size, borrowed types always have a known size
    |
 LL |     r: &dyn A + 'static
index 87116e49245703805c9867ac9db2dce04c287ac1..ebdf33303c982b311d80fb1b066cf82b52cc6946 100644 (file)
@@ -1,3 +1,11 @@
+use std::collections::hash_set::Iter;
+use std::collections::HashSet;
+
+fn iter_to_vec<'b, X>(i: Iter<'b, X>) -> Vec<X> {
+    let i = i.map(|x| x.clone());
+    i.collect() //~ ERROR E0277
+}
+
 fn main() {
     let scores = vec![(0, 0)]
         .iter()
@@ -38,4 +46,8 @@ fn main() {
     });
     let f = e.filter(|_| false);
     let g: Vec<i32> = f.collect(); //~ ERROR E0277
+
+    let mut s = HashSet::new();
+    s.insert(1u8);
+    println!("{:?}", iter_to_vec(s.iter()));
 }
index 84bac7833f67b029b56e09e1b5c54ac2d4eaf946..d76a4bfb7b3ea886c68b8e90b2593fb4e7c477ea 100644 (file)
@@ -1,5 +1,23 @@
+error[E0277]: a value of type `Vec<X>` cannot be built from an iterator over elements of type `&X`
+  --> $DIR/invalid-iterator-chain.rs:6:7
+   |
+LL |     i.collect()
+   |       ^^^^^^^ value of type `Vec<X>` cannot be built from `std::iter::Iterator<Item=&X>`
+   |
+   = help: the trait `FromIterator<&X>` is not implemented for `Vec<X>`
+   = help: the trait `FromIterator<T>` is implemented for `Vec<T>`
+note: the method call chain might not have had the expected associated types
+  --> $DIR/invalid-iterator-chain.rs:4:26
+   |
+LL | fn iter_to_vec<'b, X>(i: Iter<'b, X>) -> Vec<X> {
+   |                          ^^^^^^^^^^^ `Iterator::Item` is `&X` here
+LL |     let i = i.map(|x| x.clone());
+   |               ------------------ `Iterator::Item` remains `&X` here
+note: required by a bound in `collect`
+  --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+
 error[E0277]: a value of type `i32` cannot be made by summing an iterator over elements of type `()`
-  --> $DIR/invalid-iterator-chain.rs:7:27
+  --> $DIR/invalid-iterator-chain.rs:15:27
    |
 LL |     println!("{}", scores.sum::<i32>());
    |                           ^^^ value of type `i32` cannot be made by summing a `std::iter::Iterator<Item=()>`
@@ -9,7 +27,7 @@ LL |     println!("{}", scores.sum::<i32>());
              <i32 as Sum<&'a i32>>
              <i32 as Sum>
 note: the method call chain might not have had the expected associated types
-  --> $DIR/invalid-iterator-chain.rs:4:10
+  --> $DIR/invalid-iterator-chain.rs:12:10
    |
 LL |       let scores = vec![(0, 0)]
    |                    ------------ this expression has type `Vec<({integer}, {integer})>`
@@ -24,7 +42,7 @@ note: required by a bound in `std::iter::Iterator::sum`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
 
 error[E0277]: a value of type `i32` cannot be made by summing an iterator over elements of type `()`
-  --> $DIR/invalid-iterator-chain.rs:18:14
+  --> $DIR/invalid-iterator-chain.rs:26:14
    |
 LL |             .sum::<i32>(),
    |              ^^^ value of type `i32` cannot be made by summing a `std::iter::Iterator<Item=()>`
@@ -34,7 +52,7 @@ LL |             .sum::<i32>(),
              <i32 as Sum<&'a i32>>
              <i32 as Sum>
 note: the method call chain might not have had the expected associated types
-  --> $DIR/invalid-iterator-chain.rs:12:14
+  --> $DIR/invalid-iterator-chain.rs:20:14
    |
 LL |         vec![0, 1]
    |         ---------- this expression has type `Vec<{integer}>`
@@ -56,7 +74,7 @@ note: required by a bound in `std::iter::Iterator::sum`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
 
 error[E0277]: a value of type `i32` cannot be made by summing an iterator over elements of type `f64`
-  --> $DIR/invalid-iterator-chain.rs:28:14
+  --> $DIR/invalid-iterator-chain.rs:36:14
    |
 LL |             .sum::<i32>(),
    |              ^^^ value of type `i32` cannot be made by summing a `std::iter::Iterator<Item=f64>`
@@ -66,7 +84,7 @@ LL |             .sum::<i32>(),
              <i32 as Sum<&'a i32>>
              <i32 as Sum>
 note: the method call chain might not have had the expected associated types
-  --> $DIR/invalid-iterator-chain.rs:24:14
+  --> $DIR/invalid-iterator-chain.rs:32:14
    |
 LL |         vec![0, 1]
    |         ---------- this expression has type `Vec<{integer}>`
@@ -84,7 +102,7 @@ note: required by a bound in `std::iter::Iterator::sum`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
 
 error[E0277]: a value of type `i32` cannot be made by summing an iterator over elements of type `()`
-  --> $DIR/invalid-iterator-chain.rs:30:54
+  --> $DIR/invalid-iterator-chain.rs:38:54
    |
 LL |     println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::<i32>());
    |                                                      ^^^ value of type `i32` cannot be made by summing a `std::iter::Iterator<Item=()>`
@@ -94,7 +112,7 @@ LL |     println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::<i32>());
              <i32 as Sum<&'a i32>>
              <i32 as Sum>
 note: the method call chain might not have had the expected associated types
-  --> $DIR/invalid-iterator-chain.rs:30:38
+  --> $DIR/invalid-iterator-chain.rs:38:38
    |
 LL |     println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::<i32>());
    |                    ---------- ------ ^^^^^^^^^^^^^^^ `Iterator::Item` changed to `()` here
@@ -105,7 +123,7 @@ note: required by a bound in `std::iter::Iterator::sum`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
 
 error[E0277]: a value of type `i32` cannot be made by summing an iterator over elements of type `&()`
-  --> $DIR/invalid-iterator-chain.rs:31:40
+  --> $DIR/invalid-iterator-chain.rs:39:40
    |
 LL |     println!("{}", vec![(), ()].iter().sum::<i32>());
    |                                        ^^^ value of type `i32` cannot be made by summing a `std::iter::Iterator<Item=&()>`
@@ -115,7 +133,7 @@ LL |     println!("{}", vec![(), ()].iter().sum::<i32>());
              <i32 as Sum<&'a i32>>
              <i32 as Sum>
 note: the method call chain might not have had the expected associated types
-  --> $DIR/invalid-iterator-chain.rs:31:33
+  --> $DIR/invalid-iterator-chain.rs:39:33
    |
 LL |     println!("{}", vec![(), ()].iter().sum::<i32>());
    |                    ------------ ^^^^^^ `Iterator::Item` is `&()` here
@@ -125,7 +143,7 @@ note: required by a bound in `std::iter::Iterator::sum`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
 
 error[E0277]: a value of type `Vec<i32>` cannot be built from an iterator over elements of type `()`
-  --> $DIR/invalid-iterator-chain.rs:40:25
+  --> $DIR/invalid-iterator-chain.rs:48:25
    |
 LL |     let g: Vec<i32> = f.collect();
    |                         ^^^^^^^ value of type `Vec<i32>` cannot be built from `std::iter::Iterator<Item=()>`
@@ -133,7 +151,7 @@ LL |     let g: Vec<i32> = f.collect();
    = help: the trait `FromIterator<()>` is not implemented for `Vec<i32>`
    = help: the trait `FromIterator<T>` is implemented for `Vec<T>`
 note: the method call chain might not have had the expected associated types
-  --> $DIR/invalid-iterator-chain.rs:36:15
+  --> $DIR/invalid-iterator-chain.rs:44:15
    |
 LL |       let a = vec![0];
    |               ------- this expression has type `Vec<{integer}>`
@@ -153,6 +171,6 @@ LL |       let f = e.filter(|_| false);
 note: required by a bound in `collect`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
 
-error: aborting due to 6 previous errors
+error: aborting due to 7 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
index b590fa697adb3dd17c846c0d3d554d21019fedc3..d4e88aa26436162160ff0ccc02e3b169e9b4de17 100644 (file)
@@ -20,19 +20,19 @@ fn main() {
 
     match foo::Foo::Foo {
         Foo => {}
-//~^ ERROR variable `Foo` should have a snake case name
-//~^^ WARN `Foo` is named the same as one of the variants of the type `Foo`
-//~^^^ WARN unused variable: `Foo`
+    //~^ ERROR variable `Foo` should have a snake case name
+    //~^^ WARN `Foo` is named the same as one of the variants of the type `foo::Foo`
+    //~^^^ WARN unused variable: `Foo`
     }
 
     let Foo = foo::Foo::Foo;
     //~^ ERROR variable `Foo` should have a snake case name
-    //~^^ WARN `Foo` is named the same as one of the variants of the type `Foo`
+    //~^^ WARN `Foo` is named the same as one of the variants of the type `foo::Foo`
     //~^^^ WARN unused variable: `Foo`
 
     fn in_param(Foo: foo::Foo) {}
     //~^ ERROR variable `Foo` should have a snake case name
-    //~^^ WARN `Foo` is named the same as one of the variants of the type `Foo`
+    //~^^ WARN `Foo` is named the same as one of the variants of the type `foo::Foo`
     //~^^^ WARN unused variable: `Foo`
 
     test(1);
index 71b24a835bcd9c18f41139646eaa8b8f9a5450fe..d476d856e24c59b060ccdd85be6ff1c681e4180a 100644 (file)
@@ -1,22 +1,22 @@
-warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `Foo`
+warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo`
   --> $DIR/lint-uppercase-variables.rs:22:9
    |
 LL |         Foo => {}
-   |         ^^^ help: to match on the variant, qualify the path: `Foo::Foo`
+   |         ^^^ help: to match on the variant, qualify the path: `foo::Foo::Foo`
    |
    = note: `#[warn(bindings_with_variant_name)]` on by default
 
-warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `Foo`
+warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo`
   --> $DIR/lint-uppercase-variables.rs:28:9
    |
 LL |     let Foo = foo::Foo::Foo;
-   |         ^^^ help: to match on the variant, qualify the path: `Foo::Foo`
+   |         ^^^ help: to match on the variant, qualify the path: `foo::Foo::Foo`
 
-warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `Foo`
+warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo`
   --> $DIR/lint-uppercase-variables.rs:33:17
    |
 LL |     fn in_param(Foo: foo::Foo) {}
-   |                 ^^^ help: to match on the variant, qualify the path: `Foo::Foo`
+   |                 ^^^ help: to match on the variant, qualify the path: `foo::Foo::Foo`
 
 warning: unused variable: `Foo`
   --> $DIR/lint-uppercase-variables.rs:22:9
diff --git a/src/test/ui/lto/auxiliary/thinlto-dylib.rs b/src/test/ui/lto/auxiliary/thinlto-dylib.rs
new file mode 100644 (file)
index 0000000..9d17c35
--- /dev/null
@@ -0,0 +1,23 @@
+// Auxiliary crate for test issue-105637: the LTOed dylib which had duplicate symbols from libstd,
+// breaking the panic hook feature.
+//
+// This simulates the `rustc_driver` crate, and the main crate simulates rustc's main binary hooking
+// into this driver.
+
+// compile-flags: -Zdylib-lto -C lto=thin
+
+use std::panic;
+
+pub fn main() {
+    // Install the hook we want to see executed
+    panic::set_hook(Box::new(|_| {
+        eprintln!("LTOed auxiliary crate panic hook");
+    }));
+
+    // Trigger the panic hook with an ICE
+    run_compiler();
+}
+
+fn run_compiler() {
+    panic!("ICEing");
+}
diff --git a/src/test/ui/lto/issue-105637.rs b/src/test/ui/lto/issue-105637.rs
new file mode 100644 (file)
index 0000000..0d9f0be
--- /dev/null
@@ -0,0 +1,28 @@
+// Regression test for issue #105637: `-Zdylib-lto` with LTO duplicated symbols from other dylibs,
+// in this case from libstd.
+//
+// That manifested as both `rustc_driver` and rustc's "main" (`compiler/rustc`) having their own
+// `std::panicking::HOOK` static, and the hook in rustc's main (the default stdlib's) being executed
+// when rustc ICEs, instead of the overriden hook from `rustc_driver` (which also displays the query
+// stack and information on how to open a GH issue for the encountered ICE).
+//
+// In this test, we reproduce this setup by installing a panic hook in both the main and an LTOed
+// dylib: the last hook set should be the one being executed, the dylib's.
+
+// aux-build: thinlto-dylib.rs
+// run-fail
+// check-run-results
+
+extern crate thinlto_dylib;
+
+use std::panic;
+
+fn main() {
+    // We don't want to see this panic hook executed
+    std::panic::set_hook(Box::new(|_| {
+        eprintln!("main crate panic hook");
+    }));
+
+    // Have the LTOed dylib install its own hook and panic, we want to see its hook executed.
+    thinlto_dylib::main();
+}
diff --git a/src/test/ui/lto/issue-105637.run.stderr b/src/test/ui/lto/issue-105637.run.stderr
new file mode 100644 (file)
index 0000000..43388e7
--- /dev/null
@@ -0,0 +1 @@
+LTOed auxiliary crate panic hook
diff --git a/src/test/ui/methods/issues/issue-105732.rs b/src/test/ui/methods/issues/issue-105732.rs
new file mode 100644 (file)
index 0000000..98b7a8d
--- /dev/null
@@ -0,0 +1,13 @@
+#![feature(auto_traits)]
+
+auto trait Foo {
+    fn g(&self); //~ ERROR auto traits cannot have associated items
+}
+
+trait Bar {
+    fn f(&self) {
+        self.g(); //~ ERROR the method `g` exists for reference `&Self`, but its trait bounds were not satisfied
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/methods/issues/issue-105732.stderr b/src/test/ui/methods/issues/issue-105732.stderr
new file mode 100644 (file)
index 0000000..fb2bdf4
--- /dev/null
@@ -0,0 +1,28 @@
+error[E0380]: auto traits cannot have associated items
+  --> $DIR/issue-105732.rs:4:8
+   |
+LL | auto trait Foo {
+   |            --- auto trait cannot have associated items
+LL |     fn g(&self);
+   |     ---^-------- help: remove these associated items
+
+error[E0599]: the method `g` exists for reference `&Self`, but its trait bounds were not satisfied
+  --> $DIR/issue-105732.rs:9:14
+   |
+LL |         self.g();
+   |              ^
+   |
+   = note: the following trait bounds were not satisfied:
+           `Self: Foo`
+           which is required by `&Self: Foo`
+           `&Self: Foo`
+   = help: items from traits can only be used if the type parameter is bounded by the trait
+help: the following trait defines an item `g`, perhaps you need to add a supertrait for it:
+   |
+LL | trait Bar: Foo {
+   |          +++++
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0380, E0599.
+For more information about an error, try `rustc --explain E0380`.
index fc42d1a4dcd08136374b9ab6203cd4de854dbd23..8846efba871b9cd1f845b86b58dfbaa5a0880d1b 100644 (file)
@@ -23,7 +23,7 @@ error[E0599]: no method named `extend` found for struct `Map` in the current sco
   --> $DIR/method-not-found-generic-arg-elision.rs:87:29
    |
 LL |     v.iter().map(|x| x * x).extend(std::iter::once(100));
-   |                             ^^^^^^ method not found in `Map<std::slice::Iter<'_, i32>, [closure@$DIR/method-not-found-generic-arg-elision.rs:87:18: 87:21]>`
+   |                             ^^^^^^ method not found in `Map<Iter<'_, i32>, [closure@method-not-found-generic-arg-elision.rs:87:18]>`
 
 error[E0599]: no method named `method` found for struct `Wrapper<bool>` in the current scope
   --> $DIR/method-not-found-generic-arg-elision.rs:90:13
diff --git a/src/test/ui/mir/issue-105809.rs b/src/test/ui/mir/issue-105809.rs
new file mode 100644 (file)
index 0000000..57828fe
--- /dev/null
@@ -0,0 +1,36 @@
+// Non-regression test ICE from issue #105809 and duplicates.
+
+// build-pass: the ICE is during codegen
+// compile-flags: --edition 2018 -Zmir-opt-level=1
+
+use std::{future::Future, pin::Pin};
+
+// Create a `T` without affecting analysis like `loop {}`.
+fn create<T>() -> T {
+    loop {}
+}
+
+async fn trivial_future() {}
+
+struct Connection<H> {
+    _h: H,
+}
+
+async fn complex_future<H>(conn: &Connection<H>) {
+    let small_fut = async move {
+        let _ = conn;
+        trivial_future().await;
+    };
+
+    let mut tuple = (small_fut,);
+    let (small_fut_again,) = &mut tuple;
+    let _ = small_fut_again;
+}
+
+fn main() {
+    let mut fut = complex_future(&Connection { _h: () });
+
+    let mut cx = create();
+    let future = unsafe { Pin::new_unchecked(&mut fut) };
+    let _ = future.poll(&mut cx);
+}
index 3151bc76891e48abce961ee826b43498ab63d703..72fb0e4d774312780cb81e6e5f8fc1617f0d8113 100644 (file)
@@ -13,7 +13,7 @@ LL |     once::<&str>("str").fuse().filter(|a: &str| true).count();
 note: required by a bound in `filter`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
 
-error[E0599]: the method `count` exists for struct `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:48]>`, but its trait bounds were not satisfied
+error[E0599]: the method `count` exists for struct `Filter<Fuse<Once<&str>>, [closure@issue-36053-2.rs:7:39]>`, but its trait bounds were not satisfied
   --> $DIR/issue-36053-2.rs:7:55
    |
 LL |     once::<&str>("str").fuse().filter(|a: &str| true).count();
diff --git a/src/test/ui/missing/missing-alloc_error_handler.rs b/src/test/ui/missing/missing-alloc_error_handler.rs
deleted file mode 100644 (file)
index 4d378f0..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-// compile-flags: -C panic=abort
-// no-prefer-dynamic
-
-#![no_std]
-#![crate_type = "staticlib"]
-#![feature(alloc_error_handler)]
-
-#[panic_handler]
-fn panic(_: &core::panic::PanicInfo) -> ! {
-    loop {}
-}
-
-extern crate alloc;
-
-#[global_allocator]
-static A: MyAlloc = MyAlloc;
-
-struct MyAlloc;
-
-unsafe impl core::alloc::GlobalAlloc for MyAlloc {
-    unsafe fn alloc(&self, _: core::alloc::Layout) -> *mut u8 { 0 as _ }
-    unsafe fn dealloc(&self, _: *mut u8, _: core::alloc::Layout) {}
-}
diff --git a/src/test/ui/missing/missing-alloc_error_handler.stderr b/src/test/ui/missing/missing-alloc_error_handler.stderr
deleted file mode 100644 (file)
index 995fa7c..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-error: `#[alloc_error_handler]` function required, but not found
-
-note: use `#![feature(default_alloc_error_handler)]` for a default error handler
-
-error: aborting due to previous error
-
index 45cf3723483f3a05f0ca60546bc6c949bb7df68a..a0f790dba15ed21adddebbcb5daf9faa8cd909ef 100644 (file)
@@ -1,4 +1,4 @@
-error[E0271]: expected `[closure@$DIR/fallback-closure-wrap.rs:18:40: 18:47]` to be a closure that returns `()`, but it returns `!`
+error[E0271]: expected `[closure@fallback-closure-wrap.rs:18:40]` 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 1da29be43db864d627d9b905147687e68b935058..002dfe115b03f2f343f624377170c706334ea1db 100644 (file)
@@ -8,3 +8,4 @@ LL | fn f(x: S<u32>) {}
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0320`.
index 88b1c1396516d497870ab47a559636999fccca90..e567d5c2723f2c2b631730abe978dbaa380b09ac 100644 (file)
@@ -22,11 +22,11 @@ fn good_generic_fn<T>() {
 // This should fail because `T` ends up in the upvars of the closure.
 fn bad_generic_fn<T: Copy>(t: T) {
     assert_static(opaque(async move { t; }).next());
-    //~^ ERROR the parameter type `T` may not live long enough
+    //~^ ERROR the associated type `<impl Iterator as Iterator>::Item` may not live long enough
     assert_static(opaque(move || { t; }).next());
     //~^ ERROR the associated type `<impl Iterator as Iterator>::Item` may not live long enough
     assert_static(opaque(opaque(async move { t; }).next()).next());
-    //~^ ERROR the parameter type `T` may not live long enough
+    //~^ ERROR the associated type `<impl Iterator as Iterator>::Item` may not live long enough
 }
 
 fn main() {}
index 907964aaf379e5c27b9ecfdf665558f77dfd2380..c08f1059ebf58278b7ce88edc8127f5e867f33da 100644 (file)
@@ -1,13 +1,11 @@
-error[E0310]: the parameter type `T` may not live long enough
+error[E0310]: the associated type `<impl Iterator as Iterator>::Item` may not live long enough
   --> $DIR/closure-in-projection-issue-97405.rs:24:5
    |
 LL |     assert_static(opaque(async move { t; }).next());
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
-   |
-help: consider adding an explicit lifetime bound...
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-LL | fn bad_generic_fn<T: Copy + 'static>(t: T) {
-   |                           +++++++++
+   = help: consider adding an explicit lifetime bound `<impl Iterator as Iterator>::Item: 'static`...
+   = note: ...so that the type `<impl Iterator as Iterator>::Item` will meet its required lifetime bounds
 
 error[E0310]: the associated type `<impl Iterator as Iterator>::Item` may not live long enough
   --> $DIR/closure-in-projection-issue-97405.rs:26:5
@@ -18,16 +16,14 @@ LL |     assert_static(opaque(move || { t; }).next());
    = help: consider adding an explicit lifetime bound `<impl Iterator as Iterator>::Item: 'static`...
    = note: ...so that the type `<impl Iterator as Iterator>::Item` will meet its required lifetime bounds
 
-error[E0310]: the parameter type `T` may not live long enough
+error[E0310]: the associated type `<impl Iterator as Iterator>::Item` may not live long enough
   --> $DIR/closure-in-projection-issue-97405.rs:28:5
    |
 LL |     assert_static(opaque(opaque(async move { t; }).next()).next());
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
-   |
-help: consider adding an explicit lifetime bound...
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-LL | fn bad_generic_fn<T: Copy + 'static>(t: T) {
-   |                           +++++++++
+   = help: consider adding an explicit lifetime bound `<impl Iterator as Iterator>::Item: 'static`...
+   = note: ...so that the type `<impl Iterator as Iterator>::Item` will meet its required lifetime bounds
 
 error: aborting due to 3 previous errors
 
index 939392733f0e9659de281625967ee497f98f9eb1..558e6b7b118d8221125e8cdd953d2ac1b9834bdd 100644 (file)
@@ -6,6 +6,10 @@ LL | fn foo(_x: K) {}
    |
    = help: the trait `Sized` is not implemented for `(dyn I + 'static)`
    = help: unsized fn params are gated as an unstable feature
+help: you can use `impl Trait` as the argument type
+   |
+LL | fn foo(_x: impl K) {}
+   |            ++++
 help: function arguments must have a statically known size, borrowed types always have a known size
    |
 LL | fn foo(_x: &K) {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-impl-trait.rs b/src/test/ui/rfc-2632-const-trait-impl/const-impl-trait.rs
new file mode 100644 (file)
index 0000000..0622f96
--- /dev/null
@@ -0,0 +1,55 @@
+// check-pass
+#![allow(incomplete_features)]
+#![feature(
+    associated_type_bounds,
+    const_trait_impl,
+    const_cmp,
+    return_position_impl_trait_in_trait,
+)]
+
+use std::marker::Destruct;
+
+const fn cmp(a: &impl ~const PartialEq) -> bool {
+    a == a
+}
+
+const fn wrap(x: impl ~const PartialEq + ~const Destruct)
+    -> impl ~const PartialEq + ~const Destruct
+{
+    x
+}
+
+#[const_trait]
+trait Foo {
+    fn huh() -> impl ~const PartialEq + ~const Destruct + Copy;
+}
+
+impl const Foo for () {
+    fn huh() -> impl ~const PartialEq + ~const Destruct + Copy {
+        123
+    }
+}
+
+const _: () = {
+    assert!(cmp(&0xDEADBEEFu32));
+    assert!(cmp(&()));
+    assert!(wrap(123) == wrap(123));
+    assert!(wrap(123) != wrap(456));
+    let x = <() as Foo>::huh();
+    assert!(x == x);
+};
+
+#[const_trait]
+trait T {}
+struct S;
+impl const T for S {}
+
+const fn rpit() -> impl ~const T { S }
+
+const fn apit(_: impl ~const T + ~const Destruct) {}
+
+const fn rpit_assoc_bound() -> impl IntoIterator<Item: ~const T> { Some(S) }
+
+const fn apit_assoc_bound(_: impl IntoIterator<Item: ~const T> + ~const Destruct) {}
+
+fn main() {}
index 5bd52151f42acdc097cd97516a038ad44ff31c2f..95f7aaba0fc389fe5d8c895e6a319947bb554829 100644 (file)
@@ -1,23 +1,6 @@
 #![feature(const_trait_impl)]
 #![feature(associated_type_bounds)]
 
-#[const_trait]
-trait T {}
-struct S;
-impl T for S {}
-
-fn rpit() -> impl ~const T { S }
-//~^ ERROR `~const` is not allowed
-
-fn apit(_: impl ~const T) {}
-//~^ ERROR `~const` is not allowed
-
-fn rpit_assoc_bound() -> impl IntoIterator<Item: ~const T> { Some(S) }
-//~^ ERROR `~const` is not allowed
-
-fn apit_assoc_bound(_: impl IntoIterator<Item: ~const T>) {}
-//~^ ERROR `~const` is not allowed
-
 struct TildeQuestion<T: ~const ?Sized>(std::marker::PhantomData<T>);
 //~^ ERROR `~const` and `?` are mutually exclusive
 
index 84867cb4a5342cfb7cd10fa0b37dfd568484da7b..d20f146df3f1a102fa36cbe168734f1cec616f91 100644 (file)
@@ -1,40 +1,8 @@
-error: `~const` is not allowed here
-  --> $DIR/tilde-const-invalid-places.rs:9:19
-   |
-LL | fn rpit() -> impl ~const T { S }
-   |                   ^^^^^^^^
-   |
-   = note: `impl Trait`s cannot have `~const` trait bounds
-
-error: `~const` is not allowed here
-  --> $DIR/tilde-const-invalid-places.rs:12:17
-   |
-LL | fn apit(_: impl ~const T) {}
-   |                 ^^^^^^^^
-   |
-   = note: `impl Trait`s cannot have `~const` trait bounds
-
-error: `~const` is not allowed here
-  --> $DIR/tilde-const-invalid-places.rs:15:50
-   |
-LL | fn rpit_assoc_bound() -> impl IntoIterator<Item: ~const T> { Some(S) }
-   |                                                  ^^^^^^^^
-   |
-   = note: `impl Trait`s cannot have `~const` trait bounds
-
-error: `~const` is not allowed here
-  --> $DIR/tilde-const-invalid-places.rs:18:48
-   |
-LL | fn apit_assoc_bound(_: impl IntoIterator<Item: ~const T>) {}
-   |                                                ^^^^^^^^
-   |
-   = note: `impl Trait`s cannot have `~const` trait bounds
-
 error: `~const` and `?` are mutually exclusive
-  --> $DIR/tilde-const-invalid-places.rs:21:25
+  --> $DIR/tilde-const-invalid-places.rs:4:25
    |
 LL | struct TildeQuestion<T: ~const ?Sized>(std::marker::PhantomData<T>);
    |                         ^^^^^^^^^^^^^
 
-error: aborting due to 5 previous errors
+error: aborting due to previous error
 
diff --git a/src/test/ui/suggestions/clone-on-unconstrained-borrowed-type-param.fixed b/src/test/ui/suggestions/clone-on-unconstrained-borrowed-type-param.fixed
new file mode 100644 (file)
index 0000000..4f9e93a
--- /dev/null
@@ -0,0 +1,16 @@
+// run-rustfix
+fn wat<T: Clone>(t: &T) -> T {
+    t.clone() //~ ERROR E0308
+}
+
+#[derive(Clone)]
+struct Foo;
+
+fn wut(t: &Foo) -> Foo {
+    t.clone() //~ ERROR E0308
+}
+
+fn main() {
+    wat(&42);
+    wut(&Foo);
+}
diff --git a/src/test/ui/suggestions/clone-on-unconstrained-borrowed-type-param.rs b/src/test/ui/suggestions/clone-on-unconstrained-borrowed-type-param.rs
new file mode 100644 (file)
index 0000000..89b077d
--- /dev/null
@@ -0,0 +1,15 @@
+// run-rustfix
+fn wat<T>(t: &T) -> T {
+    t.clone() //~ ERROR E0308
+}
+
+struct Foo;
+
+fn wut(t: &Foo) -> Foo {
+    t.clone() //~ ERROR E0308
+}
+
+fn main() {
+    wat(&42);
+    wut(&Foo);
+}
diff --git a/src/test/ui/suggestions/clone-on-unconstrained-borrowed-type-param.stderr b/src/test/ui/suggestions/clone-on-unconstrained-borrowed-type-param.stderr
new file mode 100644 (file)
index 0000000..26ab515
--- /dev/null
@@ -0,0 +1,43 @@
+error[E0308]: mismatched types
+  --> $DIR/clone-on-unconstrained-borrowed-type-param.rs:3:5
+   |
+LL | fn wat<T>(t: &T) -> T {
+   |        -            - expected `T` because of return type
+   |        |
+   |        this type parameter
+LL |     t.clone()
+   |     ^^^^^^^^^ expected type parameter `T`, found `&T`
+   |
+   = note: expected type parameter `T`
+                   found reference `&T`
+note: `T` does not implement `Clone`, so `&T` was cloned instead
+  --> $DIR/clone-on-unconstrained-borrowed-type-param.rs:3:5
+   |
+LL |     t.clone()
+   |     ^
+help: consider restricting type parameter `T`
+   |
+LL | fn wat<T: Clone>(t: &T) -> T {
+   |         +++++++
+
+error[E0308]: mismatched types
+  --> $DIR/clone-on-unconstrained-borrowed-type-param.rs:9:5
+   |
+LL | fn wut(t: &Foo) -> Foo {
+   |                    --- expected `Foo` because of return type
+LL |     t.clone()
+   |     ^^^^^^^^^ expected struct `Foo`, found `&Foo`
+   |
+note: `Foo` does not implement `Clone`, so `&Foo` was cloned instead
+  --> $DIR/clone-on-unconstrained-borrowed-type-param.rs:9:5
+   |
+LL |     t.clone()
+   |     ^
+help: consider annotating `Foo` with `#[derive(Clone)]`
+   |
+LL | #[derive(Clone)]
+   |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/suggestions/enum-variant-arg-mismatch.rs b/src/test/ui/suggestions/enum-variant-arg-mismatch.rs
new file mode 100644 (file)
index 0000000..8de5bae
--- /dev/null
@@ -0,0 +1,10 @@
+pub enum Sexpr<'a> {
+    Ident(&'a str),
+}
+
+fn map<'a, F: Fn(String) -> Sexpr<'a>>(f: F) {}
+
+fn main() {
+    map(Sexpr::Ident);
+    //~^ ERROR type mismatch in function arguments
+}
diff --git a/src/test/ui/suggestions/enum-variant-arg-mismatch.stderr b/src/test/ui/suggestions/enum-variant-arg-mismatch.stderr
new file mode 100644 (file)
index 0000000..f76019b
--- /dev/null
@@ -0,0 +1,22 @@
+error[E0631]: type mismatch in function arguments
+  --> $DIR/enum-variant-arg-mismatch.rs:8:9
+   |
+LL |     Ident(&'a str),
+   |     ----- found signature defined here
+...
+LL |     map(Sexpr::Ident);
+   |     --- ^^^^^^^^^^^^ expected due to this
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = note: expected function signature `fn(String) -> _`
+              found function signature `fn(&str) -> _`
+note: required by a bound in `map`
+  --> $DIR/enum-variant-arg-mismatch.rs:5:15
+   |
+LL | fn map<'a, F: Fn(String) -> Sexpr<'a>>(f: F) {}
+   |               ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `map`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0631`.
diff --git a/src/test/ui/suggestions/issue-104327.rs b/src/test/ui/suggestions/issue-104327.rs
new file mode 100644 (file)
index 0000000..dd621ae
--- /dev/null
@@ -0,0 +1,12 @@
+trait Bar {}
+
+trait Foo {
+    fn f() {}
+}
+
+impl Foo for dyn Bar {}
+
+fn main() {
+    Foo::f();
+    //~^ ERROR cannot call associated function on trait without specifying the corresponding `impl` type
+}
diff --git a/src/test/ui/suggestions/issue-104327.stderr b/src/test/ui/suggestions/issue-104327.stderr
new file mode 100644 (file)
index 0000000..acec3a5
--- /dev/null
@@ -0,0 +1,17 @@
+error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type
+  --> $DIR/issue-104327.rs:10:5
+   |
+LL |     fn f() {}
+   |     --------- `Foo::f` defined here
+...
+LL |     Foo::f();
+   |     ^^^^^^ cannot call associated function of trait
+   |
+help: use the fully-qualified path to the only available implementation
+   |
+LL |     <(dyn Bar + 'static) as Foo>::f();
+   |     +++++++++++++++++++++++    +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0790`.
diff --git a/src/test/ui/suggestions/issue-104328.rs b/src/test/ui/suggestions/issue-104328.rs
new file mode 100644 (file)
index 0000000..c3707ba
--- /dev/null
@@ -0,0 +1,12 @@
+#![feature(object_safe_for_dispatch)]
+
+trait Foo {
+    fn f() {}
+}
+
+impl Foo for dyn Sized {}
+
+fn main() {
+    Foo::f();
+    //~^ ERROR cannot call associated function on trait without specifying the corresponding `impl` type
+}
diff --git a/src/test/ui/suggestions/issue-104328.stderr b/src/test/ui/suggestions/issue-104328.stderr
new file mode 100644 (file)
index 0000000..b31b847
--- /dev/null
@@ -0,0 +1,17 @@
+error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type
+  --> $DIR/issue-104328.rs:10:5
+   |
+LL |     fn f() {}
+   |     --------- `Foo::f` defined here
+...
+LL |     Foo::f();
+   |     ^^^^^^ cannot call associated function of trait
+   |
+help: use the fully-qualified path to the only available implementation
+   |
+LL |     <(dyn Sized + 'static) as Foo>::f();
+   |     +++++++++++++++++++++++++    +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0790`.
index 2cb53ecce10408cff69354ca06b2bed9302e9464..6910b77d9bc3fa1874c69f464fba0e1b1444ef3b 100644 (file)
@@ -20,11 +20,11 @@ LL |     let fp = BufWriter::new(fp);
 note: required by a bound in `BufWriter`
   --> $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL
 
-error[E0599]: the method `write_fmt` exists for struct `BufWriter<&dyn std::io::Write>`, but its trait bounds were not satisfied
+error[E0599]: the method `write_fmt` exists for struct `BufWriter<&dyn Write>`, but its trait bounds were not satisfied
   --> $DIR/mut-borrow-needed-by-trait.rs:21:5
    |
 LL |     writeln!(fp, "hello world").unwrap();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ method cannot be called on `BufWriter<&dyn std::io::Write>` due to unsatisfied trait bounds
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ method cannot be called on `BufWriter<&dyn Write>` due to unsatisfied trait bounds
   --> $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL
    |
    = note: doesn't satisfy `BufWriter<&dyn std::io::Write>: std::io::Write`
index 7244919e86d5d66200944d7a8c354257123348ae..caefdfc96f0388cb238bb525e0ea70c4f17eb17a 100644 (file)
@@ -11,3 +11,4 @@ LL | extern crate b;
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0460`.
index 1e97e9d0557d04f8890bfec1263b8a6c1076371d..5e890c6aa5795d7d7bfb214768ae195699db31bc 100644 (file)
@@ -11,3 +11,4 @@ LL | extern crate b;
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0460`.
index f04046f4c87bf423b4173b7f119a4984b18d9d94..dcc250d5216b0c5fff45a769b228c3c75ec4dd22 100644 (file)
@@ -11,3 +11,4 @@ LL | extern crate b;
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0460`.
index a778c61806a500b36e7db4ea2b04c047fbf52fcb..2035993d218ec5a4c377c1fc75b3c98dafb610cd 100644 (file)
@@ -11,3 +11,4 @@ LL | extern crate b;
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0460`.
index f09babf93fd358903c165ee239615e627f21b936..eef85aa954611f6e72b7573949cadf794a8ee14e 100644 (file)
@@ -11,3 +11,4 @@ LL | extern crate b;
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0460`.
index 0998cd4b5496e8303f6c04450ffd0e8233a084e5..247f74e50df600f10a4ec0888bd0350f43eb362c 100644 (file)
@@ -11,3 +11,4 @@ LL | extern crate b;
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0460`.
index 9c48cbd30a508408f4976eff4c067275700fedf6..78b54f227f0f015301720a9695b7015a8f876cd2 100644 (file)
@@ -11,3 +11,4 @@ LL | extern crate b;
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0460`.
index 5780cfef357d612bf8a23787c44da57b56423ba3..d8a81864dcaa81eee8fb98348b521255e63377bc 100644 (file)
@@ -11,3 +11,4 @@ LL | extern crate utb;
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0460`.
index d7d6241ef708cda1a68a922940d7a3963417a6ba..65340b2a2092ff5cdf345a4c08703603d70c0ee1 100644 (file)
@@ -10,7 +10,7 @@ pub trait Foo: Iterator<Item = <Self as Foo>::Key> {
 
 impl Foo for IntoIter<i32> {
     type Key = u32;
-    //~^ ERROR expected `std::vec::IntoIter<i32>` to be an iterator that yields `u32`, but it yields `i32`
+    //~^ ERROR expected `IntoIter<i32>` to be an iterator that yields `u32`, but it yields `i32`
 }
 
 fn main() {}
index 3e2d9d9038aa7c1e6b8655cd3fdf668cc42f6190..7fa1d2c2eed67c8fd85f48d77f1aa019a3d36fb7 100644 (file)
@@ -1,4 +1,4 @@
-error[E0271]: expected `std::vec::IntoIter<i32>` to be an iterator that yields `u32`, but it yields `i32`
+error[E0271]: expected `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;
index 8da0b6d6b85056198c76584c63492e85841f1dee..36b08a7d3093141c3ee61e6ff410794cc2092341 100644 (file)
@@ -20,6 +20,10 @@ LL | fn foo(_x: Foo + Send) {
    |
    = help: the trait `Sized` is not implemented for `(dyn Foo + Send + 'static)`
    = help: unsized fn params are gated as an unstable feature
+help: you can use `impl Trait` as the argument type
+   |
+LL | fn foo(_x: impl Foo + Send) {
+   |            ++++
 help: function arguments must have a statically known size, borrowed types always have a known size
    |
 LL | fn foo(_x: &Foo + Send) {
index 5f74d0c3b9260e5686593d89852bb77abed05823..575ace2374ee64ec15c33701d40fffab44285bce 100644 (file)
@@ -9,8 +9,8 @@ LL |     let _f: base::Foo = base::HasNew::new();
    |
 help: use the fully-qualified path to the only available implementation
    |
-LL |     let _f: base::Foo = base::<Foo as HasNew>::new();
-   |                               +++++++       +
+LL |     let _f: base::Foo = <Foo as base::HasNew>::new();
+   |                         +++++++             +
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type-alias-impl-trait/auxiliary/coherence_cross_crate_trait_decl.rs b/src/test/ui/type-alias-impl-trait/auxiliary/coherence_cross_crate_trait_decl.rs
new file mode 100644 (file)
index 0000000..712ed55
--- /dev/null
@@ -0,0 +1,9 @@
+pub trait SomeTrait {}
+
+impl SomeTrait for () {}
+
+// Adding this `impl` would cause errors in this crate's dependent,
+// so it would be a breaking change. We explicitly don't add this impl,
+// as the dependent crate already assumes this impl exists and thus already
+// does not compile.
+//impl SomeTrait for i32 {}
diff --git a/src/test/ui/type-alias-impl-trait/coherence_cross_crate.rs b/src/test/ui/type-alias-impl-trait/coherence_cross_crate.rs
new file mode 100644 (file)
index 0000000..a63e0a1
--- /dev/null
@@ -0,0 +1,24 @@
+// aux-build: coherence_cross_crate_trait_decl.rs
+// This test ensures that adding an `impl SomeTrait for i32` within
+// `coherence_cross_crate_trait_decl` is not a breaking change, by
+// making sure that even without such an impl this test fails to compile.
+
+#![feature(type_alias_impl_trait)]
+
+extern crate coherence_cross_crate_trait_decl;
+
+use coherence_cross_crate_trait_decl::SomeTrait;
+
+trait OtherTrait {}
+
+type Alias = impl SomeTrait;
+
+fn constrain() -> Alias {
+    ()
+}
+
+impl OtherTrait for Alias {}
+impl OtherTrait for i32 {}
+//~^ ERROR: conflicting implementations of trait `OtherTrait` for type `Alias`
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/coherence_cross_crate.stderr b/src/test/ui/type-alias-impl-trait/coherence_cross_crate.stderr
new file mode 100644 (file)
index 0000000..63a3ce2
--- /dev/null
@@ -0,0 +1,13 @@
+error[E0119]: conflicting implementations of trait `OtherTrait` for type `Alias`
+  --> $DIR/coherence_cross_crate.rs:21:1
+   |
+LL | impl OtherTrait for Alias {}
+   | ------------------------- first implementation here
+LL | impl OtherTrait for i32 {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Alias`
+   |
+   = note: upstream crates may add a new impl of trait `coherence_cross_crate_trait_decl::SomeTrait` for type `i32` in future versions
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/src/test/ui/type-alias-impl-trait/destructuring.rs b/src/test/ui/type-alias-impl-trait/destructuring.rs
new file mode 100644 (file)
index 0000000..b752e58
--- /dev/null
@@ -0,0 +1,10 @@
+#![feature(type_alias_impl_trait)]
+
+// check-pass
+
+// issue: https://github.com/rust-lang/rust/issues/104551
+
+fn main() {
+    type T = impl Sized;
+    let (_a, _b): T = (1u32, 2u32);
+}
index 24b3a045856a6accd5656b25a2531e4afae89465..4aa5966ff25d4cedac7d9db5a84b39087a0ef0f9 100644 (file)
@@ -8,7 +8,7 @@ trait Foo {
 
 impl Foo for () {
     type Bar = std::vec::IntoIter<u32>;
-    //~^ ERROR expected `std::vec::IntoIter<u32>` to be an iterator that yields `X`, but it yields `u32`
+    //~^ ERROR expected `IntoIter<u32>` to be an iterator that yields `X`, but it yields `u32`
 }
 
 fn incoherent() {
index fb40895c49f15d13e28a81527f3ef4ac2e159014..8d11b48888947d91bce4b7039892a34a8cc72b15 100644 (file)
@@ -1,4 +1,4 @@
-error[E0271]: expected `std::vec::IntoIter<u32>` to be an iterator that yields `X`, but it yields `u32`
+error[E0271]: expected `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 faac680ea19318f02e674ec0e5ddb67ad34cf9eb..ff36e18d28301ef3b1934208e8ed2175a8ecbe9f 100644 (file)
@@ -12,6 +12,10 @@ note: `NotClone` does not implement `Clone`, so `&NotClone` was cloned instead
    |
 LL |     nc.clone()
    |     ^^
+help: consider annotating `NotClone` with `#[derive(Clone)]`
+   |
+LL | #[derive(Clone)]
+   |
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/typeck/issue-57404.rs b/src/test/ui/typeck/issue-57404.rs
new file mode 100644 (file)
index 0000000..ecabca6
--- /dev/null
@@ -0,0 +1,7 @@
+#![feature(unboxed_closures)]
+#![feature(fn_traits)]
+
+fn main() {
+    let handlers: Option<Box<dyn for<'a> FnMut<&'a mut (), Output=()>>> = None;
+    handlers.unwrap().as_mut().call_mut(&mut ()); //~ ERROR: `&mut ()` is not a tuple
+}
diff --git a/src/test/ui/typeck/issue-57404.stderr b/src/test/ui/typeck/issue-57404.stderr
new file mode 100644 (file)
index 0000000..5065ac3
--- /dev/null
@@ -0,0 +1,16 @@
+error[E0277]: `&mut ()` is not a tuple
+  --> $DIR/issue-57404.rs:6:41
+   |
+LL |     handlers.unwrap().as_mut().call_mut(&mut ());
+   |                                -------- -^^^^^^
+   |                                |        |
+   |                                |        the trait `Tuple` is not implemented for `&mut ()`
+   |                                |        help: consider removing the leading `&`-reference
+   |                                required by a bound introduced by this call
+   |
+note: required by a bound in `call_mut`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
index e5ca0edd7a91c62826aa111d4be9dada4161bb37..99ec5178340030d15ca4cac950f747182a9e36cc 100644 (file)
@@ -1,8 +1,8 @@
-error[E0599]: no method named `call` found for closure `[closure@$DIR/unboxed-closures-static-call-wrong-trait.rs:6:26: 6:29]` in the current scope
+error[E0599]: no method named `call` found for closure `[closure@unboxed-closures-static-call-wrong-trait.rs:6:26]` in the current scope
   --> $DIR/unboxed-closures-static-call-wrong-trait.rs:7:10
    |
 LL |     mut_.call((0, ));
-   |          ^^^^ method not found in `[closure@$DIR/unboxed-closures-static-call-wrong-trait.rs:6:26: 6:29]`
+   |          ^^^^ method not found in `[closure@unboxed-closures-static-call-wrong-trait.rs:6:26]`
 
 error: aborting due to previous error
 
index cc0a320879c17207bbfb96b5d778e28a2c62030d..c994a4a638370bc7e0ffcbb0e2865afdfa7d4415 160000 (submodule)
@@ -1 +1 @@
-Subproject commit cc0a320879c17207bbfb96b5d778e28a2c62030d
+Subproject commit c994a4a638370bc7e0ffcbb0e2865afdfa7d4415
index 6448b2d4068deb480aa9484fb082288e7c8b81ca..1bc457a947936b4e35fa9c9cbe8a4f945d1721e5 100644 (file)
@@ -82,13 +82,6 @@ jobs:
       with:
         github_token: "${{ secrets.github_token }}"
 
-    - name: Install dependencies (Linux-i686)
-      run: |
-        sudo dpkg --add-architecture i386
-        sudo apt-get update
-        sudo apt-get install gcc-multilib libssl-dev:i386 libgit2-dev:i386
-      if: matrix.host == 'i686-unknown-linux-gnu'
-
     - name: Checkout
       uses: actions/checkout@v3.0.2
 
index 23912bb3ed6b16aea9a4ce27ad1cd5a1a2f50661..903ee938d9d2d2f73e535c3b05eff4be2b628b49 100644 (file)
@@ -6,11 +6,181 @@ document.
 
 ## Unreleased / Beta / In Rust Nightly
 
-[b52fb523...master](https://github.com/rust-lang/rust-clippy/compare/b52fb523...master)
+[4f142aa1...master](https://github.com/rust-lang/rust-clippy/compare/4f142aa1...master)
+
+## Rust 1.66
+
+Current stable, released 2022-12-15
+
+[b52fb523...4f142aa1](https://github.com/rust-lang/rust-clippy/compare/b52fb523...4f142aa1)
+
+### New Lints
+
+* [`manual_clamp`]
+  [#9484](https://github.com/rust-lang/rust-clippy/pull/9484)
+* [`missing_trait_methods`]
+  [#9670](https://github.com/rust-lang/rust-clippy/pull/9670)
+* [`unused_format_specs`]
+  [#9637](https://github.com/rust-lang/rust-clippy/pull/9637)
+* [`iter_kv_map`]
+  [#9409](https://github.com/rust-lang/rust-clippy/pull/9409)
+* [`manual_filter`]
+  [#9451](https://github.com/rust-lang/rust-clippy/pull/9451)
+* [`box_default`]
+  [#9511](https://github.com/rust-lang/rust-clippy/pull/9511)
+* [`implicit_saturating_add`]
+  [#9549](https://github.com/rust-lang/rust-clippy/pull/9549)
+* [`as_ptr_cast_mut`]
+  [#9572](https://github.com/rust-lang/rust-clippy/pull/9572)
+* [`disallowed_macros`]
+  [#9495](https://github.com/rust-lang/rust-clippy/pull/9495)
+* [`partial_pub_fields`]
+  [#9658](https://github.com/rust-lang/rust-clippy/pull/9658)
+* [`uninlined_format_args`]
+  [#9233](https://github.com/rust-lang/rust-clippy/pull/9233)
+* [`cast_nan_to_int`]
+  [#9617](https://github.com/rust-lang/rust-clippy/pull/9617)
+
+### Moves and Deprecations
+
+* `positional_named_format_parameters` was uplifted to rustc under the new name
+  `named_arguments_used_positionally`
+  [#8518](https://github.com/rust-lang/rust-clippy/pull/8518)
+* Moved [`implicit_saturating_sub`] to `style` (Now warn-by-default)
+  [#9584](https://github.com/rust-lang/rust-clippy/pull/9584)
+* Moved `derive_partial_eq_without_eq` to `nursery` (now allow-by-default)
+  [#9536](https://github.com/rust-lang/rust-clippy/pull/9536)
+
+### Enhancements
+
+* [`nonstandard_macro_braces`]: Now includes `matches!()` in the default lint config
+  [#9471](https://github.com/rust-lang/rust-clippy/pull/9471)
+* [`suboptimal_flops`]: Now supports multiplication and subtraction operations
+  [#9581](https://github.com/rust-lang/rust-clippy/pull/9581)
+* [`arithmetic_side_effects`]: Now detects cases with literals behind references
+  [#9587](https://github.com/rust-lang/rust-clippy/pull/9587)
+* [`upper_case_acronyms`]: Now also checks enum names
+  [#9580](https://github.com/rust-lang/rust-clippy/pull/9580)
+* [`needless_borrowed_reference`]: Now lints nested patterns
+  [#9573](https://github.com/rust-lang/rust-clippy/pull/9573)
+* [`unnecessary_cast`]: Now works for non-trivial non-literal expressions
+  [#9576](https://github.com/rust-lang/rust-clippy/pull/9576)
+* [`arithmetic_side_effects`]: Now detects operations with custom types
+  [#9559](https://github.com/rust-lang/rust-clippy/pull/9559)
+* [`disallowed_methods`], [`disallowed_types`]: Not correctly lints types, functions and macros
+  with the same path
+  [#9495](https://github.com/rust-lang/rust-clippy/pull/9495)
+* [`self_named_module_files`], [`mod_module_files`]: Now take remapped path prefixes into account
+  [#9475](https://github.com/rust-lang/rust-clippy/pull/9475)
+* [`bool_to_int_with_if`]: Now detects the inverse if case
+  [#9476](https://github.com/rust-lang/rust-clippy/pull/9476)
+
+### False Positive Fixes
+
+* [`arithmetic_side_effects`]: Now allows operations that can't overflow
+  [#9474](https://github.com/rust-lang/rust-clippy/pull/9474)
+* [`unnecessary_lazy_evaluations`]: No longer lints in external macros
+  [#9486](https://github.com/rust-lang/rust-clippy/pull/9486)
+* [`needless_borrow`], [`explicit_auto_deref`]: No longer lint on unions that require the reference
+  [#9490](https://github.com/rust-lang/rust-clippy/pull/9490)
+* [`almost_complete_letter_range`]: No longer lints in external macros
+  [#9467](https://github.com/rust-lang/rust-clippy/pull/9467)
+* [`drop_copy`]: No longer lints on idiomatic cases in match arms 
+  [#9491](https://github.com/rust-lang/rust-clippy/pull/9491)
+* [`question_mark`]: No longer lints in const context
+  [#9487](https://github.com/rust-lang/rust-clippy/pull/9487)
+* [`collapsible_if`]: Suggestion now work in macros
+  [#9410](https://github.com/rust-lang/rust-clippy/pull/9410)
+* [`std_instead_of_core`]: No longer triggers on unstable modules
+  [#9545](https://github.com/rust-lang/rust-clippy/pull/9545)
+* [`unused_peekable`]: No longer lints, if the peak is done in a closure or function
+  [#9465](https://github.com/rust-lang/rust-clippy/pull/9465)
+* [`useless_attribute`]: No longer lints on `#[allow]` attributes for [`unsafe_removed_from_name`]
+  [#9593](https://github.com/rust-lang/rust-clippy/pull/9593)
+* [`unnecessary_lazy_evaluations`]: No longer suggest switching to early evaluation when type has
+  custom `Drop` implementation
+  [#9551](https://github.com/rust-lang/rust-clippy/pull/9551)
+* [`unnecessary_cast`]: No longer lints on negative hexadecimal literals when cast as floats
+  [#9609](https://github.com/rust-lang/rust-clippy/pull/9609)
+* [`use_self`]: No longer lints in proc macros
+  [#9454](https://github.com/rust-lang/rust-clippy/pull/9454)
+* [`never_loop`]: Now takes `let ... else` statements into consideration.
+  [#9496](https://github.com/rust-lang/rust-clippy/pull/9496)
+* [`default_numeric_fallback`]: Now ignores constants
+  [#9636](https://github.com/rust-lang/rust-clippy/pull/9636)
+* [`uninit_vec`]: No longer lints `Vec::set_len(0)`
+  [#9519](https://github.com/rust-lang/rust-clippy/pull/9519)
+* [`arithmetic_side_effects`]: Now ignores references to integer types
+  [#9507](https://github.com/rust-lang/rust-clippy/pull/9507)
+* [`large_stack_arrays`]: No longer lints inside static items
+  [#9466](https://github.com/rust-lang/rust-clippy/pull/9466)
+* [`ref_option_ref`]: No longer lints if the inner reference is mutable
+  [#9684](https://github.com/rust-lang/rust-clippy/pull/9684)
+* [`ptr_arg`]: No longer lints if the argument is used as an incomplete trait object
+  [#9645](https://github.com/rust-lang/rust-clippy/pull/9645)
+* [`should_implement_trait`]: Now also works for `default` methods
+  [#9546](https://github.com/rust-lang/rust-clippy/pull/9546)
+
+### Suggestion Fixes/Improvements
+
+* [`derivable_impls`]: The suggestion is now machine applicable
+  [#9429](https://github.com/rust-lang/rust-clippy/pull/9429)
+* [`match_single_binding`]: The suggestion now handles scrutinies with side effects better
+  [#9601](https://github.com/rust-lang/rust-clippy/pull/9601)
+* [`zero_prefixed_literal`]: Only suggests using octal numbers, if this is possible
+  [#9652](https://github.com/rust-lang/rust-clippy/pull/9652)
+* [`rc_buffer`]: The suggestion is no longer machine applicable to avoid semantic changes
+  [#9633](https://github.com/rust-lang/rust-clippy/pull/9633)
+* [`print_literal`], [`write_literal`], [`uninlined_format_args`]: The suggestion now ignores
+  comments after the macro call.
+  [#9586](https://github.com/rust-lang/rust-clippy/pull/9586)
+* [`expect_fun_call`]:Improved the suggestion for `format!` calls with captured variables
+  [#9586](https://github.com/rust-lang/rust-clippy/pull/9586)
+* [`nonstandard_macro_braces`]: The suggestion is now machine applicable and will no longer
+  replace brackets inside the macro argument.
+  [#9499](https://github.com/rust-lang/rust-clippy/pull/9499)
+* [`from_over_into`]: The suggestion is now a machine applicable and contains explanations
+  [#9649](https://github.com/rust-lang/rust-clippy/pull/9649)
+* [`needless_return`]: The automatic suggestion now removes all required semicolons
+  [#9497](https://github.com/rust-lang/rust-clippy/pull/9497)
+* [`to_string_in_format_args`]: The suggestion now keeps parenthesis around values
+  [#9590](https://github.com/rust-lang/rust-clippy/pull/9590)
+* [`manual_assert`]: The suggestion now preserves comments
+  [#9479](https://github.com/rust-lang/rust-clippy/pull/9479)
+* [`redundant_allocation`]: The suggestion applicability is now marked `MaybeIncorrect` to
+  avoid semantic changes
+  [#9634](https://github.com/rust-lang/rust-clippy/pull/9634)
+* [`assertions_on_result_states`]: The suggestion has been corrected, for cases where the
+  `assert!` is not in a statement.
+  [#9453](https://github.com/rust-lang/rust-clippy/pull/9453)
+* [`nonminimal_bool`]: The suggestion no longer expands macros
+  [#9457](https://github.com/rust-lang/rust-clippy/pull/9457)
+* [`collapsible_match`]: Now specifies field names, when a struct is destructed
+  [#9685](https://github.com/rust-lang/rust-clippy/pull/9685)
+* [`unnecessary_cast`]: The suggestion now adds parenthesis for negative numbers
+  [#9577](https://github.com/rust-lang/rust-clippy/pull/9577)
+* [`redundant_closure`]: The suggestion now works for `impl FnMut` arguments
+  [#9556](https://github.com/rust-lang/rust-clippy/pull/9556)
+
+### ICE Fixes
+
+* [`unnecessary_to_owned`]: Avoid ICEs in favor of false negatives if information is missing
+  [#9505](https://github.com/rust-lang/rust-clippy/pull/9505)
+* [`manual_range_contains`]: No longer ICEs on values behind references
+  [#9627](https://github.com/rust-lang/rust-clippy/pull/9627)
+* [`needless_pass_by_value`]: No longer ICEs on unsized `dyn Fn` arguments
+  [#9531](https://github.com/rust-lang/rust-clippy/pull/9531)
+* `*_interior_mutable_const` lints: no longer ICE on const unions containing `!Freeze` types
+  [#9539](https://github.com/rust-lang/rust-clippy/pull/9539)
+
+### Others
+
+* Released `rustc_tools_util` for version information on `Crates.io`. (Further adjustments will
+  not be published as part of this changelog)
 
 ## Rust 1.65
 
-Current stable, released 2022-11-03
+Released 2022-11-03
 
 [3c7e7dbc...b52fb523](https://github.com/rust-lang/rust-clippy/compare/3c7e7dbc...b52fb523)
 
@@ -3875,6 +4045,7 @@ Released 2018-09-13
 [`alloc_instead_of_core`]: https://rust-lang.github.io/rust-clippy/master/index.html#alloc_instead_of_core
 [`allow_attributes_without_reason`]: https://rust-lang.github.io/rust-clippy/master/index.html#allow_attributes_without_reason
 [`almost_complete_letter_range`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_letter_range
+[`almost_complete_range`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_range
 [`almost_swapped`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_swapped
 [`approx_constant`]: https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant
 [`arithmetic_side_effects`]: https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects
@@ -4353,6 +4524,8 @@ Released 2018-09-13
 [`self_named_constructors`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_named_constructors
 [`self_named_module_files`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_named_module_files
 [`semicolon_if_nothing_returned`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_if_nothing_returned
+[`semicolon_inside_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_inside_block
+[`semicolon_outside_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_outside_block
 [`separated_literal_suffix`]: https://rust-lang.github.io/rust-clippy/master/index.html#separated_literal_suffix
 [`serde_api_misuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#serde_api_misuse
 [`shadow_reuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_reuse
index fe425a2fb991fdb1377b985eb83d007156ad58dc..f8cb4b7219c47467e6e41412b57f17733c02a46b 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "clippy"
-version = "0.1.67"
+version = "0.1.68"
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
@@ -23,7 +23,7 @@ path = "src/driver.rs"
 [dependencies]
 clippy_lints = { path = "clippy_lints" }
 semver = "1.0"
-rustc_tools_util = "0.2.1"
+rustc_tools_util = "0.3.0"
 tempfile = { version = "3.2", optional = true }
 termize = "0.1"
 
@@ -55,7 +55,7 @@ tokio = { version = "1", features = ["io-util"] }
 rustc-semver = "1.1"
 
 [build-dependencies]
-rustc_tools_util = "0.2.1"
+rustc_tools_util = "0.3.0"
 
 [features]
 deny-warnings = ["clippy_lints/deny-warnings"]
index 6248d588a890b9dc13038eaa051ca56cd46d18b6..23867df8efe1dc0ce542f3e299df8326fe1ad56d 100644 (file)
@@ -1,6 +1,6 @@
 # Clippy
 
-[![Clippy Test](https://github.com/rust-lang/rust-clippy/workflows/Clippy%20Test/badge.svg?branch=auto&event=push)](https://github.com/rust-lang/rust-clippy/actions?query=workflow%3A%22Clippy+Test%22+event%3Apush+branch%3Aauto)
+[![Clippy Test](https://github.com/rust-lang/rust-clippy/workflows/Clippy%20Test%20(bors)/badge.svg?branch=auto&event=push)](https://github.com/rust-lang/rust-clippy/actions?query=workflow%3A%22Clippy+Test+(bors)%22+event%3Apush+branch%3Aauto)
 [![License: MIT OR Apache-2.0](https://img.shields.io/crates/l/clippy.svg)](https://github.com/rust-lang/rust-clippy#license)
 
 A collection of lints to catch common mistakes and improve your
index b5484bec3c8b8dca5dc0a00930d846e60533d4a7..b79d09b0dd2d2776e98a4ae73de9c2884e722677 100644 (file)
@@ -3,17 +3,5 @@ fn main() {
     println!("cargo:rustc-env=PROFILE={}", std::env::var("PROFILE").unwrap());
     // Don't rebuild even if nothing changed
     println!("cargo:rerun-if-changed=build.rs");
-    // forward git repo hashes we build at
-    println!(
-        "cargo:rustc-env=GIT_HASH={}",
-        rustc_tools_util::get_commit_hash().unwrap_or_default()
-    );
-    println!(
-        "cargo:rustc-env=COMMIT_DATE={}",
-        rustc_tools_util::get_commit_date().unwrap_or_default()
-    );
-    println!(
-        "cargo:rustc-env=RUSTC_RELEASE_CHANNEL={}",
-        rustc_tools_util::get_channel()
-    );
+    rustc_tools_util::setup_version_info!();
 }
index aedff24c12c6078b7aec3236f261837008df36e3..a9f69b1ba6300907b1ec7c4770a53ab98f9eceba 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "clippy_lints"
-version = "0.1.67"
+version = "0.1.68"
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
diff --git a/src/tools/clippy/clippy_lints/src/almost_complete_letter_range.rs b/src/tools/clippy/clippy_lints/src/almost_complete_letter_range.rs
deleted file mode 100644 (file)
index 52beaf5..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::source::{trim_span, walk_span_to_context};
-use rustc_ast::ast::{Expr, ExprKind, LitKind, Pat, PatKind, RangeEnd, RangeLimits};
-use rustc_errors::Applicability;
-use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::Span;
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for ranges which almost include the entire range of letters from 'a' to 'z', but
-    /// don't because they're a half open range.
-    ///
-    /// ### Why is this bad?
-    /// This (`'a'..'z'`) is almost certainly a typo meant to include all letters.
-    ///
-    /// ### Example
-    /// ```rust
-    /// let _ = 'a'..'z';
-    /// ```
-    /// Use instead:
-    /// ```rust
-    /// let _ = 'a'..='z';
-    /// ```
-    #[clippy::version = "1.63.0"]
-    pub ALMOST_COMPLETE_LETTER_RANGE,
-    suspicious,
-    "almost complete letter range"
-}
-impl_lint_pass!(AlmostCompleteLetterRange => [ALMOST_COMPLETE_LETTER_RANGE]);
-
-pub struct AlmostCompleteLetterRange {
-    msrv: Msrv,
-}
-impl AlmostCompleteLetterRange {
-    pub fn new(msrv: Msrv) -> Self {
-        Self { msrv }
-    }
-}
-impl EarlyLintPass for AlmostCompleteLetterRange {
-    fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &Expr) {
-        if let ExprKind::Range(Some(start), Some(end), RangeLimits::HalfOpen) = &e.kind {
-            let ctxt = e.span.ctxt();
-            let sugg = if let Some(start) = walk_span_to_context(start.span, ctxt)
-                && let Some(end) = walk_span_to_context(end.span, ctxt)
-                && self.msrv.meets(msrvs::RANGE_INCLUSIVE)
-            {
-                Some((trim_span(cx.sess().source_map(), start.between(end)), "..="))
-            } else {
-                None
-            };
-            check_range(cx, e.span, start, end, sugg);
-        }
-    }
-
-    fn check_pat(&mut self, cx: &EarlyContext<'_>, p: &Pat) {
-        if let PatKind::Range(Some(start), Some(end), kind) = &p.kind
-            && matches!(kind.node, RangeEnd::Excluded)
-        {
-            let sugg = if self.msrv.meets(msrvs::RANGE_INCLUSIVE) {
-                "..="
-            } else {
-                "..."
-            };
-            check_range(cx, p.span, start, end, Some((kind.span, sugg)));
-        }
-    }
-
-    extract_msrv_attr!(EarlyContext);
-}
-
-fn check_range(cx: &EarlyContext<'_>, span: Span, start: &Expr, end: &Expr, sugg: Option<(Span, &str)>) {
-    if let ExprKind::Lit(start_token_lit) = start.peel_parens().kind
-        && let ExprKind::Lit(end_token_lit) = end.peel_parens().kind
-        && matches!(
-            (
-                LitKind::from_token_lit(start_token_lit),
-                LitKind::from_token_lit(end_token_lit),
-            ),
-            (
-                Ok(LitKind::Byte(b'a') | LitKind::Char('a')),
-                Ok(LitKind::Byte(b'z') | LitKind::Char('z'))
-            )
-            | (
-                Ok(LitKind::Byte(b'A') | LitKind::Char('A')),
-                Ok(LitKind::Byte(b'Z') | LitKind::Char('Z')),
-            )
-        )
-        && !in_external_macro(cx.sess(), span)
-    {
-        span_lint_and_then(
-            cx,
-            ALMOST_COMPLETE_LETTER_RANGE,
-            span,
-            "almost complete ascii letter range",
-            |diag| {
-                if let Some((span, sugg)) = sugg {
-                    diag.span_suggestion(
-                        span,
-                        "use an inclusive range",
-                        sugg,
-                        Applicability::MaybeIncorrect,
-                    );
-                }
-            }
-        );
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/almost_complete_range.rs b/src/tools/clippy/clippy_lints/src/almost_complete_range.rs
new file mode 100644 (file)
index 0000000..42e14b5
--- /dev/null
@@ -0,0 +1,114 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::source::{trim_span, walk_span_to_context};
+use rustc_ast::ast::{Expr, ExprKind, LitKind, Pat, PatKind, RangeEnd, RangeLimits};
+use rustc_errors::Applicability;
+use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::Span;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for ranges which almost include the entire range of letters from 'a' to 'z'
+    /// or digits from '0' to '9', but don't because they're a half open range.
+    ///
+    /// ### Why is this bad?
+    /// This (`'a'..'z'`) is almost certainly a typo meant to include all letters.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let _ = 'a'..'z';
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let _ = 'a'..='z';
+    /// ```
+    #[clippy::version = "1.63.0"]
+    pub ALMOST_COMPLETE_RANGE,
+    suspicious,
+    "almost complete range"
+}
+impl_lint_pass!(AlmostCompleteRange => [ALMOST_COMPLETE_RANGE]);
+
+pub struct AlmostCompleteRange {
+    msrv: Msrv,
+}
+impl AlmostCompleteRange {
+    pub fn new(msrv: Msrv) -> Self {
+        Self { msrv }
+    }
+}
+impl EarlyLintPass for AlmostCompleteRange {
+    fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &Expr) {
+        if let ExprKind::Range(Some(start), Some(end), RangeLimits::HalfOpen) = &e.kind {
+            let ctxt = e.span.ctxt();
+            let sugg = if let Some(start) = walk_span_to_context(start.span, ctxt)
+                && let Some(end) = walk_span_to_context(end.span, ctxt)
+                && self.msrv.meets(msrvs::RANGE_INCLUSIVE)
+            {
+                Some((trim_span(cx.sess().source_map(), start.between(end)), "..="))
+            } else {
+                None
+            };
+            check_range(cx, e.span, start, end, sugg);
+        }
+    }
+
+    fn check_pat(&mut self, cx: &EarlyContext<'_>, p: &Pat) {
+        if let PatKind::Range(Some(start), Some(end), kind) = &p.kind
+            && matches!(kind.node, RangeEnd::Excluded)
+        {
+            let sugg = if self.msrv.meets(msrvs::RANGE_INCLUSIVE) {
+                "..="
+            } else {
+                "..."
+            };
+            check_range(cx, p.span, start, end, Some((kind.span, sugg)));
+        }
+    }
+
+    extract_msrv_attr!(EarlyContext);
+}
+
+fn check_range(cx: &EarlyContext<'_>, span: Span, start: &Expr, end: &Expr, sugg: Option<(Span, &str)>) {
+    if let ExprKind::Lit(start_token_lit) = start.peel_parens().kind
+        && let ExprKind::Lit(end_token_lit) = end.peel_parens().kind
+        && matches!(
+            (
+                LitKind::from_token_lit(start_token_lit),
+                LitKind::from_token_lit(end_token_lit),
+            ),
+            (
+                Ok(LitKind::Byte(b'a') | LitKind::Char('a')),
+                Ok(LitKind::Byte(b'z') | LitKind::Char('z'))
+            )
+            | (
+                Ok(LitKind::Byte(b'A') | LitKind::Char('A')),
+                Ok(LitKind::Byte(b'Z') | LitKind::Char('Z')),
+            )
+            | (
+                Ok(LitKind::Byte(b'0') | LitKind::Char('0')),
+                Ok(LitKind::Byte(b'9') | LitKind::Char('9')),
+            )
+        )
+        && !in_external_macro(cx.sess(), span)
+    {
+        span_lint_and_then(
+            cx,
+            ALMOST_COMPLETE_RANGE,
+            span,
+            "almost complete ascii range",
+            |diag| {
+                if let Some((span, sugg)) = sugg {
+                    diag.span_suggestion(
+                        span,
+                        "use an inclusive range",
+                        sugg,
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+            }
+        );
+    }
+}
index 36daceabe0bea61a034aeac4dd894cbcff834eb0..91900542af8330e52d72655efb34be044bbfbbf5 100644 (file)
@@ -30,7 +30,7 @@
     /// ```rust
     /// let x: Box<String> = Box::default();
     /// ```
-    #[clippy::version = "1.65.0"]
+    #[clippy::version = "1.66.0"]
     pub BOX_DEFAULT,
     perf,
     "Using Box::new(T::default()) instead of Box::default()"
index c6d505c4a181fc2e3b52c2be3b1d713f7123eec2..161e3a698e9ea6133ba0d6a86e2ad70983d7dbf8 100644 (file)
     /// ```rust,ignore
     /// let _: = 0_u64;
     /// ```
-    #[clippy::version = "1.64.0"]
+    #[clippy::version = "1.66.0"]
     pub CAST_NAN_TO_INT,
     suspicious,
     "casting a known floating-point NaN into an integer"
index e4d76f07d6b482b13fa7d5fbaf9cb8b6ce9923fd..3cd7d1d7e722833645876976a615e1d5a7de123f 100644 (file)
@@ -35,7 +35,7 @@
     crate::utils::internal_lints::produce_ice::PRODUCE_ICE_INFO,
     #[cfg(feature = "internal")]
     crate::utils::internal_lints::unnecessary_def_path::UNNECESSARY_DEF_PATH_INFO,
-    crate::almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE_INFO,
+    crate::almost_complete_range::ALMOST_COMPLETE_RANGE_INFO,
     crate::approx_const::APPROX_CONSTANT_INFO,
     crate::as_conversions::AS_CONVERSIONS_INFO,
     crate::asm_syntax::INLINE_ASM_X86_ATT_SYNTAX_INFO,
     crate::returns::NEEDLESS_RETURN_INFO,
     crate::same_name_method::SAME_NAME_METHOD_INFO,
     crate::self_named_constructors::SELF_NAMED_CONSTRUCTORS_INFO,
+    crate::semicolon_block::SEMICOLON_INSIDE_BLOCK_INFO,
+    crate::semicolon_block::SEMICOLON_OUTSIDE_BLOCK_INFO,
     crate::semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED_INFO,
     crate::serde_api::SERDE_API_MISUSE_INFO,
     crate::shadow::SHADOW_REUSE_INFO,
index 31183266acfcba44236911f54cd37d25113dc8ef..7b43d8ccc67d1fec92a5be0389860e9c8c6658a5 100644 (file)
@@ -1390,10 +1390,15 @@ fn ty_auto_deref_stability<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, precedenc
                 continue;
             },
             ty::Param(_) => TyPosition::new_deref_stable_for_result(precedence, ty),
-            ty::Alias(ty::Projection, _) if ty.has_non_region_param() => TyPosition::new_deref_stable_for_result(precedence, ty),
-            ty::Infer(_) | ty::Error(_) | ty::Bound(..) | ty::Alias(ty::Opaque, ..) | ty::Placeholder(_) | ty::Dynamic(..) => {
-                Position::ReborrowStable(precedence).into()
+            ty::Alias(ty::Projection, _) if ty.has_non_region_param() => {
+                TyPosition::new_deref_stable_for_result(precedence, ty)
             },
+            ty::Infer(_)
+            | ty::Error(_)
+            | ty::Bound(..)
+            | ty::Alias(ty::Opaque, ..)
+            | ty::Placeholder(_)
+            | ty::Dynamic(..) => Position::ReborrowStable(precedence).into(),
             ty::Adt(..) if ty.has_placeholders() || ty.has_opaque_types() => {
                 Position::ReborrowStable(precedence).into()
             },
index 3f0b165f2b604a006e253bf4972c458611599212..cf3483d4c00b17134724bbc51eafcf6abb904aaa 100644 (file)
@@ -513,10 +513,7 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) ->
         tcx.mk_predicates(ty_predicates.iter().map(|&(p, _)| p).chain(
             params.iter().filter(|&&(_, needs_eq)| needs_eq).map(|&(param, _)| {
                 tcx.mk_predicate(Binder::dummy(PredicateKind::Clause(Clause::Trait(TraitPredicate {
-                    trait_ref: tcx.mk_trait_ref(
-                        eq_trait_id,
-                        [tcx.mk_param_from_def(param)],
-                    ),
+                    trait_ref: tcx.mk_trait_ref(eq_trait_id, [tcx.mk_param_from_def(param)]),
                     constness: BoundConstness::NotConst,
                     polarity: ImplPolarity::Positive,
                 }))))
index 68122b4cef577fede678085f08f58baa9181cbe1..1971cab64ef38a8f01890c1cd8394f7bd238af96 100644 (file)
@@ -47,7 +47,7 @@
     ///     value: usize,
     /// }
     /// ```
-    #[clippy::version = "1.65.0"]
+    #[clippy::version = "1.66.0"]
     pub DISALLOWED_MACROS,
     style,
     "use of a disallowed macro"
index 111b624f52994d747fc327b41830a4cbbba11ff8..69f7c152fc4af84ad6eb70ce628129babe33502f 100644 (file)
@@ -2,7 +2,8 @@
 use clippy_utils::is_diag_trait_item;
 use clippy_utils::macros::FormatParamKind::{Implicit, Named, NamedInline, Numbered, Starred};
 use clippy_utils::macros::{
-    is_format_macro, is_panic, root_macro_call, Count, FormatArg, FormatArgsExpn, FormatParam, FormatParamUsage,
+    is_assert_macro, is_format_macro, is_panic, root_macro_call, Count, FormatArg, FormatArgsExpn, FormatParam,
+    FormatParamUsage,
 };
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet_opt;
     ///
     /// If a format string contains a numbered argument that cannot be inlined
     /// nothing will be suggested, e.g. `println!("{0}={1}", var, 1+2)`.
-    #[clippy::version = "1.65.0"]
+    #[clippy::version = "1.66.0"]
     pub UNINLINED_FORMAT_ARGS,
     style,
     "using non-inlined variables in `format!` calls"
@@ -290,8 +291,9 @@ fn check_uninlined_args(
     if args.format_string.span.from_expansion() {
         return;
     }
-    if call_site.edition() < Edition2021 && is_panic(cx, def_id) {
-        // panic! before 2021 edition considers a single string argument as non-format
+    if call_site.edition() < Edition2021 && (is_panic(cx, def_id) || is_assert_macro(cx, def_id)) {
+        // panic!, assert!, and debug_assert! before 2021 edition considers a single string argument as
+        // non-format
         return;
     }
 
index 0634b2798fefee63669f0a2325e9e89b8332ca7a..a92f7548ff254d16a2f51b255675650d139e8734 100644 (file)
@@ -10,7 +10,7 @@
     TyKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::hir::nested_filter::OnlyBodies;
+use rustc_middle::{hir::nested_filter::OnlyBodies, ty};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::symbol::{kw, sym};
 use rustc_span::{Span, Symbol};
@@ -78,6 +78,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
             && let Some(GenericArgs { args: [GenericArg::Type(target_ty)], .. }) = into_trait_seg.args
             && let Some(middle_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id)
             && cx.tcx.is_diagnostic_item(sym::Into, middle_trait_ref.def_id)
+            && !matches!(middle_trait_ref.substs.type_at(1).kind(), ty::Alias(ty::Opaque, _))
         {
             span_lint_and_then(
                 cx,
index bf1351829c6a5e2e61755dc873df6494e5009ab5..6e19343931ecb846bc9d9ece97efd37c9f27683b 100644 (file)
@@ -31,7 +31,7 @@
     ///
     /// u = u.saturating_add(1);
     /// ```
-    #[clippy::version = "1.65.0"]
+    #[clippy::version = "1.66.0"]
     pub IMPLICIT_SATURATING_ADD,
     style,
     "Perform saturating addition instead of implicitly checking max bound of data type"
index 4cd7dff4cfd762c95352f230beb6b8b3f0652458..eebfb753a0c5dfdefcb0e542676fcbf9c8faba6d 100644 (file)
@@ -1,13 +1,13 @@
 //! lint on indexing and slicing operations
 
 use clippy_utils::consts::{constant, Constant};
-use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
+use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
 use clippy_utils::higher;
 use rustc_ast::ast::RangeLimits;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 
 declare_clippy_lint! {
     /// ### What it does
     "indexing/slicing usage"
 }
 
-declare_lint_pass!(IndexingSlicing => [INDEXING_SLICING, OUT_OF_BOUNDS_INDEXING]);
+impl_lint_pass!(IndexingSlicing => [INDEXING_SLICING, OUT_OF_BOUNDS_INDEXING]);
+
+#[derive(Copy, Clone)]
+pub struct IndexingSlicing {
+    suppress_restriction_lint_in_const: bool,
+}
+
+impl IndexingSlicing {
+    pub fn new(suppress_restriction_lint_in_const: bool) -> Self {
+        Self {
+            suppress_restriction_lint_in_const,
+        }
+    }
+}
 
 impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if cx.tcx.hir().is_inside_const_context(expr.hir_id) {
+        if self.suppress_restriction_lint_in_const && cx.tcx.hir().is_inside_const_context(expr.hir_id) {
             return;
         }
 
         if let ExprKind::Index(array, index) = &expr.kind {
+            let note = "the suggestion might not be applicable in constant blocks";
             let ty = cx.typeck_results().expr_ty(array).peel_refs();
             if let Some(range) = higher::Range::hir(index) {
                 // Ranged indexes, i.e., &x[n..m], &x[n..], &x[..n] and &x[..]
@@ -141,7 +155,13 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                     (None, None) => return, // [..] is ok.
                 };
 
-                span_lint_and_help(cx, INDEXING_SLICING, expr.span, "slicing may panic", None, help_msg);
+                span_lint_and_then(cx, INDEXING_SLICING, expr.span, "slicing may panic", |diag| {
+                    diag.help(help_msg);
+
+                    if cx.tcx.hir().is_inside_const_context(expr.hir_id) {
+                        diag.note(note);
+                    }
+                });
             } else {
                 // Catchall non-range index, i.e., [n] or [n << m]
                 if let ty::Array(..) = ty.kind() {
@@ -156,14 +176,13 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                     }
                 }
 
-                span_lint_and_help(
-                    cx,
-                    INDEXING_SLICING,
-                    expr.span,
-                    "indexing may panic",
-                    None,
-                    "consider using `.get(n)` or `.get_mut(n)` instead",
-                );
+                span_lint_and_then(cx, INDEXING_SLICING, expr.span, "indexing may panic", |diag| {
+                    diag.help("consider using `.get(n)` or `.get_mut(n)` instead");
+
+                    if cx.tcx.hir().is_inside_const_context(expr.hir_id) {
+                        diag.note(note);
+                    }
+                });
             }
         }
     }
index 73841f9aa9a2112a626dd86e95b34779d90b33ff..e88d1764a24896a23d168a5b01c2d908e851e804 100644 (file)
@@ -1,13 +1,13 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed};
+use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed, peel_ref_operators};
 use if_chain::if_chain;
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::def_id::DefIdSet;
 use rustc_hir::{
     def_id::DefId, AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, ImplItem, ImplItemKind, ImplicitSelfKind, Item,
-    ItemKind, Mutability, Node, TraitItemRef, TyKind,
+    ItemKind, Mutability, Node, TraitItemRef, TyKind, UnOp,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, AssocKind, FnSig, Ty};
@@ -16,6 +16,7 @@
     source_map::{Span, Spanned, Symbol},
     symbol::sym,
 };
+use std::borrow::Cow;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -428,16 +429,23 @@ fn check_len(
 fn check_empty_expr(cx: &LateContext<'_>, span: Span, lit1: &Expr<'_>, lit2: &Expr<'_>, op: &str) {
     if (is_empty_array(lit2) || is_empty_string(lit2)) && has_is_empty(cx, lit1) {
         let mut applicability = Applicability::MachineApplicable;
+
+        let lit1 = peel_ref_operators(cx, lit1);
+        let mut lit_str = snippet_with_applicability(cx, lit1.span, "_", &mut applicability);
+
+        // Wrap the expression in parentheses if it's a deref expression. Otherwise operator precedence will
+        // cause the code to dereference boolean(won't compile).
+        if let ExprKind::Unary(UnOp::Deref, _) = lit1.kind {
+            lit_str = Cow::from(format!("({lit_str})"));
+        }
+
         span_lint_and_sugg(
             cx,
             COMPARISON_TO_EMPTY,
             span,
             "comparison to empty slice",
             &format!("using `{op}is_empty` is clearer and more explicit"),
-            format!(
-                "{op}{}.is_empty()",
-                snippet_with_applicability(cx, lit1.span, "_", &mut applicability)
-            ),
+            format!("{op}{lit_str}.is_empty()"),
             applicability,
         );
     }
index 7b17d8a156d5af6ddb3b9417b7990e65d2a3d5ee..39850d598038f1b3d15fce37e068528a3c9b1c8d 100644 (file)
@@ -66,7 +66,7 @@
 mod renamed_lints;
 
 // begin lints modules, do not remove this comment, it’s used in `update_lints`
-mod almost_complete_letter_range;
+mod almost_complete_range;
 mod approx_const;
 mod as_conversions;
 mod asm_syntax;
 mod returns;
 mod same_name_method;
 mod self_named_constructors;
+mod semicolon_block;
 mod semicolon_if_nothing_returned;
 mod serde_api;
 mod shadow;
@@ -507,9 +508,20 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     }
 
     let arithmetic_side_effects_allowed = conf.arithmetic_side_effects_allowed.clone();
+    let arithmetic_side_effects_allowed_binary = conf.arithmetic_side_effects_allowed_binary.clone();
+    let arithmetic_side_effects_allowed_unary = conf.arithmetic_side_effects_allowed_unary.clone();
     store.register_late_pass(move |_| {
         Box::new(operators::arithmetic_side_effects::ArithmeticSideEffects::new(
-            arithmetic_side_effects_allowed.clone(),
+            arithmetic_side_effects_allowed
+                .iter()
+                .flat_map(|el| [[el.clone(), "*".to_string()], ["*".to_string(), el.clone()]])
+                .chain(arithmetic_side_effects_allowed_binary.clone())
+                .collect(),
+            arithmetic_side_effects_allowed
+                .iter()
+                .chain(arithmetic_side_effects_allowed_unary.iter())
+                .cloned()
+                .collect(),
         ))
     });
     store.register_late_pass(|_| Box::new(utils::dump_hir::DumpHir));
@@ -538,7 +550,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(needless_bool::NeedlessBool));
     store.register_late_pass(|_| Box::new(needless_bool::BoolComparison));
     store.register_late_pass(|_| Box::new(needless_for_each::NeedlessForEach));
-    store.register_late_pass(|_| Box::new(misc::MiscLints));
+    store.register_late_pass(|_| Box::<misc::LintPass>::default());
     store.register_late_pass(|_| Box::new(eta_reduction::EtaReduction));
     store.register_late_pass(|_| Box::new(mut_mut::MutMut));
     store.register_late_pass(|_| Box::new(mut_reference::UnnecessaryMutPassed));
@@ -561,6 +573,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     let avoid_breaking_exported_api = conf.avoid_breaking_exported_api;
     let allow_expect_in_tests = conf.allow_expect_in_tests;
     let allow_unwrap_in_tests = conf.allow_unwrap_in_tests;
+    let suppress_restriction_lint_in_const = conf.suppress_restriction_lint_in_const;
     store.register_late_pass(move |_| Box::new(approx_const::ApproxConstant::new(msrv())));
     store.register_late_pass(move |_| {
         Box::new(methods::Methods::new(
@@ -682,7 +695,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(inherent_impl::MultipleInherentImpl));
     store.register_late_pass(|_| Box::new(neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd));
     store.register_late_pass(|_| Box::new(unwrap::Unwrap));
-    store.register_late_pass(|_| Box::new(indexing_slicing::IndexingSlicing));
+    store.register_late_pass(move |_| {
+        Box::new(indexing_slicing::IndexingSlicing::new(
+            suppress_restriction_lint_in_const,
+        ))
+    });
     store.register_late_pass(|_| Box::new(non_copy_const::NonCopyConst));
     store.register_late_pass(|_| Box::new(ptr_offset_with_cast::PtrOffsetWithCast));
     store.register_late_pass(|_| Box::new(redundant_clone::RedundantClone));
@@ -859,7 +876,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(rc_clone_in_vec_init::RcCloneInVecInit));
     store.register_early_pass(|| Box::<duplicate_mod::DuplicateMod>::default());
     store.register_early_pass(|| Box::new(unused_rounding::UnusedRounding));
-    store.register_early_pass(move || Box::new(almost_complete_letter_range::AlmostCompleteLetterRange::new(msrv())));
+    store.register_early_pass(move || Box::new(almost_complete_range::AlmostCompleteRange::new(msrv())));
     store.register_late_pass(|_| Box::new(swap_ptr_to_ref::SwapPtrToRef));
     store.register_late_pass(|_| Box::new(mismatching_type_param_order::TypeParamMismatch));
     store.register_late_pass(|_| Box::new(read_zero_byte_vec::ReadZeroByteVec));
@@ -884,6 +901,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(from_raw_with_void_ptr::FromRawWithVoidPtr));
     store.register_late_pass(|_| Box::new(suspicious_xor_used_as_pow::ConfusingXorAndPow));
     store.register_late_pass(move |_| Box::new(manual_is_ascii_check::ManualIsAsciiCheck::new(msrv())));
+    store.register_late_pass(|_| Box::new(semicolon_block::SemicolonBlock));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
index b6f4cf7bbb37f149eccda55bbc0ef40b2f08def9..28ee24309cc467e57c6f374f8b0d86a314134d57 100644 (file)
@@ -25,7 +25,6 @@ pub(super) struct IncrementVisitor<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,                  // context reference
     states: HirIdMap<IncrementVisitorVarState>, // incremented variables
     depth: u32,                                 // depth of conditional expressions
-    done: bool,
 }
 
 impl<'a, 'tcx> IncrementVisitor<'a, 'tcx> {
@@ -34,7 +33,6 @@ pub(super) fn new(cx: &'a LateContext<'tcx>) -> Self {
             cx,
             states: HirIdMap::default(),
             depth: 0,
-            done: false,
         }
     }
 
@@ -51,10 +49,6 @@ pub(super) fn into_results(self) -> impl Iterator<Item = HirId> {
 
 impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
-        if self.done {
-            return;
-        }
-
         // If node is a variable
         if let Some(def_id) = path_to_local(expr) {
             if let Some(parent) = get_parent_expr(self.cx, expr) {
@@ -95,7 +89,9 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
             walk_expr(self, expr);
             self.depth -= 1;
         } else if let ExprKind::Continue(_) = expr.kind {
-            self.done = true;
+            // If we see a `continue` block, then we increment depth so that the IncrementVisitor
+            // state will be set to DontWarn if we see the variable being modified anywhere afterwards.
+            self.depth += 1;
         } else {
             walk_expr(self, expr);
         }
index b8ed9b9ec18f718b0cc56160b0966a9e0cf220a5..4277455a3a21c8e096e0c36e588724d065372d99 100644 (file)
@@ -2,7 +2,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::macros::{root_macro_call, FormatArgsExpn};
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{peel_blocks_with_stmt, span_extract_comment, sugg};
+use clippy_utils::{is_else_clause, peel_blocks_with_stmt, span_extract_comment, sugg};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
@@ -47,6 +47,10 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
             if cx.tcx.item_name(macro_call.def_id) == sym::panic;
             if !cx.tcx.sess.source_map().is_multiline(cond.span);
             if let Some(format_args) = FormatArgsExpn::find_nested(cx, then, macro_call.expn);
+            // Don't change `else if foo { panic!(..) }` to `else { assert!(foo, ..) }` as it just
+            // shuffles the condition around.
+            // Should this have a config value?
+            if !is_else_clause(cx.tcx, expr);
             then {
                 let mut applicability = Applicability::MachineApplicable;
                 let format_args_snip = snippet_with_applicability(cx, format_args.inputs_span(), "..", &mut applicability);
index 5ab049d8d133fd34629227da15fbfef84c255915..d9ef7dffa020dbbd6d24715a35129fa72f88bcf2 100644 (file)
@@ -1,11 +1,12 @@
 use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::{diagnostics::span_lint_and_sugg, in_constant, macros::root_macro_call, source::snippet};
+use clippy_utils::{diagnostics::span_lint_and_sugg, higher, in_constant, macros::root_macro_call, source::snippet};
+use rustc_ast::ast::RangeLimits;
 use rustc_ast::LitKind::{Byte, Char};
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, PatKind, RangeEnd};
+use rustc_hir::{BorrowKind, Expr, ExprKind, PatKind, RangeEnd};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::{def_id::DefId, sym};
+use rustc_span::{def_id::DefId, sym, Span};
 
 declare_clippy_lint! {
     /// ### What it does
     ///     assert!(matches!(b'X', b'A'..=b'Z'));
     ///     assert!(matches!('2', '0'..='9'));
     ///     assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
+    ///
+    ///     ('0'..='9').contains(&'0');
+    ///     ('a'..='z').contains(&'a');
+    ///     ('A'..='Z').contains(&'A');
     /// }
     /// ```
     /// Use instead:
     ///     assert!(b'X'.is_ascii_uppercase());
     ///     assert!('2'.is_ascii_digit());
     ///     assert!('x'.is_ascii_alphabetic());
+    ///
+    ///     '0'.is_ascii_digit();
+    ///     'a'.is_ascii_lowercase();
+    ///     'A'.is_ascii_uppercase();
     /// }
     /// ```
     #[clippy::version = "1.66.0"]
@@ -75,40 +84,21 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             return;
         }
 
-        let Some(macro_call) = root_macro_call(expr.span) else { return };
-
-        if is_matches_macro(cx, macro_call.def_id) {
+        if let Some(macro_call) = root_macro_call(expr.span)
+            && is_matches_macro(cx, macro_call.def_id) {
             if let ExprKind::Match(recv, [arm, ..], _) = expr.kind {
                 let range = check_pat(&arm.pat.kind);
-
-                if let Some(sugg) = match range {
-                    CharRange::UpperChar => Some("is_ascii_uppercase"),
-                    CharRange::LowerChar => Some("is_ascii_lowercase"),
-                    CharRange::FullChar => Some("is_ascii_alphabetic"),
-                    CharRange::Digit => Some("is_ascii_digit"),
-                    CharRange::Otherwise => None,
-                } {
-                    let default_snip = "..";
-                    // `snippet_with_applicability` may set applicability to `MaybeIncorrect` for
-                    // macro span, so we check applicability manually by comparing `recv` is not default.
-                    let recv = snippet(cx, recv.span, default_snip);
-
-                    let applicability = if recv == default_snip {
-                        Applicability::HasPlaceholders
-                    } else {
-                        Applicability::MachineApplicable
-                    };
-
-                    span_lint_and_sugg(
-                        cx,
-                        MANUAL_IS_ASCII_CHECK,
-                        macro_call.span,
-                        "manual check for common ascii range",
-                        "try",
-                        format!("{recv}.{sugg}()"),
-                        applicability,
-                    );
-                }
+                check_is_ascii(cx, macro_call.span, recv, &range);
+            }
+        } else if let ExprKind::MethodCall(path, receiver, [arg], ..) = expr.kind
+            && path.ident.name == sym!(contains)
+            && let Some(higher::Range { start: Some(start), end: Some(end), limits: RangeLimits::Closed })
+            = higher::Range::hir(receiver) {
+            let range = check_range(start, end);
+            if let ExprKind::AddrOf(BorrowKind::Ref, _, e) = arg.kind {
+                check_is_ascii(cx, expr.span, e, &range);
+            } else {
+                check_is_ascii(cx, expr.span, arg, &range);
             }
         }
     }
@@ -116,6 +106,37 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
     extract_msrv_attr!(LateContext);
 }
 
+fn check_is_ascii(cx: &LateContext<'_>, span: Span, recv: &Expr<'_>, range: &CharRange) {
+    if let Some(sugg) = match range {
+        CharRange::UpperChar => Some("is_ascii_uppercase"),
+        CharRange::LowerChar => Some("is_ascii_lowercase"),
+        CharRange::FullChar => Some("is_ascii_alphabetic"),
+        CharRange::Digit => Some("is_ascii_digit"),
+        CharRange::Otherwise => None,
+    } {
+        let default_snip = "..";
+        // `snippet_with_applicability` may set applicability to `MaybeIncorrect` for
+        // macro span, so we check applicability manually by comparing `recv` is not default.
+        let recv = snippet(cx, recv.span, default_snip);
+
+        let applicability = if recv == default_snip {
+            Applicability::HasPlaceholders
+        } else {
+            Applicability::MachineApplicable
+        };
+
+        span_lint_and_sugg(
+            cx,
+            MANUAL_IS_ASCII_CHECK,
+            span,
+            "manual check for common ascii range",
+            "try",
+            format!("{recv}.{sugg}()"),
+            applicability,
+        );
+    }
+}
+
 fn check_pat(pat_kind: &PatKind<'_>) -> CharRange {
     match pat_kind {
         PatKind::Or(pats) => {
index 874d36ca9f4e378704019c8ae971c046c68d898c..9c6f8b43c078fbc77abd20dd5e7b374c47b6ffad 100644 (file)
@@ -151,7 +151,12 @@ fn emit_manual_let_else(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, pat:
             } else {
                 format!("{{ {sn_else} }}")
             };
-            let sugg = format!("let {sn_pat} = {sn_expr} else {else_bl};");
+            let sn_bl = if matches!(pat.kind, PatKind::Or(..)) {
+                format!("({sn_pat})")
+            } else {
+                sn_pat.into_owned()
+            };
+            let sugg = format!("let {sn_bl} = {sn_expr} else {else_bl};");
             diag.span_suggestion(span, "consider writing", sugg, app);
         },
     );
index c1e6c82487dc54d79b5e86185541108c149af35e..72cdb9c17361676240c5d767cd34a67db9164dbd 100644 (file)
@@ -70,7 +70,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
             && seg.args.is_none()
             && let hir::ExprKind::MethodCall(_, target_expr, [], _) = &collect_expr.kind
             && let Some(collect_def_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id)
-            && match_def_path(cx, collect_def_id, &paths::CORE_ITER_COLLECT) {
+            && cx.tcx.is_diagnostic_item(sym::iterator_collect_fn, collect_def_id)
+        {
             check_into_iter(cx, parent_expr, left_expr, target_expr, &self.msrv);
             check_iter(cx, parent_expr, left_expr, target_expr, &self.msrv);
             check_to_owned(cx, parent_expr, left_expr, target_expr, &self.msrv);
index 429cdc1918d79d7c03d1d5b24fe1bff04c8e7afb..06ecbce4e70e940bed5d941b41be29198817ef6c 100644 (file)
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_context;
-use clippy_utils::ty::peel_mid_ty_refs;
+use clippy_utils::ty::{implements_trait, peel_mid_ty_refs};
 use clippy_utils::{is_diag_item_method, is_diag_trait_item};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
@@ -19,6 +19,8 @@ pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv
         let (input_type, ref_count) = peel_mid_ty_refs(input_type);
         if let Some(ty_name) = input_type.ty_adt_def().map(|adt_def| cx.tcx.item_name(adt_def.did()));
         if return_type == input_type;
+        if let Some(clone_trait) = cx.tcx.lang_items().clone_trait();
+        if implements_trait(cx, return_type, clone_trait, &[]);
         then {
             let mut app = Applicability::MachineApplicable;
             let recv_snip = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut app).0;
index d2913680cbb742a11db2439aa668aff4d0a979c0..561e4336593b047ed5f071e89c18f5ec6c82c69e 100644 (file)
     /// let map: HashMap<u32, u32> = HashMap::new();
     /// let values = map.values().collect::<Vec<_>>();
     /// ```
-    #[clippy::version = "1.65.0"]
+    #[clippy::version = "1.66.0"]
     pub ITER_KV_MAP,
     complexity,
     "iterating on map using `iter` when `keys` or `values` would do"
@@ -3672,7 +3672,10 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                     no_effect_replace::check(cx, expr, arg1, arg2);
 
                     // Check for repeated `str::replace` calls to perform `collapsible_str_replace` lint
-                    if name == "replace" && let Some(("replace", ..)) = method_call(recv) {
+                    if self.msrv.meets(msrvs::PATTERN_TRAIT_CHAR_ARRAY)
+                        && name == "replace"
+                        && let Some(("replace", ..)) = method_call(recv)
+                    {
                         collapsible_str_replace::check(cx, expr, arg1, arg2);
                     }
                 },
index 7e3bed1e41a9457d9ca485d17ac4c0b92cf52dc7..660b7049cce974df23d916d36959aae105e45139 100644 (file)
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::ty::implements_trait;
-use clippy_utils::{get_trait_def_id, match_def_path, paths};
+use clippy_utils::{get_trait_def_id, is_expr_used_or_unified, match_def_path, paths};
 use rustc_ast::ast::{LitIntType, LitKind};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
@@ -19,6 +19,10 @@ pub(super) fn check<'tcx>(
     // Get receiver type
     let ty = cx.typeck_results().expr_ty(recv).peel_refs();
 
+    if is_expr_used_or_unified(cx.tcx, expr) {
+        return;
+    }
+
     if let Some(seek_trait_id) = get_trait_def_id(cx, &paths::STD_IO_SEEK) &&
         implements_trait(cx, ty, seek_trait_id, &[]) &&
         let ExprKind::Call(func, args1) = arg.kind &&
index 516dee20f8b15f17266ca589927a2631361f7072..9f4beb92b9d2e77bc265e5f13eb3b050989fc77a 100644 (file)
@@ -9,12 +9,14 @@
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::hygiene::DesugaringKind;
 use rustc_span::source_map::{ExpnKind, Span};
 
 use clippy_utils::sugg::Sugg;
-use clippy_utils::{get_parent_expr, in_constant, is_integer_literal, iter_input_pats, last_path_segment, SpanlessEq};
+use clippy_utils::{
+    get_parent_expr, in_constant, is_integer_literal, is_no_std_crate, iter_input_pats, last_path_segment, SpanlessEq,
+};
 
 declare_clippy_lint! {
     /// ### What it does
     "using `0 as *{const, mut} T`"
 }
 
-declare_lint_pass!(MiscLints => [
+pub struct LintPass {
+    std_or_core: &'static str,
+}
+impl Default for LintPass {
+    fn default() -> Self {
+        Self { std_or_core: "std" }
+    }
+}
+impl_lint_pass!(LintPass => [
     TOPLEVEL_REF_ARG,
     USED_UNDERSCORE_BINDING,
     SHORT_CIRCUIT_STATEMENT,
     ZERO_PTR,
 ]);
 
-impl<'tcx> LateLintPass<'tcx> for MiscLints {
+impl<'tcx> LateLintPass<'tcx> for LintPass {
+    fn check_crate(&mut self, cx: &LateContext<'_>) {
+        if is_no_std_crate(cx) {
+            self.std_or_core = "core";
+        }
+    }
+
     fn check_fn(
         &mut self,
         cx: &LateContext<'tcx>,
@@ -231,7 +247,7 @@ fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
 
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if let ExprKind::Cast(e, ty) = expr.kind {
-            check_cast(cx, expr.span, e, ty);
+            self.check_cast(cx, expr.span, e, ty);
             return;
         }
         if in_attributes_expansion(expr) || expr.span.is_desugaring(DesugaringKind::Await) {
@@ -310,26 +326,28 @@ fn non_macro_local(cx: &LateContext<'_>, res: def::Res) -> bool {
     }
 }
 
-fn check_cast(cx: &LateContext<'_>, span: Span, e: &Expr<'_>, ty: &hir::Ty<'_>) {
-    if_chain! {
-        if let TyKind::Ptr(ref mut_ty) = ty.kind;
-        if is_integer_literal(e, 0);
-        if !in_constant(cx, e.hir_id);
-        then {
-            let (msg, sugg_fn) = match mut_ty.mutbl {
-                Mutability::Mut => ("`0 as *mut _` detected", "std::ptr::null_mut"),
-                Mutability::Not => ("`0 as *const _` detected", "std::ptr::null"),
-            };
+impl LintPass {
+    fn check_cast(&self, cx: &LateContext<'_>, span: Span, e: &Expr<'_>, ty: &hir::Ty<'_>) {
+        if_chain! {
+            if let TyKind::Ptr(ref mut_ty) = ty.kind;
+            if is_integer_literal(e, 0);
+            if !in_constant(cx, e.hir_id);
+            then {
+                let (msg, sugg_fn) = match mut_ty.mutbl {
+                    Mutability::Mut => ("`0 as *mut _` detected", "ptr::null_mut"),
+                    Mutability::Not => ("`0 as *const _` detected", "ptr::null"),
+                };
 
-            let (sugg, appl) = if let TyKind::Infer = mut_ty.ty.kind {
-                (format!("{sugg_fn}()"), Applicability::MachineApplicable)
-            } else if let Some(mut_ty_snip) = snippet_opt(cx, mut_ty.ty.span) {
-                (format!("{sugg_fn}::<{mut_ty_snip}>()"), Applicability::MachineApplicable)
-            } else {
-                // `MaybeIncorrect` as type inference may not work with the suggested code
-                (format!("{sugg_fn}()"), Applicability::MaybeIncorrect)
-            };
-            span_lint_and_sugg(cx, ZERO_PTR, span, msg, "try", sugg, appl);
+                let (sugg, appl) = if let TyKind::Infer = mut_ty.ty.kind {
+                    (format!("{}::{sugg_fn}()", self.std_or_core), Applicability::MachineApplicable)
+                } else if let Some(mut_ty_snip) = snippet_opt(cx, mut_ty.ty.span) {
+                    (format!("{}::{sugg_fn}::<{mut_ty_snip}>()", self.std_or_core), Applicability::MachineApplicable)
+                } else {
+                    // `MaybeIncorrect` as type inference may not work with the suggested code
+                    (format!("{}::{sugg_fn}()", self.std_or_core), Applicability::MaybeIncorrect)
+                };
+                span_lint_and_sugg(cx, ZERO_PTR, span, msg, "try", sugg, appl);
+            }
         }
     }
 }
index 20b82d81a2aeb64e57d11994ceb3755a96e4cde4..4fbc8398e373443d5cc80c80eb2214933bfe786d 100644 (file)
@@ -5,25 +5,26 @@
     peel_hir_expr_refs,
 };
 use rustc_ast as ast;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::Ty;
 use rustc_session::impl_lint_pass;
 use rustc_span::source_map::{Span, Spanned};
 
-const HARD_CODED_ALLOWED: &[&str] = &[
-    "&str",
-    "f32",
-    "f64",
-    "std::num::Saturating",
-    "std::num::Wrapping",
-    "std::string::String",
+const HARD_CODED_ALLOWED_BINARY: &[[&str; 2]] = &[
+    ["f32", "f32"],
+    ["f64", "f64"],
+    ["std::num::Saturating", "std::num::Saturating"],
+    ["std::num::Wrapping", "std::num::Wrapping"],
+    ["std::string::String", "&str"],
 ];
+const HARD_CODED_ALLOWED_UNARY: &[&str] = &["f32", "f64", "std::num::Saturating", "std::num::Wrapping"];
 
 #[derive(Debug)]
 pub struct ArithmeticSideEffects {
-    allowed: FxHashSet<String>,
+    allowed_binary: FxHashMap<String, FxHashSet<String>>,
+    allowed_unary: FxHashSet<String>,
     // Used to check whether expressions are constants, such as in enum discriminants and consts
     const_span: Option<Span>,
     expr_span: Option<Span>,
@@ -33,19 +34,55 @@ pub struct ArithmeticSideEffects {
 
 impl ArithmeticSideEffects {
     #[must_use]
-    pub fn new(mut allowed: FxHashSet<String>) -> Self {
-        allowed.extend(HARD_CODED_ALLOWED.iter().copied().map(String::from));
+    pub fn new(user_allowed_binary: Vec<[String; 2]>, user_allowed_unary: Vec<String>) -> Self {
+        let mut allowed_binary: FxHashMap<String, FxHashSet<String>> = <_>::default();
+        for [lhs, rhs] in user_allowed_binary.into_iter().chain(
+            HARD_CODED_ALLOWED_BINARY
+                .iter()
+                .copied()
+                .map(|[lhs, rhs]| [lhs.to_string(), rhs.to_string()]),
+        ) {
+            allowed_binary.entry(lhs).or_default().insert(rhs);
+        }
+        let allowed_unary = user_allowed_unary
+            .into_iter()
+            .chain(HARD_CODED_ALLOWED_UNARY.iter().copied().map(String::from))
+            .collect();
         Self {
-            allowed,
+            allowed_binary,
+            allowed_unary,
             const_span: None,
             expr_span: None,
         }
     }
 
-    /// Checks if the given `expr` has any of the inner `allowed` elements.
-    fn is_allowed_ty(&self, ty: Ty<'_>) -> bool {
-        self.allowed
-            .contains(ty.to_string().split('<').next().unwrap_or_default())
+    /// Checks if the lhs and the rhs types of a binary operation like "addition" or
+    /// "multiplication" are present in the inner set of allowed types.
+    fn has_allowed_binary(&self, lhs_ty: Ty<'_>, rhs_ty: Ty<'_>) -> bool {
+        let lhs_ty_string = lhs_ty.to_string();
+        let lhs_ty_string_elem = lhs_ty_string.split('<').next().unwrap_or_default();
+        let rhs_ty_string = rhs_ty.to_string();
+        let rhs_ty_string_elem = rhs_ty_string.split('<').next().unwrap_or_default();
+        if let Some(rhs_from_specific) = self.allowed_binary.get(lhs_ty_string_elem)
+            && {
+                let rhs_has_allowed_ty = rhs_from_specific.contains(rhs_ty_string_elem);
+                rhs_has_allowed_ty || rhs_from_specific.contains("*")
+            }
+        {
+           true
+        } else if let Some(rhs_from_glob) = self.allowed_binary.get("*") {
+            rhs_from_glob.contains(rhs_ty_string_elem)
+        } else {
+            false
+        }
+    }
+
+    /// Checks if the type of an unary operation like "negation" is present in the inner set of
+    /// allowed types.
+    fn has_allowed_unary(&self, ty: Ty<'_>) -> bool {
+        let ty_string = ty.to_string();
+        let ty_string_elem = ty_string.split('<').next().unwrap_or_default();
+        self.allowed_unary.contains(ty_string_elem)
     }
 
     // For example, 8i32 or &i64::MAX.
@@ -97,8 +134,7 @@ fn manage_bin_ops<'tcx>(
         };
         let lhs_ty = cx.typeck_results().expr_ty(lhs);
         let rhs_ty = cx.typeck_results().expr_ty(rhs);
-        let lhs_and_rhs_have_the_same_ty = lhs_ty == rhs_ty;
-        if lhs_and_rhs_have_the_same_ty && self.is_allowed_ty(lhs_ty) && self.is_allowed_ty(rhs_ty) {
+        if self.has_allowed_binary(lhs_ty, rhs_ty) {
             return;
         }
         let has_valid_op = if Self::is_integral(lhs_ty) && Self::is_integral(rhs_ty) {
@@ -137,7 +173,7 @@ fn manage_unary_ops<'tcx>(
             return;
         }
         let ty = cx.typeck_results().expr_ty(expr).peel_refs();
-        if self.is_allowed_ty(ty) {
+        if self.has_allowed_unary(ty) {
             return;
         }
         let actual_un_expr = peel_hir_expr_refs(un_expr).0;
index b48d6c4e2e2af96318e38bdcb81ce5b2f3a548e9..14a12da862efeb68d4f151077dac7859d2ecb9db 100644 (file)
@@ -1,7 +1,7 @@
 use clippy_utils::consts::{constant_full_int, constant_simple, Constant, FullInt};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{clip, unsext};
+use clippy_utils::{clip, peel_hir_expr_refs, unsext};
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, Node};
 use rustc_lint::LateContext;
@@ -20,20 +20,76 @@ pub(crate) fn check<'tcx>(
     if !is_allowed(cx, op, left, right) {
         match op {
             BinOpKind::Add | BinOpKind::BitOr | BinOpKind::BitXor => {
-                check_op(cx, left, 0, expr.span, right.span, needs_parenthesis(cx, expr, right));
-                check_op(cx, right, 0, expr.span, left.span, Parens::Unneeded);
+                check_op(
+                    cx,
+                    left,
+                    0,
+                    expr.span,
+                    peel_hir_expr_refs(right).0.span,
+                    needs_parenthesis(cx, expr, right),
+                );
+                check_op(
+                    cx,
+                    right,
+                    0,
+                    expr.span,
+                    peel_hir_expr_refs(left).0.span,
+                    Parens::Unneeded,
+                );
             },
             BinOpKind::Shl | BinOpKind::Shr | BinOpKind::Sub => {
-                check_op(cx, right, 0, expr.span, left.span, Parens::Unneeded);
+                check_op(
+                    cx,
+                    right,
+                    0,
+                    expr.span,
+                    peel_hir_expr_refs(left).0.span,
+                    Parens::Unneeded,
+                );
             },
             BinOpKind::Mul => {
-                check_op(cx, left, 1, expr.span, right.span, needs_parenthesis(cx, expr, right));
-                check_op(cx, right, 1, expr.span, left.span, Parens::Unneeded);
+                check_op(
+                    cx,
+                    left,
+                    1,
+                    expr.span,
+                    peel_hir_expr_refs(right).0.span,
+                    needs_parenthesis(cx, expr, right),
+                );
+                check_op(
+                    cx,
+                    right,
+                    1,
+                    expr.span,
+                    peel_hir_expr_refs(left).0.span,
+                    Parens::Unneeded,
+                );
             },
-            BinOpKind::Div => check_op(cx, right, 1, expr.span, left.span, Parens::Unneeded),
+            BinOpKind::Div => check_op(
+                cx,
+                right,
+                1,
+                expr.span,
+                peel_hir_expr_refs(left).0.span,
+                Parens::Unneeded,
+            ),
             BinOpKind::BitAnd => {
-                check_op(cx, left, -1, expr.span, right.span, needs_parenthesis(cx, expr, right));
-                check_op(cx, right, -1, expr.span, left.span, Parens::Unneeded);
+                check_op(
+                    cx,
+                    left,
+                    -1,
+                    expr.span,
+                    peel_hir_expr_refs(right).0.span,
+                    needs_parenthesis(cx, expr, right),
+                );
+                check_op(
+                    cx,
+                    right,
+                    -1,
+                    expr.span,
+                    peel_hir_expr_refs(left).0.span,
+                    Parens::Unneeded,
+                );
             },
             BinOpKind::Rem => check_remainder(cx, left, right, expr.span, left.span),
             _ => (),
index b8a20d5ebe9bd689e7d996fea0dff6e86d9dcdd4..eba230da6c39b772bb90e600f07d9f2df3fcc9b5 100644 (file)
@@ -90,9 +90,6 @@
     /// use rust_decimal::Decimal;
     /// let _n = Decimal::MAX + Decimal::MAX;
     /// ```
-    ///
-    /// ### Allowed types
-    /// Custom allowed types can be specified through the "arithmetic-side-effects-allowed" filter.
     #[clippy::version = "1.64.0"]
     pub ARITHMETIC_SIDE_EFFECTS,
     restriction,
index d612d249c2f000ab3c869952f1806ff491ac2450..c2a8db7df038b9355ca6abf1e9833436688ce033 100644 (file)
@@ -84,7 +84,11 @@ fn check_item_post(&mut self, _cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
 
 fn is_not_macro_export<'tcx>(item: &'tcx Item<'tcx>) -> bool {
     if let ItemKind::Use(path, _) = item.kind {
-        if path.res.iter().all(|res| matches!(res, Res::Def(DefKind::Macro(MacroKind::Bang), _))) {
+        if path
+            .res
+            .iter()
+            .all(|res| matches!(res, Res::Def(DefKind::Macro(MacroKind::Bang), _)))
+        {
             return false;
         }
     } else if let ItemKind::Macro(..) = item.kind {
index 3aa2490bc44e018fa32371b1f94e0c69a46e4892..41f991a967bfd9929b025657ef21c8fc0aa573ca 100644 (file)
@@ -66,7 +66,7 @@ fn visit_type(ty: &Ty, cx: &EarlyContext<'_>, reason: &str) {
                         TyKind::Path(..) | TyKind::Slice(..) | TyKind::Array(..) | TyKind::Tup(..) => {
                             if lifetime.ident.name == rustc_span::symbol::kw::StaticLifetime {
                                 let snip = snippet(cx, borrow_type.ty.span, "<type>");
-                                let sugg = format!("&{snip}");
+                                let sugg = format!("&{}{snip}", borrow_type.mutbl.prefix_str());
                                 span_lint_and_then(
                                     cx,
                                     REDUNDANT_STATIC_LIFETIMES,
index 8e214218f23ae1d5f617147d4e9ca2ff42cb37af..72c25592609ba77191f7877134b6c8bff1df90d8 100644 (file)
@@ -2,6 +2,7 @@
 
 #[rustfmt::skip]
 pub static RENAMED_LINTS: &[(&str, &str)] = &[
+    ("clippy::almost_complete_letter_range", "clippy::almost_complete_range"),
     ("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"),
diff --git a/src/tools/clippy/clippy_lints/src/semicolon_block.rs b/src/tools/clippy/clippy_lints/src/semicolon_block.rs
new file mode 100644 (file)
index 0000000..8f1d149
--- /dev/null
@@ -0,0 +1,137 @@
+use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_then};
+use rustc_errors::Applicability;
+use rustc_hir::{Block, Expr, ExprKind, Stmt, StmtKind};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::Span;
+
+declare_clippy_lint! {
+    /// ### What it does
+    ///
+    /// Suggests moving the semicolon after a block to the inside of the block, after its last
+    /// expression.
+    ///
+    /// ### Why is this bad?
+    ///
+    /// For consistency it's best to have the semicolon inside/outside the block. Either way is fine
+    /// and this lint suggests inside the block.
+    /// Take a look at `semicolon_outside_block` for the other alternative.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// # fn f(_: u32) {}
+    /// # let x = 0;
+    /// unsafe { f(x) };
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// # fn f(_: u32) {}
+    /// # let x = 0;
+    /// unsafe { f(x); }
+    /// ```
+    #[clippy::version = "1.66.0"]
+    pub SEMICOLON_INSIDE_BLOCK,
+    restriction,
+    "add a semicolon inside the block"
+}
+declare_clippy_lint! {
+    /// ### What it does
+    ///
+    /// Suggests moving the semicolon from a block's final expression outside of the block.
+    ///
+    /// ### Why is this bad?
+    ///
+    /// For consistency it's best to have the semicolon inside/outside the block. Either way is fine
+    /// and this lint suggests outside the block.
+    /// Take a look at `semicolon_inside_block` for the other alternative.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// # fn f(_: u32) {}
+    /// # let x = 0;
+    /// unsafe { f(x); }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// # fn f(_: u32) {}
+    /// # let x = 0;
+    /// unsafe { f(x) };
+    /// ```
+    #[clippy::version = "1.66.0"]
+    pub SEMICOLON_OUTSIDE_BLOCK,
+    restriction,
+    "add a semicolon outside the block"
+}
+declare_lint_pass!(SemicolonBlock => [SEMICOLON_INSIDE_BLOCK, SEMICOLON_OUTSIDE_BLOCK]);
+
+impl LateLintPass<'_> for SemicolonBlock {
+    fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) {
+        match stmt.kind {
+            StmtKind::Expr(Expr {
+                kind: ExprKind::Block(block, _),
+                ..
+            }) if !block.span.from_expansion() => {
+                let Block {
+                    expr: None,
+                    stmts: [.., stmt],
+                    ..
+                } = block else { return };
+                let &Stmt {
+                    kind: StmtKind::Semi(expr),
+                    span,
+                    ..
+                } = stmt else { return };
+                semicolon_outside_block(cx, block, expr, span);
+            },
+            StmtKind::Semi(Expr {
+                kind: ExprKind::Block(block @ Block { expr: Some(tail), .. }, _),
+                ..
+            }) if !block.span.from_expansion() => semicolon_inside_block(cx, block, tail, stmt.span),
+            _ => (),
+        }
+    }
+}
+
+fn semicolon_inside_block(cx: &LateContext<'_>, block: &Block<'_>, tail: &Expr<'_>, semi_span: Span) {
+    let insert_span = tail.span.source_callsite().shrink_to_hi();
+    let remove_span = semi_span.with_lo(block.span.hi());
+
+    span_lint_and_then(
+        cx,
+        SEMICOLON_INSIDE_BLOCK,
+        semi_span,
+        "consider moving the `;` inside the block for consistent formatting",
+        |diag| {
+            multispan_sugg_with_applicability(
+                diag,
+                "put the `;` here",
+                Applicability::MachineApplicable,
+                [(remove_span, String::new()), (insert_span, ";".to_owned())],
+            );
+        },
+    );
+}
+
+fn semicolon_outside_block(cx: &LateContext<'_>, block: &Block<'_>, tail_stmt_expr: &Expr<'_>, semi_span: Span) {
+    let insert_span = block.span.with_lo(block.span.hi());
+    // account for macro calls
+    let semi_span = cx.sess().source_map().stmt_span(semi_span, block.span);
+    let remove_span = semi_span.with_lo(tail_stmt_expr.span.source_callsite().hi());
+
+    span_lint_and_then(
+        cx,
+        SEMICOLON_OUTSIDE_BLOCK,
+        block.span,
+        "consider moving the `;` outside the block for consistent formatting",
+        |diag| {
+            multispan_sugg_with_applicability(
+                diag,
+                "put the `;` here",
+                Applicability::MachineApplicable,
+                [(remove_span, String::new()), (insert_span, ";".to_owned())],
+            );
+        },
+    );
+}
index f4705481d4e69b3131ad73ce0439ba6903092dca..bc18cad6d381b0cb165d46e6bd000b7c8305d637 100644 (file)
@@ -1,12 +1,12 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg};
 use clippy_utils::source::{snippet, snippet_with_applicability};
 use clippy_utils::ty::is_type_lang_item;
+use clippy_utils::{get_expr_use_or_unification_node, peel_blocks, SpanlessEq};
 use clippy_utils::{get_parent_expr, is_lint_allowed, match_function_call, method_calls, paths};
-use clippy_utils::{peel_blocks, SpanlessEq};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
-use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, LangItem, QPath};
+use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, LangItem, Node, QPath};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
@@ -249,6 +249,7 @@ fn is_add(cx: &LateContext<'_>, src: &Expr<'_>, target: &Expr<'_>) -> bool {
 declare_lint_pass!(StringLitAsBytes => [STRING_LIT_AS_BYTES, STRING_FROM_UTF8_AS_BYTES]);
 
 impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
+    #[expect(clippy::too_many_lines)]
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
         use rustc_ast::LitKind;
 
@@ -316,18 +317,27 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                     && lit_content.as_str().len() <= MAX_LENGTH_BYTE_STRING_LIT
                     && !receiver.span.from_expansion()
                 {
-                    span_lint_and_sugg(
-                        cx,
-                        STRING_LIT_AS_BYTES,
-                        e.span,
-                        "calling `as_bytes()` on a string literal",
-                        "consider using a byte string literal instead",
-                        format!(
-                            "b{}",
-                            snippet_with_applicability(cx, receiver.span, r#""foo""#, &mut applicability)
-                        ),
-                        applicability,
-                    );
+                    if let Some((parent, id)) = get_expr_use_or_unification_node(cx.tcx, e)
+                        && let Node::Expr(parent) = parent
+                        && let ExprKind::Match(scrutinee, ..) = parent.kind
+                        && scrutinee.hir_id == id
+                    {
+                        // Don't lint. Byte strings produce `&[u8; N]` whereas `as_bytes()` produces
+                        // `&[u8]`. This change would prevent matching with different sized slices.
+                    } else {
+                        span_lint_and_sugg(
+                            cx,
+                            STRING_LIT_AS_BYTES,
+                            e.span,
+                            "calling `as_bytes()` on a string literal",
+                            "consider using a byte string literal instead",
+                            format!(
+                                "b{}",
+                                snippet_with_applicability(cx, receiver.span, r#""foo""#, &mut applicability)
+                            ),
+                            applicability,
+                        );
+                    }
                 }
             }
         }
index b6dc8cd7ab1197e338e653a2fa3e1d5f20442877..3e7d0028c0fbd97df2a73e40300db80ac39606fe 100644 (file)
@@ -205,10 +205,49 @@ pub(crate) fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
 }
 
 define_Conf! {
-    /// Lint: Arithmetic.
+    /// Lint: ARITHMETIC_SIDE_EFFECTS.
     ///
-    /// Suppress checking of the passed type names.
+    /// Suppress checking of the passed type names in all types of operations.
+    ///
+    /// If a specific operation is desired, consider using `arithmetic_side_effects_allowed_binary` or `arithmetic_side_effects_allowed_unary` instead.
+    ///
+    /// #### Example
+    ///
+    /// ```toml
+    /// arithmetic-side-effects-allowed = ["SomeType", "AnotherType"]
+    /// ```
+    ///
+    /// #### Noteworthy
+    ///
+    /// A type, say `SomeType`, listed in this configuration has the same behavior of `["SomeType" , "*"], ["*", "SomeType"]` in `arithmetic_side_effects_allowed_binary`.
     (arithmetic_side_effects_allowed: rustc_data_structures::fx::FxHashSet<String> = <_>::default()),
+    /// Lint: ARITHMETIC_SIDE_EFFECTS.
+    ///
+    /// Suppress checking of the passed type pair names in binary operations like addition or
+    /// multiplication.
+    ///
+    /// Supports the "*" wildcard to indicate that a certain type won't trigger the lint regardless
+    /// of the involved counterpart. For example, `["SomeType", "*"]` or `["*", "AnotherType"]`.
+    ///
+    /// Pairs are asymmetric, which means that `["SomeType", "AnotherType"]` is not the same as
+    /// `["AnotherType", "SomeType"]`.
+    ///
+    /// #### Example
+    ///
+    /// ```toml
+    /// arithmetic-side-effects-allowed-binary = [["SomeType" , "f32"], ["AnotherType", "*"]]
+    /// ```
+    (arithmetic_side_effects_allowed_binary: Vec<[String; 2]> = <_>::default()),
+    /// Lint: ARITHMETIC_SIDE_EFFECTS.
+    ///
+    /// Suppress checking of the passed type names in unary operations like "negation" (`-`).
+    ///
+    /// #### Example
+    ///
+    /// ```toml
+    /// arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"]
+    /// ```
+    (arithmetic_side_effects_allowed_unary: rustc_data_structures::fx::FxHashSet<String> = <_>::default()),
     /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX.
     ///
     /// Suppress lints whenever the suggested change would cause breakage for other crates.
@@ -406,6 +445,14 @@ pub(crate) fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
     ///
     /// Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar)`
     (allow_mixed_uninlined_format_args: bool = true),
+    /// Lint: INDEXING_SLICING
+    ///
+    /// Whether to suppress a restriction lint in constant code. In same
+    /// cases the restructured operation might not be unavoidable, as the
+    /// suggested counterparts are unavailable in constant code. This
+    /// configuration will cause restriction lints to trigger even
+    /// if no suggestion can be made.
+    (suppress_restriction_lint_in_const: bool = false),
 }
 
 /// Search for the configuration file.
index 680935f2329e4e5037ffdf2c1f01022c962f3702..9afe02c1e47da00cadc26e240f6e4d34d6fe99ae 100644 (file)
@@ -7,7 +7,7 @@
 use rustc_hir::Item;
 use rustc_hir_analysis::hir_ty_to_ty;
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::{self, fast_reject::SimplifiedTypeGen, FloatTy};
+use rustc_middle::ty::{self, fast_reject::SimplifiedType, FloatTy};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::symbol::Symbol;
 
@@ -73,10 +73,10 @@ pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool {
     let lang_items = cx.tcx.lang_items();
     // This list isn't complete, but good enough for our current list of paths.
     let incoherent_impls = [
-        SimplifiedTypeGen::FloatSimplifiedType(FloatTy::F32),
-        SimplifiedTypeGen::FloatSimplifiedType(FloatTy::F64),
-        SimplifiedTypeGen::SliceSimplifiedType,
-        SimplifiedTypeGen::StrSimplifiedType,
+        SimplifiedType::FloatSimplifiedType(FloatTy::F32),
+        SimplifiedType::FloatSimplifiedType(FloatTy::F64),
+        SimplifiedType::SliceSimplifiedType,
+        SimplifiedType::StrSimplifiedType,
     ]
     .iter()
     .flat_map(|&ty| cx.tcx.incoherent_impls(ty).iter().copied());
index fb9f4740ecc5003922077019e7c3c12e4d634e77..ac6a566b9cd3ae5f208e9c4758a71c79f5867b50 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "clippy_utils"
-version = "0.1.67"
+version = "0.1.68"
 edition = "2021"
 publish = false
 
index 90192f46cbfa09f416e88c94060d3962f5c9cfef..43e2d1ec826c2343b9d6dea43c11ae3fe3789917 100644 (file)
@@ -97,7 +97,7 @@
 use rustc_middle::ty as rustc_ty;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
 use rustc_middle::ty::binding::BindingMode;
-use rustc_middle::ty::fast_reject::SimplifiedTypeGen::{
+use rustc_middle::ty::fast_reject::SimplifiedType::{
     ArraySimplifiedType, BoolSimplifiedType, CharSimplifiedType, FloatSimplifiedType, IntSimplifiedType,
     PtrSimplifiedType, SliceSimplifiedType, StrSimplifiedType, UintSimplifiedType,
 };
@@ -196,7 +196,7 @@ pub fn in_constant(cx: &LateContext<'_>, id: HirId) -> bool {
     let parent_id = cx.tcx.hir().get_parent_item(id).def_id;
     match cx.tcx.hir().get_by_def_id(parent_id) {
         Node::Item(&Item {
-            kind: ItemKind::Const(..) | ItemKind::Static(..),
+            kind: ItemKind::Const(..) | ItemKind::Static(..) | ItemKind::Enum(..),
             ..
         })
         | Node::TraitItem(&TraitItem {
index d13b34a66cca783ea01a70426ca6316af8684471..77c5f1155423c4a7a4399694988e3b56442bae5a 100644 (file)
@@ -208,6 +208,12 @@ pub fn is_panic(cx: &LateContext<'_>, def_id: DefId) -> bool {
     )
 }
 
+/// Is `def_id` of `assert!` or `debug_assert!`
+pub fn is_assert_macro(cx: &LateContext<'_>, def_id: DefId) -> bool {
+    let Some(name) = cx.tcx.get_diagnostic_name(def_id) else { return false };
+    matches!(name, sym::assert_macro | sym::debug_assert_macro)
+}
+
 pub enum PanicExpn<'a> {
     /// No arguments - `panic!()`
     Empty,
index 12a512f78a699eb30c92ac178b17663db424d090..ba5bc9c3135daa8ca34a9eddf552dafb332af796 100644 (file)
@@ -21,7 +21,7 @@ macro_rules! msrv_aliases {
 msrv_aliases! {
     1,65,0 { LET_ELSE }
     1,62,0 { BOOL_THEN_SOME }
-    1,58,0 { FORMAT_ARGS_CAPTURE }
+    1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY }
     1,53,0 { OR_PATTERNS, MANUAL_BITS, BTREE_MAP_RETAIN, BTREE_SET_RETAIN, ARRAY_INTO_ITERATOR }
     1,52,0 { STR_SPLIT_ONCE, REM_EUCLID_CONST }
     1,51,0 { BORROW_AS_PTR, SEEK_FROM_CURRENT, UNSIGNED_ABS }
index 6417f0f3c71348bb6761918cb08c7c373e7b9bc6..9ca50105ae57d0e93c96f7b48d1030bb10011c85 100644 (file)
@@ -20,7 +20,6 @@
 pub const BTREEMAP_INSERT: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "insert"];
 pub const BTREESET_ITER: [&str; 6] = ["alloc", "collections", "btree", "set", "BTreeSet", "iter"];
 pub const CLONE_TRAIT_METHOD: [&str; 4] = ["core", "clone", "Clone", "clone"];
-pub const CORE_ITER_COLLECT: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "collect"];
 pub const CORE_ITER_CLONED: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "cloned"];
 pub const CORE_ITER_COPIED: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "copied"];
 pub const CORE_ITER_FILTER: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "filter"];
index 8bf542ada04dd80ace50f751c29337d8ecdd71d4..e5d7da682813c16d4883f2985d0963c03eb03a7c 100644 (file)
@@ -301,10 +301,7 @@ fn check_terminator<'tcx>(
             check_operand(tcx, value, span, body)
         },
 
-        TerminatorKind::SwitchInt {
-            discr,
-            targets: _,
-        } => check_operand(tcx, discr, span, body),
+        TerminatorKind::SwitchInt { discr, targets: _ } => check_operand(tcx, discr, span, body),
 
         TerminatorKind::Abort => Err((span, "abort is not stable in const fn".into())),
         TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => {
index a6bcb134d408096099ddd5d13263a68e28688fa1..2773da70d7880c2b387b96bfebabe33963051adb 100644 (file)
@@ -16,8 +16,8 @@
 use rustc_lint::LateContext;
 use rustc_middle::mir::interpret::{ConstValue, Scalar};
 use rustc_middle::ty::{
-    self, AdtDef, AssocKind, Binder, BoundRegion, DefIdTree, FnSig, IntTy, List, ParamEnv, Predicate, PredicateKind,
-    AliasTy, Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, UintTy,
+    self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, DefIdTree, FnSig, IntTy, List, ParamEnv, Predicate,
+    PredicateKind, Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, UintTy,
     VariantDef, VariantDiscr,
 };
 use rustc_middle::ty::{GenericArg, GenericArgKind};
@@ -30,7 +30,7 @@
 
 use crate::{match_def_path, path_res, paths};
 
-// Checks if the given type implements copy.
+/// Checks if the given type implements copy.
 pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
     ty.is_copy_modulo_regions(cx.tcx, cx.param_env)
 }
@@ -69,50 +69,66 @@ pub fn contains_adt_constructor<'tcx>(ty: Ty<'tcx>, adt: AdtDef<'tcx>) -> bool {
 /// This method also recurses into opaque type predicates, so call it with `impl Trait<U>` and `U`
 /// will also return `true`.
 pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, needle: Ty<'tcx>) -> bool {
-    ty.walk().any(|inner| match inner.unpack() {
-        GenericArgKind::Type(inner_ty) => {
-            if inner_ty == needle {
-                return true;
-            }
+    fn contains_ty_adt_constructor_opaque_inner<'tcx>(
+        cx: &LateContext<'tcx>,
+        ty: Ty<'tcx>,
+        needle: Ty<'tcx>,
+        seen: &mut FxHashSet<DefId>,
+    ) -> bool {
+        ty.walk().any(|inner| match inner.unpack() {
+            GenericArgKind::Type(inner_ty) => {
+                if inner_ty == needle {
+                    return true;
+                }
 
-            if inner_ty.ty_adt_def() == needle.ty_adt_def() {
-                return true;
-            }
+                if inner_ty.ty_adt_def() == needle.ty_adt_def() {
+                    return true;
+                }
 
-            if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *inner_ty.kind() {
-                for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
-                    match predicate.kind().skip_binder() {
-                        // For `impl Trait<U>`, it will register a predicate of `T: Trait<U>`, so we go through
-                        // and check substituions to find `U`.
-                        ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => {
-                            if trait_predicate
-                                .trait_ref
-                                .substs
-                                .types()
-                                .skip(1) // Skip the implicit `Self` generic parameter
-                                .any(|ty| contains_ty_adt_constructor_opaque(cx, ty, needle))
-                            {
-                                return true;
-                            }
-                        },
-                        // For `impl Trait<Assoc=U>`, it will register a predicate of `<T as Trait>::Assoc = U`,
-                        // so we check the term for `U`.
-                        ty::PredicateKind::Clause(ty::Clause::Projection(projection_predicate)) => {
-                            if let ty::TermKind::Ty(ty) = projection_predicate.term.unpack() {
-                                if contains_ty_adt_constructor_opaque(cx, ty, needle) {
+                if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *inner_ty.kind() {
+                    if !seen.insert(def_id) {
+                        return false;
+                    }
+
+                    for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
+                        match predicate.kind().skip_binder() {
+                            // For `impl Trait<U>`, it will register a predicate of `T: Trait<U>`, so we go through
+                            // and check substituions to find `U`.
+                            ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => {
+                                if trait_predicate
+                                    .trait_ref
+                                    .substs
+                                    .types()
+                                    .skip(1) // Skip the implicit `Self` generic parameter
+                                    .any(|ty| contains_ty_adt_constructor_opaque_inner(cx, ty, needle, seen))
+                                {
                                     return true;
                                 }
-                            };
-                        },
-                        _ => (),
+                            },
+                            // For `impl Trait<Assoc=U>`, it will register a predicate of `<T as Trait>::Assoc = U`,
+                            // so we check the term for `U`.
+                            ty::PredicateKind::Clause(ty::Clause::Projection(projection_predicate)) => {
+                                if let ty::TermKind::Ty(ty) = projection_predicate.term.unpack() {
+                                    if contains_ty_adt_constructor_opaque_inner(cx, ty, needle, seen) {
+                                        return true;
+                                    }
+                                };
+                            },
+                            _ => (),
+                        }
                     }
                 }
-            }
 
-            false
-        },
-        GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
-    })
+                false
+            },
+            GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
+        })
+    }
+
+    // A hash set to ensure that the same opaque type (`impl Trait` in RPIT or TAIT) is not
+    // visited twice.
+    let mut seen = FxHashSet::default();
+    contains_ty_adt_constructor_opaque_inner(cx, ty, needle, &mut seen)
 }
 
 /// Resolves `<T as Iterator>::Item` for `T`
@@ -631,7 +647,9 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t
             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::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => sig_from_bounds(cx, ty, cx.tcx.item_bounds(def_id), cx.tcx.opt_parent(def_id)),
+        ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => {
+            sig_from_bounds(cx, ty, cx.tcx.item_bounds(def_id), cx.tcx.opt_parent(def_id))
+        },
         ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)),
         ty::Dynamic(bounds, _, _) => {
             let lang_items = cx.tcx.lang_items();
@@ -685,8 +703,7 @@ fn sig_from_bounds<'tcx>(
                 inputs = Some(i);
             },
             PredicateKind::Clause(ty::Clause::Projection(p))
-                if Some(p.projection_ty.def_id) == lang_items.fn_once_output()
-                    && p.projection_ty.self_ty() == ty =>
+                if Some(p.projection_ty.def_id) == lang_items.fn_once_output() && p.projection_ty.self_ty() == ty =>
             {
                 if output.is_some() {
                     // Multiple different fn trait impls. Is this even allowed?
@@ -1039,10 +1056,7 @@ fn helper<'tcx>(
             }
         }
 
-        Some(tcx.mk_alias_ty(
-            assoc_item.def_id,
-            substs,
-        ))
+        Some(tcx.mk_alias_ty(assoc_item.def_id, substs))
     }
     helper(
         tcx,
index 082570f1fe5d87a1924f3503a02ce5fcf6931b4e..c01e1062cb5445c2557a08692ff35eb79212db2d 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "declare_clippy_lint"
-version = "0.1.67"
+version = "0.1.68"
 edition = "2021"
 publish = false
 
index 19fee38db46e642eb18f600b1a3b7d8b6e8a814f..8e21cef32abb63ff135e93acb27ef0d644e97de9 100644 (file)
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2022-12-01"
+channel = "nightly-2022-12-17"
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
diff --git a/src/tools/clippy/rustc_tools_util/CHANGELOG.md b/src/tools/clippy/rustc_tools_util/CHANGELOG.md
new file mode 100644 (file)
index 0000000..1b351da
--- /dev/null
@@ -0,0 +1,6 @@
+# Changelog
+
+## Version 0.3.0
+
+* Added `setup_version_info!();` macro for automated scripts.
+* `get_version_info!()` no longer requires the user to import `rustc_tools_util::VersionInfo` and `std::env`
index 89c3d6aaa89e785e15db5dd2de15d7ca69d7239e..877049ae7d0ebd92d8d11d95698f89ded3698a93 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "rustc_tools_util"
-version = "0.2.1"
+version = "0.3.0"
 description = "small helper to generate version information for git packages"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
index e947f9c7e66ed29d7fdc0cf9e4fbc5828994fca5..eefc661f96352e04d182fe016702674df122880f 100644 (file)
@@ -13,43 +13,39 @@ build = "build.rs"
 List rustc_tools_util as regular AND build dependency.
 ````toml
 [dependencies]
-rustc_tools_util = "0.2.1"
+rustc_tools_util = "0.3.0"
 
 [build-dependencies]
-rustc_tools_util = "0.2.1"
+rustc_tools_util = "0.3.0"
 ````
 
 In `build.rs`, generate the data in your `main()`
-````rust
+
+```rust
 fn main() {
-    println!(
-        "cargo:rustc-env=GIT_HASH={}",
-        rustc_tools_util::get_commit_hash().unwrap_or_default()
-    );
-    println!(
-        "cargo:rustc-env=COMMIT_DATE={}",
-        rustc_tools_util::get_commit_date().unwrap_or_default()
-    );
-    println!(
-        "cargo:rustc-env=RUSTC_RELEASE_CHANNEL={}",
-        rustc_tools_util::get_channel().unwrap_or_default()
-    );
+    rustc_tools_util::setup_version_info!();
 }
-
-````
+```
 
 Use the version information in your main.rs
-````rust
-use rustc_tools_util::*;
 
+```rust
 fn show_version() {
     let version_info = rustc_tools_util::get_version_info!();
     println!("{}", version_info);
 }
-````
+```
+
 This gives the following output in clippy:
-`clippy 0.0.212 (a416c5e 2018-12-14)`
+`clippy 0.1.66 (a28f3c8 2022-11-20)`
+
+## Repository
+
+This project is part of the rust-lang/rust-clippy repository. The source code
+can be found under `./rustc_tools_util/`.
 
+The changelog for `rustc_tools_util` is available under:
+[`rustc_tools_util/CHANGELOG.md`](https://github.com/rust-lang/rust-clippy/blob/master/rustc_tools_util/CHANGELOG.md)
 
 ## License
 
index 01d25c53126fdefcb7460562a192deccd457aa7d..4c1d8c3733df61b97582e3780118d9b2446b8de7 100644 (file)
@@ -1,20 +1,20 @@
 #![cfg_attr(feature = "deny-warnings", deny(warnings))]
 
-use std::env;
-
+/// This macro creates the version string during compilation from the
+/// current environment
 #[macro_export]
 macro_rules! get_version_info {
     () => {{
-        let major = env!("CARGO_PKG_VERSION_MAJOR").parse::<u8>().unwrap();
-        let minor = env!("CARGO_PKG_VERSION_MINOR").parse::<u8>().unwrap();
-        let patch = env!("CARGO_PKG_VERSION_PATCH").parse::<u16>().unwrap();
-        let crate_name = String::from(env!("CARGO_PKG_NAME"));
+        let major = std::env!("CARGO_PKG_VERSION_MAJOR").parse::<u8>().unwrap();
+        let minor = std::env!("CARGO_PKG_VERSION_MINOR").parse::<u8>().unwrap();
+        let patch = std::env!("CARGO_PKG_VERSION_PATCH").parse::<u16>().unwrap();
+        let crate_name = String::from(std::env!("CARGO_PKG_NAME"));
 
-        let host_compiler = option_env!("RUSTC_RELEASE_CHANNEL").map(str::to_string);
-        let commit_hash = option_env!("GIT_HASH").map(str::to_string);
-        let commit_date = option_env!("COMMIT_DATE").map(str::to_string);
+        let host_compiler = std::option_env!("RUSTC_RELEASE_CHANNEL").map(str::to_string);
+        let commit_hash = std::option_env!("GIT_HASH").map(str::to_string);
+        let commit_date = std::option_env!("COMMIT_DATE").map(str::to_string);
 
-        VersionInfo {
+        $crate::VersionInfo {
             major,
             minor,
             patch,
@@ -26,6 +26,24 @@ macro_rules! get_version_info {
     }};
 }
 
+/// This macro can be used in `build.rs` to automatically set the needed
+/// environment values, namely `GIT_HASH`, `COMMIT_DATE` and
+/// `RUSTC_RELEASE_CHANNEL`
+#[macro_export]
+macro_rules! setup_version_info {
+    () => {{
+        println!(
+            "cargo:rustc-env=GIT_HASH={}",
+            $crate::get_commit_hash().unwrap_or_default()
+        );
+        println!(
+            "cargo:rustc-env=COMMIT_DATE={}",
+            $crate::get_commit_date().unwrap_or_default()
+        );
+        println!("cargo:rustc-env=RUSTC_RELEASE_CHANNEL={}", $crate::get_channel());
+    }};
+}
+
 // some code taken and adapted from RLS and cargo
 pub struct VersionInfo {
     pub major: u8,
@@ -101,7 +119,7 @@ pub fn get_commit_date() -> Option<String> {
 
 #[must_use]
 pub fn get_channel() -> String {
-    match env::var("CFG_RELEASE_CHANNEL") {
+    match std::env::var("CFG_RELEASE_CHANNEL") {
         Ok(channel) => channel,
         Err(_) => {
             // if that failed, try to ask rustc -V, do some parsing and find out
@@ -136,8 +154,8 @@ mod test {
     fn test_struct_local() {
         let vi = get_version_info!();
         assert_eq!(vi.major, 0);
-        assert_eq!(vi.minor, 2);
-        assert_eq!(vi.patch, 1);
+        assert_eq!(vi.minor, 3);
+        assert_eq!(vi.patch, 0);
         assert_eq!(vi.crate_name, "rustc_tools_util");
         // hard to make positive tests for these since they will always change
         assert!(vi.commit_hash.is_none());
@@ -147,7 +165,7 @@ fn test_struct_local() {
     #[test]
     fn test_display_local() {
         let vi = get_version_info!();
-        assert_eq!(vi.to_string(), "rustc_tools_util 0.2.1");
+        assert_eq!(vi.to_string(), "rustc_tools_util 0.3.0");
     }
 
     #[test]
@@ -156,7 +174,7 @@ fn test_debug_local() {
         let s = format!("{vi:?}");
         assert_eq!(
             s,
-            "VersionInfo { crate_name: \"rustc_tools_util\", major: 0, minor: 2, patch: 1 }"
+            "VersionInfo { crate_name: \"rustc_tools_util\", major: 0, minor: 3, patch: 0 }"
         );
     }
 }
index 9ec4df8e651b1bf3f7756656f8548f5c2ec8e9c0..bcc096c570e1b7013524d3b20048903cc3d85780 100644 (file)
@@ -19,7 +19,6 @@
 use rustc_interface::interface;
 use rustc_session::parse::ParseSess;
 use rustc_span::symbol::Symbol;
-use rustc_tools_util::VersionInfo;
 
 use std::borrow::Cow;
 use std::env;
index d418d2daa313e75d69fb6454fc12a8e59f7e37f2..7a78b32620d0bf41301fa50cf781b6a5c658bb45 100644 (file)
@@ -2,7 +2,6 @@
 // warn on lints, that are included in `rust-lang/rust`s bootstrap
 #![warn(rust_2018_idioms, unused_lifetimes)]
 
-use rustc_tools_util::VersionInfo;
 use std::env;
 use std::path::PathBuf;
 use std::process::{self, Command};
index 2a240cc249b0c768f084dab5b6f220ae53a59399..3ca45404e44bb88290ad846bccca89f21b88f6a7 100644 (file)
@@ -7,14 +7,6 @@ LL |     const DEREF_TRAIT: [&str; 4] = ["core", "ops", "deref", "Deref"];
    = help: convert all references to use `sym::Deref`
    = note: `-D clippy::unnecessary-def-path` implied by `-D warnings`
 
-error: hardcoded path to a diagnostic item
-  --> $DIR/unnecessary_def_path_hardcoded_path.rs:12:43
-   |
-LL |     const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
-   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: convert all references to use `sym::deref_method`
-
 error: hardcoded path to a language item
   --> $DIR/unnecessary_def_path_hardcoded_path.rs:11:40
    |
@@ -23,5 +15,13 @@ LL |     const DEREF_MUT_TRAIT: [&str; 4] = ["core", "ops", "deref", "DerefMut"]
    |
    = help: convert all references to use `LangItem::DerefMut`
 
+error: hardcoded path to a diagnostic item
+  --> $DIR/unnecessary_def_path_hardcoded_path.rs:12:43
+   |
+LL |     const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
+   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: convert all references to use `sym::deref_method`
+
 error: aborting due to 3 previous errors
 
index e8a023ab17643514d08d08c803d51beea762610f..36db9e54a228854ac09f5953faedbc07e6ee90ec 100644 (file)
 
 use core::ops::{Add, Neg};
 
-#[derive(Clone, Copy)]
-struct Point {
-    x: i32,
-    y: i32,
+macro_rules! create {
+    ($name:ident) => {
+        #[allow(clippy::arithmetic_side_effects)]
+        #[derive(Clone, Copy)]
+        struct $name;
+
+        impl Add<$name> for $name {
+            type Output = $name;
+            fn add(self, other: $name) -> Self::Output {
+                todo!()
+            }
+        }
+
+        impl Add<i32> for $name {
+            type Output = $name;
+            fn add(self, other: i32) -> Self::Output {
+                todo!()
+            }
+        }
+
+        impl Add<$name> for i32 {
+            type Output = $name;
+            fn add(self, other: $name) -> Self::Output {
+                todo!()
+            }
+        }
+
+        impl Add<i64> for $name {
+            type Output = $name;
+            fn add(self, other: i64) -> Self::Output {
+                todo!()
+            }
+        }
+
+        impl Add<$name> for i64 {
+            type Output = $name;
+            fn add(self, other: $name) -> Self::Output {
+                todo!()
+            }
+        }
+
+        impl Neg for $name {
+            type Output = $name;
+            fn neg(self) -> Self::Output {
+                todo!()
+            }
+        }
+    };
 }
 
-impl Add for Point {
-    type Output = Self;
+create!(Foo);
+create!(Bar);
+create!(Baz);
+create!(OutOfNames);
 
-    fn add(self, other: Self) -> Self {
-        todo!()
-    }
+fn lhs_and_rhs_are_equal() {
+    // is explicitly on the list
+    let _ = OutOfNames + OutOfNames;
+    // is explicitly on the list
+    let _ = Foo + Foo;
+    // is implicitly on the list
+    let _ = Bar + Bar;
+    // not on the list
+    let _ = Baz + Baz;
 }
 
-impl Neg for Point {
-    type Output = Self;
+fn lhs_is_different() {
+    // is explicitly on the list
+    let _ = 1i32 + OutOfNames;
+    // is explicitly on the list
+    let _ = 1i32 + Foo;
+    // is implicitly on the list
+    let _ = 1i32 + Bar;
+    // not on the list
+    let _ = 1i32 + Baz;
 
-    fn neg(self) -> Self::Output {
-        todo!()
-    }
+    // not on the list
+    let _ = 1i64 + Foo;
+    // is implicitly on the list
+    let _ = 1i64 + Bar;
+    // not on the list
+    let _ = 1i64 + Baz;
 }
 
-fn main() {
-    let _ = Point { x: 1, y: 0 } + Point { x: 2, y: 3 };
+fn rhs_is_different() {
+    // is explicitly on the list
+    let _ = OutOfNames + 1i32;
+    // is explicitly on the list
+    let _ = Foo + 1i32;
+    // is implicitly on the list
+    let _ = Bar + 1i32;
+    // not on the list
+    let _ = Baz + 1i32;
+
+    // not on the list
+    let _ = Foo + 1i64;
+    // is implicitly on the list
+    let _ = Bar + 1i64;
+    // not on the list
+    let _ = Baz + 1i64;
+}
 
-    let point: Point = Point { x: 1, y: 0 };
-    let _ = point + point;
-    let _ = -point;
+fn unary() {
+    // is explicitly on the list
+    let _ = -OutOfNames;
+    // is specifically on the list
+    let _ = -Foo;
+    // not on the list
+    let _ = -Bar;
+    // not on the list
+    let _ = -Baz;
 }
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.stderr b/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.stderr
new file mode 100644 (file)
index 0000000..ad89534
--- /dev/null
@@ -0,0 +1,58 @@
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects_allowed.rs:68:13
+   |
+LL |     let _ = Baz + Baz;
+   |             ^^^^^^^^^
+   |
+   = note: `-D clippy::arithmetic-side-effects` implied by `-D warnings`
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects_allowed.rs:79:13
+   |
+LL |     let _ = 1i32 + Baz;
+   |             ^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects_allowed.rs:82:13
+   |
+LL |     let _ = 1i64 + Foo;
+   |             ^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects_allowed.rs:86:13
+   |
+LL |     let _ = 1i64 + Baz;
+   |             ^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects_allowed.rs:97:13
+   |
+LL |     let _ = Baz + 1i32;
+   |             ^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects_allowed.rs:100:13
+   |
+LL |     let _ = Foo + 1i64;
+   |             ^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects_allowed.rs:104:13
+   |
+LL |     let _ = Baz + 1i64;
+   |             ^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects_allowed.rs:113:13
+   |
+LL |     let _ = -Bar;
+   |             ^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects_allowed.rs:115:13
+   |
+LL |     let _ = -Baz;
+   |             ^^^^
+
+error: aborting due to 9 previous errors
+
index e736256f29a475564c327ccdab471bec05993d49..89cbea7ecfe4728a7660a497312179bdafea4311 100644 (file)
@@ -1 +1,11 @@
-arithmetic-side-effects-allowed = ["Point"]
+arithmetic-side-effects-allowed = [
+    "OutOfNames"
+]
+arithmetic-side-effects-allowed-binary = [
+    ["Foo", "Foo"],
+    ["Foo", "i32"],
+    ["i32", "Foo"],
+    ["Bar", "*"],
+    ["*", "Bar"],
+]
+arithmetic-side-effects-allowed-unary = ["Foo"]
diff --git a/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/clippy.toml b/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/clippy.toml
new file mode 100644 (file)
index 0000000..1b9384d
--- /dev/null
@@ -0,0 +1 @@
+suppress-restriction-lint-in-const = true
diff --git a/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.rs b/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.rs
new file mode 100644 (file)
index 0000000..5a2df9f
--- /dev/null
@@ -0,0 +1,60 @@
+#![feature(inline_const)]
+#![warn(clippy::indexing_slicing)]
+// We also check the out_of_bounds_indexing lint here, because it lints similar things and
+// we want to avoid false positives.
+#![warn(clippy::out_of_bounds_indexing)]
+#![allow(unconditional_panic, clippy::no_effect, clippy::unnecessary_operation)]
+
+const ARR: [i32; 2] = [1, 2];
+const REF: &i32 = &ARR[idx()]; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
+const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts.
+
+const fn idx() -> usize {
+    1
+}
+const fn idx4() -> usize {
+    4
+}
+
+fn main() {
+    let x = [1, 2, 3, 4];
+    let index: usize = 1;
+    x[index];
+    x[4]; // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays.
+    x[1 << 3]; // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays.
+
+    x[0]; // Ok, should not produce stderr.
+    x[3]; // Ok, should not produce stderr.
+    x[const { idx() }]; // Ok, should not produce stderr.
+    x[const { idx4() }]; // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays.
+    const { &ARR[idx()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
+    const { &ARR[idx4()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
+
+    let y = &x;
+    y[0]; // Ok, referencing shouldn't affect this lint. See the issue 6021
+    y[4]; // Ok, rustc will handle references too.
+
+    let v = vec![0; 5];
+    v[0];
+    v[10];
+    v[1 << 3];
+
+    const N: usize = 15; // Out of bounds
+    const M: usize = 3; // In bounds
+    x[N]; // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays.
+    x[M]; // Ok, should not produce stderr.
+    v[N];
+    v[M];
+}
+
+/// An opaque integer representation
+pub struct Integer<'a> {
+    /// The underlying data
+    value: &'a [u8],
+}
+impl<'a> Integer<'a> {
+    // Check whether `self` holds a negative number or not
+    pub const fn is_negative(&self) -> bool {
+        self.value[0] & 0b1000_0000 != 0
+    }
+}
diff --git a/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr b/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr
new file mode 100644 (file)
index 0000000..bc178b7
--- /dev/null
@@ -0,0 +1,70 @@
+error[E0080]: evaluation of `main::{constant#3}` failed
+  --> $DIR/test.rs:31:14
+   |
+LL |     const { &ARR[idx4()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
+   |              ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4
+
+note: erroneous constant used
+  --> $DIR/test.rs:31:5
+   |
+LL |     const { &ARR[idx4()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+
+error: indexing may panic
+  --> $DIR/test.rs:22:5
+   |
+LL |     x[index];
+   |     ^^^^^^^^
+   |
+   = help: consider using `.get(n)` or `.get_mut(n)` instead
+   = note: `-D clippy::indexing-slicing` implied by `-D warnings`
+
+error: indexing may panic
+  --> $DIR/test.rs:38:5
+   |
+LL |     v[0];
+   |     ^^^^
+   |
+   = help: consider using `.get(n)` or `.get_mut(n)` instead
+
+error: indexing may panic
+  --> $DIR/test.rs:39:5
+   |
+LL |     v[10];
+   |     ^^^^^
+   |
+   = help: consider using `.get(n)` or `.get_mut(n)` instead
+
+error: indexing may panic
+  --> $DIR/test.rs:40:5
+   |
+LL |     v[1 << 3];
+   |     ^^^^^^^^^
+   |
+   = help: consider using `.get(n)` or `.get_mut(n)` instead
+
+error: indexing may panic
+  --> $DIR/test.rs:46:5
+   |
+LL |     v[N];
+   |     ^^^^
+   |
+   = help: consider using `.get(n)` or `.get_mut(n)` instead
+
+error: indexing may panic
+  --> $DIR/test.rs:47:5
+   |
+LL |     v[M];
+   |     ^^^^
+   |
+   = help: consider using `.get(n)` or `.get_mut(n)` instead
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/test.rs:10:24
+   |
+LL | const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts.
+   |                        ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
index 01a5e962c9491ea0d52cd89707f4c1d3c3ec4e74..a22c6a5a0607d9ede572bdfd9ed7997237675717 100644 (file)
@@ -6,6 +6,8 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie
            allow-unwrap-in-tests
            allowed-scripts
            arithmetic-side-effects-allowed
+           arithmetic-side-effects-allowed-binary
+           arithmetic-side-effects-allowed-unary
            array-size-threshold
            avoid-breaking-exported-api
            await-holding-invalid-types
@@ -35,6 +37,7 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie
            pass-by-value-size-limit
            single-char-binding-names-threshold
            standard-macro-braces
+           suppress-restriction-lint-in-const
            third-party
            too-large-for-stack
            too-many-arguments-threshold
diff --git a/src/tools/clippy/tests/ui/almost_complete_letter_range.fixed b/src/tools/clippy/tests/ui/almost_complete_letter_range.fixed
deleted file mode 100644 (file)
index adcbd4d..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-// run-rustfix
-// edition:2018
-// aux-build:macro_rules.rs
-
-#![feature(exclusive_range_pattern)]
-#![feature(stmt_expr_attributes)]
-#![warn(clippy::almost_complete_letter_range)]
-#![allow(ellipsis_inclusive_range_patterns)]
-#![allow(clippy::needless_parens_on_range_literals)]
-
-#[macro_use]
-extern crate macro_rules;
-
-macro_rules! a {
-    () => {
-        'a'
-    };
-}
-
-macro_rules! b {
-    () => {
-        let _ = 'a'..='z';
-    };
-}
-
-fn main() {
-    #[rustfmt::skip]
-    {
-        let _ = ('a') ..='z';
-        let _ = 'A' ..= ('Z');
-    }
-
-    let _ = 'b'..'z';
-    let _ = 'B'..'Z';
-
-    let _ = (b'a')..=(b'z');
-    let _ = b'A'..=b'Z';
-
-    let _ = b'b'..b'z';
-    let _ = b'B'..b'Z';
-
-    let _ = a!()..='z';
-
-    let _ = match 0u8 {
-        b'a'..=b'z' if true => 1,
-        b'A'..=b'Z' if true => 2,
-        b'b'..b'z' => 3,
-        b'B'..b'Z' => 4,
-        _ => 5,
-    };
-
-    let _ = match 'x' {
-        'a'..='z' if true => 1,
-        'A'..='Z' if true => 2,
-        'b'..'z' => 3,
-        'B'..'Z' => 4,
-        _ => 5,
-    };
-
-    almost_complete_letter_range!();
-    b!();
-}
-
-#[clippy::msrv = "1.25"]
-fn _under_msrv() {
-    let _ = match 'a' {
-        'a'...'z' => 1,
-        _ => 2,
-    };
-}
-
-#[clippy::msrv = "1.26"]
-fn _meets_msrv() {
-    let _ = 'a'..='z';
-    let _ = match 'a' {
-        'a'..='z' => 1,
-        _ => 2,
-    };
-}
diff --git a/src/tools/clippy/tests/ui/almost_complete_letter_range.rs b/src/tools/clippy/tests/ui/almost_complete_letter_range.rs
deleted file mode 100644 (file)
index 9979316..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-// run-rustfix
-// edition:2018
-// aux-build:macro_rules.rs
-
-#![feature(exclusive_range_pattern)]
-#![feature(stmt_expr_attributes)]
-#![warn(clippy::almost_complete_letter_range)]
-#![allow(ellipsis_inclusive_range_patterns)]
-#![allow(clippy::needless_parens_on_range_literals)]
-
-#[macro_use]
-extern crate macro_rules;
-
-macro_rules! a {
-    () => {
-        'a'
-    };
-}
-
-macro_rules! b {
-    () => {
-        let _ = 'a'..'z';
-    };
-}
-
-fn main() {
-    #[rustfmt::skip]
-    {
-        let _ = ('a') ..'z';
-        let _ = 'A' .. ('Z');
-    }
-
-    let _ = 'b'..'z';
-    let _ = 'B'..'Z';
-
-    let _ = (b'a')..(b'z');
-    let _ = b'A'..b'Z';
-
-    let _ = b'b'..b'z';
-    let _ = b'B'..b'Z';
-
-    let _ = a!()..'z';
-
-    let _ = match 0u8 {
-        b'a'..b'z' if true => 1,
-        b'A'..b'Z' if true => 2,
-        b'b'..b'z' => 3,
-        b'B'..b'Z' => 4,
-        _ => 5,
-    };
-
-    let _ = match 'x' {
-        'a'..'z' if true => 1,
-        'A'..'Z' if true => 2,
-        'b'..'z' => 3,
-        'B'..'Z' => 4,
-        _ => 5,
-    };
-
-    almost_complete_letter_range!();
-    b!();
-}
-
-#[clippy::msrv = "1.25"]
-fn _under_msrv() {
-    let _ = match 'a' {
-        'a'..'z' => 1,
-        _ => 2,
-    };
-}
-
-#[clippy::msrv = "1.26"]
-fn _meets_msrv() {
-    let _ = 'a'..'z';
-    let _ = match 'a' {
-        'a'..'z' => 1,
-        _ => 2,
-    };
-}
diff --git a/src/tools/clippy/tests/ui/almost_complete_letter_range.stderr b/src/tools/clippy/tests/ui/almost_complete_letter_range.stderr
deleted file mode 100644 (file)
index 9abf6d6..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-error: almost complete ascii letter range
-  --> $DIR/almost_complete_letter_range.rs:29:17
-   |
-LL |         let _ = ('a') ..'z';
-   |                 ^^^^^^--^^^
-   |                       |
-   |                       help: use an inclusive range: `..=`
-   |
-   = note: `-D clippy::almost-complete-letter-range` implied by `-D warnings`
-
-error: almost complete ascii letter range
-  --> $DIR/almost_complete_letter_range.rs:30:17
-   |
-LL |         let _ = 'A' .. ('Z');
-   |                 ^^^^--^^^^^^
-   |                     |
-   |                     help: use an inclusive range: `..=`
-
-error: almost complete ascii letter range
-  --> $DIR/almost_complete_letter_range.rs:36:13
-   |
-LL |     let _ = (b'a')..(b'z');
-   |             ^^^^^^--^^^^^^
-   |                   |
-   |                   help: use an inclusive range: `..=`
-
-error: almost complete ascii letter range
-  --> $DIR/almost_complete_letter_range.rs:37:13
-   |
-LL |     let _ = b'A'..b'Z';
-   |             ^^^^--^^^^
-   |                 |
-   |                 help: use an inclusive range: `..=`
-
-error: almost complete ascii letter range
-  --> $DIR/almost_complete_letter_range.rs:42:13
-   |
-LL |     let _ = a!()..'z';
-   |             ^^^^--^^^
-   |                 |
-   |                 help: use an inclusive range: `..=`
-
-error: almost complete ascii letter range
-  --> $DIR/almost_complete_letter_range.rs:45:9
-   |
-LL |         b'a'..b'z' if true => 1,
-   |         ^^^^--^^^^
-   |             |
-   |             help: use an inclusive range: `..=`
-
-error: almost complete ascii letter range
-  --> $DIR/almost_complete_letter_range.rs:46:9
-   |
-LL |         b'A'..b'Z' if true => 2,
-   |         ^^^^--^^^^
-   |             |
-   |             help: use an inclusive range: `..=`
-
-error: almost complete ascii letter range
-  --> $DIR/almost_complete_letter_range.rs:53:9
-   |
-LL |         'a'..'z' if true => 1,
-   |         ^^^--^^^
-   |            |
-   |            help: use an inclusive range: `..=`
-
-error: almost complete ascii letter range
-  --> $DIR/almost_complete_letter_range.rs:54:9
-   |
-LL |         'A'..'Z' if true => 2,
-   |         ^^^--^^^
-   |            |
-   |            help: use an inclusive range: `..=`
-
-error: almost complete ascii letter range
-  --> $DIR/almost_complete_letter_range.rs:22:17
-   |
-LL |         let _ = 'a'..'z';
-   |                 ^^^--^^^
-   |                    |
-   |                    help: use an inclusive range: `..=`
-...
-LL |     b!();
-   |     ---- in this macro invocation
-   |
-   = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: almost complete ascii letter range
-  --> $DIR/almost_complete_letter_range.rs:67:9
-   |
-LL |         'a'..'z' => 1,
-   |         ^^^--^^^
-   |            |
-   |            help: use an inclusive range: `...`
-
-error: almost complete ascii letter range
-  --> $DIR/almost_complete_letter_range.rs:74:13
-   |
-LL |     let _ = 'a'..'z';
-   |             ^^^--^^^
-   |                |
-   |                help: use an inclusive range: `..=`
-
-error: almost complete ascii letter range
-  --> $DIR/almost_complete_letter_range.rs:76:9
-   |
-LL |         'a'..'z' => 1,
-   |         ^^^--^^^
-   |            |
-   |            help: use an inclusive range: `..=`
-
-error: aborting due to 13 previous errors
-
diff --git a/src/tools/clippy/tests/ui/almost_complete_range.fixed b/src/tools/clippy/tests/ui/almost_complete_range.fixed
new file mode 100644 (file)
index 0000000..6046add
--- /dev/null
@@ -0,0 +1,108 @@
+// run-rustfix
+// edition:2018
+// aux-build:macro_rules.rs
+
+#![feature(exclusive_range_pattern)]
+#![feature(stmt_expr_attributes)]
+#![warn(clippy::almost_complete_range)]
+#![allow(ellipsis_inclusive_range_patterns)]
+#![allow(clippy::needless_parens_on_range_literals)]
+#![allow(clippy::double_parens)]
+
+#[macro_use]
+extern crate macro_rules;
+
+macro_rules! a {
+    () => {
+        'a'
+    };
+}
+macro_rules! A {
+    () => {
+        'A'
+    };
+}
+macro_rules! zero {
+    () => {
+        '0'
+    };
+}
+
+macro_rules! b {
+    () => {
+        let _ = 'a'..='z';
+        let _ = 'A'..='Z';
+        let _ = '0'..='9';
+    };
+}
+
+fn main() {
+    #[rustfmt::skip]
+    {
+        let _ = ('a') ..='z';
+        let _ = 'A' ..= ('Z');
+        let _ = ((('0'))) ..= ('9');
+    }
+
+    let _ = 'b'..'z';
+    let _ = 'B'..'Z';
+    let _ = '1'..'9';
+
+    let _ = (b'a')..=(b'z');
+    let _ = b'A'..=b'Z';
+    let _ = b'0'..=b'9';
+
+    let _ = b'b'..b'z';
+    let _ = b'B'..b'Z';
+    let _ = b'1'..b'9';
+
+    let _ = a!()..='z';
+    let _ = A!()..='Z';
+    let _ = zero!()..='9';
+
+    let _ = match 0u8 {
+        b'a'..=b'z' if true => 1,
+        b'A'..=b'Z' if true => 2,
+        b'0'..=b'9' if true => 3,
+        b'b'..b'z' => 4,
+        b'B'..b'Z' => 5,
+        b'1'..b'9' => 6,
+        _ => 7,
+    };
+
+    let _ = match 'x' {
+        'a'..='z' if true => 1,
+        'A'..='Z' if true => 2,
+        '0'..='9' if true => 3,
+        'b'..'z' => 4,
+        'B'..'Z' => 5,
+        '1'..'9' => 6,
+        _ => 7,
+    };
+
+    almost_complete_range!();
+    b!();
+}
+
+#[clippy::msrv = "1.25"]
+fn _under_msrv() {
+    let _ = match 'a' {
+        'a'...'z' => 1,
+        'A'...'Z' => 2,
+        '0'...'9' => 3,
+        _ => 4,
+    };
+}
+
+#[clippy::msrv = "1.26"]
+fn _meets_msrv() {
+    let _ = 'a'..='z';
+    let _ = 'A'..='Z';
+    let _ = '0'..='9';
+    let _ = match 'a' {
+        'a'..='z' => 1,
+        'A'..='Z' => 1,
+        '0'..='9' => 3,
+        _ => 4,
+    };
+}
diff --git a/src/tools/clippy/tests/ui/almost_complete_range.rs b/src/tools/clippy/tests/ui/almost_complete_range.rs
new file mode 100644 (file)
index 0000000..ae7e07a
--- /dev/null
@@ -0,0 +1,108 @@
+// run-rustfix
+// edition:2018
+// aux-build:macro_rules.rs
+
+#![feature(exclusive_range_pattern)]
+#![feature(stmt_expr_attributes)]
+#![warn(clippy::almost_complete_range)]
+#![allow(ellipsis_inclusive_range_patterns)]
+#![allow(clippy::needless_parens_on_range_literals)]
+#![allow(clippy::double_parens)]
+
+#[macro_use]
+extern crate macro_rules;
+
+macro_rules! a {
+    () => {
+        'a'
+    };
+}
+macro_rules! A {
+    () => {
+        'A'
+    };
+}
+macro_rules! zero {
+    () => {
+        '0'
+    };
+}
+
+macro_rules! b {
+    () => {
+        let _ = 'a'..'z';
+        let _ = 'A'..'Z';
+        let _ = '0'..'9';
+    };
+}
+
+fn main() {
+    #[rustfmt::skip]
+    {
+        let _ = ('a') ..'z';
+        let _ = 'A' .. ('Z');
+        let _ = ((('0'))) .. ('9');
+    }
+
+    let _ = 'b'..'z';
+    let _ = 'B'..'Z';
+    let _ = '1'..'9';
+
+    let _ = (b'a')..(b'z');
+    let _ = b'A'..b'Z';
+    let _ = b'0'..b'9';
+
+    let _ = b'b'..b'z';
+    let _ = b'B'..b'Z';
+    let _ = b'1'..b'9';
+
+    let _ = a!()..'z';
+    let _ = A!()..'Z';
+    let _ = zero!()..'9';
+
+    let _ = match 0u8 {
+        b'a'..b'z' if true => 1,
+        b'A'..b'Z' if true => 2,
+        b'0'..b'9' if true => 3,
+        b'b'..b'z' => 4,
+        b'B'..b'Z' => 5,
+        b'1'..b'9' => 6,
+        _ => 7,
+    };
+
+    let _ = match 'x' {
+        'a'..'z' if true => 1,
+        'A'..'Z' if true => 2,
+        '0'..'9' if true => 3,
+        'b'..'z' => 4,
+        'B'..'Z' => 5,
+        '1'..'9' => 6,
+        _ => 7,
+    };
+
+    almost_complete_range!();
+    b!();
+}
+
+#[clippy::msrv = "1.25"]
+fn _under_msrv() {
+    let _ = match 'a' {
+        'a'..'z' => 1,
+        'A'..'Z' => 2,
+        '0'..'9' => 3,
+        _ => 4,
+    };
+}
+
+#[clippy::msrv = "1.26"]
+fn _meets_msrv() {
+    let _ = 'a'..'z';
+    let _ = 'A'..'Z';
+    let _ = '0'..'9';
+    let _ = match 'a' {
+        'a'..'z' => 1,
+        'A'..'Z' => 1,
+        '0'..'9' => 3,
+        _ => 4,
+    };
+}
diff --git a/src/tools/clippy/tests/ui/almost_complete_range.stderr b/src/tools/clippy/tests/ui/almost_complete_range.stderr
new file mode 100644 (file)
index 0000000..a7a5328
--- /dev/null
@@ -0,0 +1,235 @@
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:42:17
+   |
+LL |         let _ = ('a') ..'z';
+   |                 ^^^^^^--^^^
+   |                       |
+   |                       help: use an inclusive range: `..=`
+   |
+   = note: `-D clippy::almost-complete-range` implied by `-D warnings`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:43:17
+   |
+LL |         let _ = 'A' .. ('Z');
+   |                 ^^^^--^^^^^^
+   |                     |
+   |                     help: use an inclusive range: `..=`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:44:17
+   |
+LL |         let _ = ((('0'))) .. ('9');
+   |                 ^^^^^^^^^^--^^^^^^
+   |                           |
+   |                           help: use an inclusive range: `..=`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:51:13
+   |
+LL |     let _ = (b'a')..(b'z');
+   |             ^^^^^^--^^^^^^
+   |                   |
+   |                   help: use an inclusive range: `..=`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:52:13
+   |
+LL |     let _ = b'A'..b'Z';
+   |             ^^^^--^^^^
+   |                 |
+   |                 help: use an inclusive range: `..=`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:53:13
+   |
+LL |     let _ = b'0'..b'9';
+   |             ^^^^--^^^^
+   |                 |
+   |                 help: use an inclusive range: `..=`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:59:13
+   |
+LL |     let _ = a!()..'z';
+   |             ^^^^--^^^
+   |                 |
+   |                 help: use an inclusive range: `..=`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:60:13
+   |
+LL |     let _ = A!()..'Z';
+   |             ^^^^--^^^
+   |                 |
+   |                 help: use an inclusive range: `..=`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:61:13
+   |
+LL |     let _ = zero!()..'9';
+   |             ^^^^^^^--^^^
+   |                    |
+   |                    help: use an inclusive range: `..=`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:64:9
+   |
+LL |         b'a'..b'z' if true => 1,
+   |         ^^^^--^^^^
+   |             |
+   |             help: use an inclusive range: `..=`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:65:9
+   |
+LL |         b'A'..b'Z' if true => 2,
+   |         ^^^^--^^^^
+   |             |
+   |             help: use an inclusive range: `..=`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:66:9
+   |
+LL |         b'0'..b'9' if true => 3,
+   |         ^^^^--^^^^
+   |             |
+   |             help: use an inclusive range: `..=`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:74:9
+   |
+LL |         'a'..'z' if true => 1,
+   |         ^^^--^^^
+   |            |
+   |            help: use an inclusive range: `..=`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:75:9
+   |
+LL |         'A'..'Z' if true => 2,
+   |         ^^^--^^^
+   |            |
+   |            help: use an inclusive range: `..=`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:76:9
+   |
+LL |         '0'..'9' if true => 3,
+   |         ^^^--^^^
+   |            |
+   |            help: use an inclusive range: `..=`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:33:17
+   |
+LL |         let _ = 'a'..'z';
+   |                 ^^^--^^^
+   |                    |
+   |                    help: use an inclusive range: `..=`
+...
+LL |     b!();
+   |     ---- in this macro invocation
+   |
+   = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:34:17
+   |
+LL |         let _ = 'A'..'Z';
+   |                 ^^^--^^^
+   |                    |
+   |                    help: use an inclusive range: `..=`
+...
+LL |     b!();
+   |     ---- in this macro invocation
+   |
+   = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:35:17
+   |
+LL |         let _ = '0'..'9';
+   |                 ^^^--^^^
+   |                    |
+   |                    help: use an inclusive range: `..=`
+...
+LL |     b!();
+   |     ---- in this macro invocation
+   |
+   = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:90:9
+   |
+LL |         'a'..'z' => 1,
+   |         ^^^--^^^
+   |            |
+   |            help: use an inclusive range: `...`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:91:9
+   |
+LL |         'A'..'Z' => 2,
+   |         ^^^--^^^
+   |            |
+   |            help: use an inclusive range: `...`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:92:9
+   |
+LL |         '0'..'9' => 3,
+   |         ^^^--^^^
+   |            |
+   |            help: use an inclusive range: `...`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:99:13
+   |
+LL |     let _ = 'a'..'z';
+   |             ^^^--^^^
+   |                |
+   |                help: use an inclusive range: `..=`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:100:13
+   |
+LL |     let _ = 'A'..'Z';
+   |             ^^^--^^^
+   |                |
+   |                help: use an inclusive range: `..=`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:101:13
+   |
+LL |     let _ = '0'..'9';
+   |             ^^^--^^^
+   |                |
+   |                help: use an inclusive range: `..=`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:103:9
+   |
+LL |         'a'..'z' => 1,
+   |         ^^^--^^^
+   |            |
+   |            help: use an inclusive range: `..=`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:104:9
+   |
+LL |         'A'..'Z' => 1,
+   |         ^^^--^^^
+   |            |
+   |            help: use an inclusive range: `..=`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:105:9
+   |
+LL |         '0'..'9' => 3,
+   |         ^^^--^^^
+   |            |
+   |            help: use an inclusive range: `..=`
+
+error: aborting due to 27 previous errors
+
index 0259a0824e794cc7ba5a0f957f0130f6b3c49a0e..9fe4b7cf28d8d3fc4ee574fa194d060adc6f3d8f 100644 (file)
@@ -1,28 +1,10 @@
-error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:78:13
-   |
-LL |     let _ = String::new() + "";
-   |             ^^^^^^^^^^^^^^^^^^
-   |
-   = note: `-D clippy::arithmetic-side-effects` implied by `-D warnings`
-
-error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:86:27
-   |
-LL |     let inferred_string = string + "";
-   |                           ^^^^^^^^^^^
-
-error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:90:13
-   |
-LL |     let _ = inferred_string + "";
-   |             ^^^^^^^^^^^^^^^^^^^^
-
 error: arithmetic operation that can potentially result in unexpected side-effects
   --> $DIR/arithmetic_side_effects.rs:165:5
    |
 LL |     _n += 1;
    |     ^^^^^^^
+   |
+   = note: `-D clippy::arithmetic-side-effects` implied by `-D warnings`
 
 error: arithmetic operation that can potentially result in unexpected side-effects
   --> $DIR/arithmetic_side_effects.rs:166:5
@@ -348,5 +330,5 @@ error: arithmetic operation that can potentially result in unexpected side-effec
 LL |     _n = -&_n;
    |          ^^^^
 
-error: aborting due to 58 previous errors
+error: aborting due to 55 previous errors
 
index ef3ca9aea380c0bfba020deffb65b601f56a90b4..1e5f20e8c39baf5ad8c47d5dd77530bfcba75dc6 100644 (file)
@@ -142,8 +142,10 @@ macro_rules! equatable_if_let {
 }
 
 #[macro_export]
-macro_rules! almost_complete_letter_range {
+macro_rules! almost_complete_range {
     () => {
         let _ = 'a'..'z';
+        let _ = 'A'..'Z';
+        let _ = '0'..'9';
     };
 }
index eefeb1decb69e604519618c9567ab6ee990b3a81..7c57864245a9446f5849fac3c732557eb0b53ca3 100644 (file)
@@ -42,7 +42,7 @@ impl<T> StaticRef<T> {
 impl<T> std::ops::Deref for StaticRef<T> {
     type Target = T;
 
-    fn deref(&self) -> &'static T {
+    fn deref(&self) -> &T {
         unsafe { &*self.ptr }
     }
 }
index 72a708b40737b3932688127ec9b1905901bacb86..925cbf25368fbd18b3ceb6b537b38070e82266a4 100644 (file)
@@ -45,3 +45,9 @@ mod cast_lossless_in_impl {
         }
     }
 }
+
+#[derive(PartialEq, Debug)]
+#[repr(i64)]
+enum Test {
+    A = u32::MAX as i64 + 1,
+}
index 34bb47181e69deffcf1bfe283ed4557b68d08c4e..c82bd9108d23bfb8ad03bc97911c76d49e00cb67 100644 (file)
@@ -45,3 +45,9 @@ pub const fn convert(x: u32) -> u64 {
         }
     }
 }
+
+#[derive(PartialEq, Debug)]
+#[repr(i64)]
+enum Test {
+    A = u32::MAX as i64 + 1,
+}
index 49fc9a9629e25415a714b6e3616602c77367f239..9792ae9ed6b8b34ddb097b3c17be2cf15a4692f4 100644 (file)
@@ -1,5 +1,6 @@
 // run-rustfix
 
+#![allow(unused)]
 #![warn(clippy::collapsible_str_replace)]
 
 fn get_filter() -> char {
@@ -71,3 +72,13 @@ fn main() {
         .replace('u', iter.next().unwrap())
         .replace('s', iter.next().unwrap());
 }
+
+#[clippy::msrv = "1.57"]
+fn msrv_1_57() {
+    let _ = "".replace('a', "1.57").replace('b', "1.57");
+}
+
+#[clippy::msrv = "1.58"]
+fn msrv_1_58() {
+    let _ = "".replace(['a', 'b'], "1.58");
+}
index e3e25c4146ffa6bdd7a71bcd2067ba9a6ec6b68e..baee185b79ea388e77b8d143de03d68d92c964a9 100644 (file)
@@ -1,5 +1,6 @@
 // run-rustfix
 
+#![allow(unused)]
 #![warn(clippy::collapsible_str_replace)]
 
 fn get_filter() -> char {
@@ -74,3 +75,13 @@ fn main() {
         .replace('u', iter.next().unwrap())
         .replace('s', iter.next().unwrap());
 }
+
+#[clippy::msrv = "1.57"]
+fn msrv_1_57() {
+    let _ = "".replace('a', "1.57").replace('b', "1.57");
+}
+
+#[clippy::msrv = "1.58"]
+fn msrv_1_58() {
+    let _ = "".replace('a', "1.58").replace('b', "1.58");
+}
index 8e3daf3b898a3328e6f5f9de77f42e24f2729b79..223358cf53f3e0e07c8b2db2c37a9d4cb9f619b4 100644 (file)
@@ -1,5 +1,5 @@
 error: used consecutive `str::replace` call
-  --> $DIR/collapsible_str_replace.rs:19:27
+  --> $DIR/collapsible_str_replace.rs:20:27
    |
 LL |     let _ = "hesuo worpd".replace('s', "l").replace('u', "l");
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['s', 'u'], "l")`
@@ -7,19 +7,19 @@ LL |     let _ = "hesuo worpd".replace('s', "l").replace('u', "l");
    = note: `-D clippy::collapsible-str-replace` implied by `-D warnings`
 
 error: used consecutive `str::replace` call
-  --> $DIR/collapsible_str_replace.rs:21:27
+  --> $DIR/collapsible_str_replace.rs:22:27
    |
 LL |     let _ = "hesuo worpd".replace('s', l).replace('u', l);
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['s', 'u'], l)`
 
 error: used consecutive `str::replace` call
-  --> $DIR/collapsible_str_replace.rs:23:27
+  --> $DIR/collapsible_str_replace.rs:24:27
    |
 LL |     let _ = "hesuo worpd".replace('s', "l").replace('u', "l").replace('p', "l");
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['s', 'u', 'p'], "l")`
 
 error: used consecutive `str::replace` call
-  --> $DIR/collapsible_str_replace.rs:26:10
+  --> $DIR/collapsible_str_replace.rs:27:10
    |
 LL |           .replace('s', "l")
    |  __________^
@@ -29,58 +29,64 @@ LL | |         .replace('d', "l");
    | |__________________________^ help: replace with: `replace(['s', 'u', 'p', 'd'], "l")`
 
 error: used consecutive `str::replace` call
-  --> $DIR/collapsible_str_replace.rs:31:27
+  --> $DIR/collapsible_str_replace.rs:32:27
    |
 LL |     let _ = "hesuo world".replace(s, "l").replace('u', "l");
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([s, 'u'], "l")`
 
 error: used consecutive `str::replace` call
-  --> $DIR/collapsible_str_replace.rs:33:27
+  --> $DIR/collapsible_str_replace.rs:34:27
    |
 LL |     let _ = "hesuo worpd".replace(s, "l").replace('u', "l").replace('p', "l");
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([s, 'u', 'p'], "l")`
 
 error: used consecutive `str::replace` call
-  --> $DIR/collapsible_str_replace.rs:35:27
+  --> $DIR/collapsible_str_replace.rs:36:27
    |
 LL |     let _ = "hesuo worpd".replace(s, "l").replace(u, "l").replace('p', "l");
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([s, u, 'p'], "l")`
 
 error: used consecutive `str::replace` call
-  --> $DIR/collapsible_str_replace.rs:37:27
+  --> $DIR/collapsible_str_replace.rs:38:27
    |
 LL |     let _ = "hesuo worpd".replace(s, "l").replace(u, "l").replace(p, "l");
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([s, u, p], "l")`
 
 error: used consecutive `str::replace` call
-  --> $DIR/collapsible_str_replace.rs:39:27
+  --> $DIR/collapsible_str_replace.rs:40:27
    |
 LL |     let _ = "hesuo worlp".replace('s', "l").replace('u', "l").replace('p', "d");
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['s', 'u'], "l")`
 
 error: used consecutive `str::replace` call
-  --> $DIR/collapsible_str_replace.rs:41:45
+  --> $DIR/collapsible_str_replace.rs:42:45
    |
 LL |     let _ = "hesuo worpd".replace('s', "x").replace('u', "l").replace('p', "l");
    |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['u', 'p'], "l")`
 
 error: used consecutive `str::replace` call
-  --> $DIR/collapsible_str_replace.rs:44:47
+  --> $DIR/collapsible_str_replace.rs:45:47
    |
 LL |     let _ = "hesudo worpd".replace("su", "l").replace('d', "l").replace('p', "l");
    |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['d', 'p'], "l")`
 
 error: used consecutive `str::replace` call
-  --> $DIR/collapsible_str_replace.rs:46:28
+  --> $DIR/collapsible_str_replace.rs:47:28
    |
 LL |     let _ = "hesudo worpd".replace(d, "l").replace('p', "l").replace("su", "l");
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([d, 'p'], "l")`
 
 error: used consecutive `str::replace` call
-  --> $DIR/collapsible_str_replace.rs:48:27
+  --> $DIR/collapsible_str_replace.rs:49:27
    |
 LL |     let _ = "hesuo world".replace(get_filter(), "l").replace('s', "l");
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([get_filter(), 's'], "l")`
 
-error: aborting due to 13 previous errors
+error: used consecutive `str::replace` call
+  --> $DIR/collapsible_str_replace.rs:86:16
+   |
+LL |     let _ = "".replace('a', "1.58").replace('b', "1.58");
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['a', 'b'], "1.58")`
+
+error: aborting due to 14 previous errors
 
index 6eddc01e2c471215af0fa4584f5083e5a1eec796..46565a97f005979b3bc03a5a4555d41a8c2ac0cc 100644 (file)
@@ -189,3 +189,33 @@ pub fn test() {
         }
     }
 }
+
+mod issue_10058 {
+    pub fn test() {
+        // should not lint since we are increasing counter potentially more than once in the loop
+        let values = [0, 1, 0, 1, 1, 1, 0, 1, 0, 1];
+        let mut counter = 0;
+        for value in values {
+            counter += 1;
+
+            if value == 0 {
+                continue;
+            }
+
+            counter += 1;
+        }
+    }
+
+    pub fn test2() {
+        // should not lint since we are increasing counter potentially more than once in the loop
+        let values = [0, 1, 0, 1, 1, 1, 0, 1, 0, 1];
+        let mut counter = 0;
+        for value in values {
+            counter += 1;
+
+            if value != 0 {
+                counter += 1;
+            }
+        }
+    }
+}
index 125c9a69cd3fd1fdd48f8b7a37d7672d84f18a9a..72d635c2ccd65609ada5efc15d5197457ec4b622 100644 (file)
@@ -1,5 +1,6 @@
 // run-rustfix
 
+#![feature(type_alias_impl_trait)]
 #![warn(clippy::from_over_into)]
 #![allow(unused)]
 
@@ -81,4 +82,10 @@ fn msrv_1_41() {
     }
 }
 
+type Opaque = impl Sized;
+struct IntoOpaque;
+impl Into<Opaque> for IntoOpaque {
+    fn into(self) -> Opaque {}
+}
+
 fn main() {}
index 5aa127bfabe4b792a59ab914277c7034d7e06b2b..965f4d5d7859ee47484ccc12da79112bbc743fad 100644 (file)
@@ -1,5 +1,6 @@
 // run-rustfix
 
+#![feature(type_alias_impl_trait)]
 #![warn(clippy::from_over_into)]
 #![allow(unused)]
 
@@ -81,4 +82,10 @@ fn into(self) -> FromOverInto<T> {
     }
 }
 
+type Opaque = impl Sized;
+struct IntoOpaque;
+impl Into<Opaque> for IntoOpaque {
+    fn into(self) -> Opaque {}
+}
+
 fn main() {}
index a1764a5ea12ae8f5deef37156c803d244523c4f0..3c4d011d6fb468e735fb07c7d49a7064bad3fcc7 100644 (file)
@@ -1,5 +1,5 @@
 error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
-  --> $DIR/from_over_into.rs:9:1
+  --> $DIR/from_over_into.rs:10:1
    |
 LL | impl Into<StringWrapper> for String {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -13,7 +13,7 @@ LL ~         StringWrapper(val)
    |
 
 error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
-  --> $DIR/from_over_into.rs:17:1
+  --> $DIR/from_over_into.rs:18:1
    |
 LL | impl Into<SelfType> for String {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -26,7 +26,7 @@ LL ~         SelfType(String::new())
    |
 
 error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
-  --> $DIR/from_over_into.rs:32:1
+  --> $DIR/from_over_into.rs:33:1
    |
 LL | impl Into<SelfKeywords> for X {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -41,7 +41,7 @@ LL ~         let _: X = val;
    |
 
 error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
-  --> $DIR/from_over_into.rs:44:1
+  --> $DIR/from_over_into.rs:45:1
    |
 LL | impl core::convert::Into<bool> for crate::ExplicitPaths {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -59,7 +59,7 @@ LL ~         val.0
    |
 
 error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
-  --> $DIR/from_over_into.rs:77:5
+  --> $DIR/from_over_into.rs:78:5
    |
 LL |     impl<T> Into<FromOverInto<T>> for Vec<T> {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
index e7b9a78c5dbc3e3fdf95f0aa971f8c128b672e23..cac69ef42c4136e36e5b8571b0963c62b799b11a 100644 (file)
@@ -65,7 +65,7 @@ fn main() {
     42;
     1;
     42;
-    &x;
+    x;
     x;
 
     let mut a = A(String::new());
@@ -112,6 +112,10 @@ fn main() {
     2 * { a };
     (({ a } + 4));
     1;
+
+    // Issue #9904
+    let x = 0i32;
+    let _: i32 = x;
 }
 
 pub fn decide(a: bool, b: bool) -> u32 {
index 9a435cdbb753f34dca293efde32429b27817e88f..33201aad4f641244e93af221aff06f183ac1d470 100644 (file)
@@ -112,6 +112,10 @@ fn f(_: i32) {
     2 * (0 + { a });
     1 * ({ a } + 4);
     1 * 1;
+
+    // Issue #9904
+    let x = 0i32;
+    let _: i32 = &x + 0;
 }
 
 pub fn decide(a: bool, b: bool) -> u32 {
index 1a104a20b841c1688e9412fffaf261867ef26905..3ba557d18b24433c9c57bd491ffcfb44f929e9db 100644 (file)
@@ -70,7 +70,7 @@ error: this operation has no effect
   --> $DIR/identity_op.rs:68:5
    |
 LL |     &x >> 0;
-   |     ^^^^^^^ help: consider reducing it to: `&x`
+   |     ^^^^^^^ help: consider reducing it to: `x`
 
 error: this operation has no effect
   --> $DIR/identity_op.rs:69:5
@@ -229,10 +229,16 @@ LL |     1 * 1;
    |     ^^^^^ help: consider reducing it to: `1`
 
 error: this operation has no effect
-  --> $DIR/identity_op.rs:118:5
+  --> $DIR/identity_op.rs:118:18
+   |
+LL |     let _: i32 = &x + 0;
+   |                  ^^^^^^ help: consider reducing it to: `x`
+
+error: this operation has no effect
+  --> $DIR/identity_op.rs:122:5
    |
 LL |     0 + if a { 1 } else { 2 } + if b { 3 } else { 5 }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(if a { 1 } else { 2 })`
 
-error: aborting due to 39 previous errors
+error: aborting due to 40 previous errors
 
index 33770fc2a2cf9cca67a956157de5fc83599d93d2..51b1afbe5ac83ecaffe7bcca428f1ed8b08fa2bc 100644 (file)
@@ -115,4 +115,14 @@ fn main() {
     let pathbuf_ref = &pathbuf_ref;
     let _ = pathbuf_ref.to_owned(); // Don't lint. Returns `&&PathBuf`
     let _ = (**pathbuf_ref).clone();
+
+    struct NoClone;
+    impl ToOwned for NoClone {
+        type Owned = Self;
+        fn to_owned(&self) -> Self {
+            NoClone
+        }
+    }
+    let no_clone = &NoClone;
+    let _ = no_clone.to_owned();
 }
index fc896525bd2709ba82b41b56073bf8418649488e..8a9027433d95be632772e54ef97025e8e8a58df1 100644 (file)
@@ -115,4 +115,14 @@ fn main() {
     let pathbuf_ref = &pathbuf_ref;
     let _ = pathbuf_ref.to_owned(); // Don't lint. Returns `&&PathBuf`
     let _ = pathbuf_ref.to_path_buf();
+
+    struct NoClone;
+    impl ToOwned for NoClone {
+        type Owned = Self;
+        fn to_owned(&self) -> Self {
+            NoClone
+        }
+    }
+    let no_clone = &NoClone;
+    let _ = no_clone.to_owned();
 }
index 4476e0eb9220a636eb6c813ec414e661584c8c79..26abc9edb5e445f16976d94e032d33003388166d 100644 (file)
@@ -6,7 +6,7 @@
 #![allow(unconditional_panic, clippy::no_effect, clippy::unnecessary_operation)]
 
 const ARR: [i32; 2] = [1, 2];
-const REF: &i32 = &ARR[idx()]; // Ok, should not produce stderr.
+const REF: &i32 = &ARR[idx()]; // This should be linted, since `suppress-restriction-lint-in-const` default is false.
 const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts.
 
 const fn idx() -> usize {
@@ -27,8 +27,8 @@ fn main() {
     x[3]; // Ok, should not produce stderr.
     x[const { idx() }]; // Ok, should not produce stderr.
     x[const { idx4() }]; // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays.
-    const { &ARR[idx()] }; // Ok, should not produce stderr.
-    const { &ARR[idx4()] }; // Ok, let rustc handle const contexts.
+    const { &ARR[idx()] }; // This should be linted, since `suppress-restriction-lint-in-const` default is false.
+    const { &ARR[idx4()] }; // This should be linted, since `suppress-restriction-lint-in-const` default is false.
 
     let y = &x;
     y[0]; // Ok, referencing shouldn't affect this lint. See the issue 6021
index d8b6e3f1262b735345660276aa3456cb759aad52..8fd77913a3fd97626ed617357380b578ab13ef1c 100644 (file)
@@ -1,13 +1,32 @@
+error: indexing may panic
+  --> $DIR/indexing_slicing_index.rs:9:20
+   |
+LL | const REF: &i32 = &ARR[idx()]; // This should be linted, since `suppress-restriction-lint-in-const` default is false.
+   |                    ^^^^^^^^^^
+   |
+   = help: consider using `.get(n)` or `.get_mut(n)` instead
+   = note: the suggestion might not be applicable in constant blocks
+   = note: `-D clippy::indexing-slicing` implied by `-D warnings`
+
+error: indexing may panic
+  --> $DIR/indexing_slicing_index.rs:10:24
+   |
+LL | const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts.
+   |                        ^^^^^^^^^^^
+   |
+   = help: consider using `.get(n)` or `.get_mut(n)` instead
+   = note: the suggestion might not be applicable in constant blocks
+
 error[E0080]: evaluation of `main::{constant#3}` failed
   --> $DIR/indexing_slicing_index.rs:31:14
    |
-LL |     const { &ARR[idx4()] }; // Ok, let rustc handle const contexts.
+LL |     const { &ARR[idx4()] }; // This should be linted, since `suppress-restriction-lint-in-const` default is false.
    |              ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4
 
 note: erroneous constant used
   --> $DIR/indexing_slicing_index.rs:31:5
    |
-LL |     const { &ARR[idx4()] }; // Ok, let rustc handle const contexts.
+LL |     const { &ARR[idx4()] }; // This should be linted, since `suppress-restriction-lint-in-const` default is false.
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: indexing may panic
@@ -17,7 +36,24 @@ LL |     x[index];
    |     ^^^^^^^^
    |
    = help: consider using `.get(n)` or `.get_mut(n)` instead
-   = note: `-D clippy::indexing-slicing` implied by `-D warnings`
+
+error: indexing may panic
+  --> $DIR/indexing_slicing_index.rs:30:14
+   |
+LL |     const { &ARR[idx()] }; // This should be linted, since `suppress-restriction-lint-in-const` default is false.
+   |              ^^^^^^^^^^
+   |
+   = help: consider using `.get(n)` or `.get_mut(n)` instead
+   = note: the suggestion might not be applicable in constant blocks
+
+error: indexing may panic
+  --> $DIR/indexing_slicing_index.rs:31:14
+   |
+LL |     const { &ARR[idx4()] }; // This should be linted, since `suppress-restriction-lint-in-const` default is false.
+   |              ^^^^^^^^^^^
+   |
+   = help: consider using `.get(n)` or `.get_mut(n)` instead
+   = note: the suggestion might not be applicable in constant blocks
 
 error: indexing may panic
   --> $DIR/indexing_slicing_index.rs:38:5
@@ -65,6 +101,6 @@ error[E0080]: evaluation of constant value failed
 LL | const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts.
    |                        ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4
 
-error: aborting due to 8 previous errors
+error: aborting due to 12 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
index 1f3b8ac99b19146f766e6758d0cd799d37dc92c0..c1c0b5ae40f6170b4b9d4daa0dd5424f661b8fa7 100644 (file)
@@ -3,6 +3,9 @@
 #![warn(clippy::len_zero)]
 #![allow(dead_code, unused, clippy::len_without_is_empty)]
 
+extern crate core;
+use core::ops::Deref;
+
 pub struct One;
 struct Wither;
 
@@ -56,6 +59,26 @@ impl WithIsEmpty for Wither {
     }
 }
 
+struct DerefToDerefToString;
+
+impl Deref for DerefToDerefToString {
+    type Target = DerefToString;
+
+    fn deref(&self) -> &Self::Target {
+        &DerefToString {}
+    }
+}
+
+struct DerefToString;
+
+impl Deref for DerefToString {
+    type Target = str;
+
+    fn deref(&self) -> &Self::Target {
+        "Hello, world!"
+    }
+}
+
 fn main() {
     let x = [1, 2];
     if x.is_empty() {
@@ -64,6 +87,23 @@ fn main() {
 
     if "".is_empty() {}
 
+    let s = "Hello, world!";
+    let s1 = &s;
+    let s2 = &s1;
+    let s3 = &s2;
+    let s4 = &s3;
+    let s5 = &s4;
+    let s6 = &s5;
+    println!("{}", s1.is_empty());
+    println!("{}", s2.is_empty());
+    println!("{}", s3.is_empty());
+    println!("{}", s4.is_empty());
+    println!("{}", s5.is_empty());
+    println!("{}", (s6).is_empty());
+
+    let d2s = DerefToDerefToString {};
+    println!("{}", (**d2s).is_empty());
+
     let y = One;
     if y.len() == 0 {
         // No error; `One` does not have `.is_empty()`.
index dc21de0001b6c76eb2f57cdba4e7416319d5b756..cc2eb05b6bfd2ee81c35ea7754118532dd5f7ab9 100644 (file)
@@ -3,6 +3,9 @@
 #![warn(clippy::len_zero)]
 #![allow(dead_code, unused, clippy::len_without_is_empty)]
 
+extern crate core;
+use core::ops::Deref;
+
 pub struct One;
 struct Wither;
 
@@ -56,6 +59,26 @@ fn is_empty(&self) -> bool {
     }
 }
 
+struct DerefToDerefToString;
+
+impl Deref for DerefToDerefToString {
+    type Target = DerefToString;
+
+    fn deref(&self) -> &Self::Target {
+        &DerefToString {}
+    }
+}
+
+struct DerefToString;
+
+impl Deref for DerefToString {
+    type Target = str;
+
+    fn deref(&self) -> &Self::Target {
+        "Hello, world!"
+    }
+}
+
 fn main() {
     let x = [1, 2];
     if x.len() == 0 {
@@ -64,6 +87,23 @@ fn main() {
 
     if "".len() == 0 {}
 
+    let s = "Hello, world!";
+    let s1 = &s;
+    let s2 = &s1;
+    let s3 = &s2;
+    let s4 = &s3;
+    let s5 = &s4;
+    let s6 = &s5;
+    println!("{}", *s1 == "");
+    println!("{}", **s2 == "");
+    println!("{}", ***s3 == "");
+    println!("{}", ****s4 == "");
+    println!("{}", *****s5 == "");
+    println!("{}", ******(s6) == "");
+
+    let d2s = DerefToDerefToString {};
+    println!("{}", &**d2s == "");
+
     let y = One;
     if y.len() == 0 {
         // No error; `One` does not have `.is_empty()`.
index 6c71f1beeac67c27a89916538cbdfcc2af70d896..b6f13780253c2e526533179cc5602c0ff557f68a 100644 (file)
@@ -1,5 +1,5 @@
 error: length comparison to zero
-  --> $DIR/len_zero.rs:61:8
+  --> $DIR/len_zero.rs:84:8
    |
 LL |     if x.len() == 0 {
    |        ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `x.is_empty()`
@@ -7,82 +7,126 @@ LL |     if x.len() == 0 {
    = note: `-D clippy::len-zero` implied by `-D warnings`
 
 error: length comparison to zero
-  --> $DIR/len_zero.rs:65:8
+  --> $DIR/len_zero.rs:88:8
    |
 LL |     if "".len() == 0 {}
    |        ^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `"".is_empty()`
 
+error: comparison to empty slice
+  --> $DIR/len_zero.rs:97:20
+   |
+LL |     println!("{}", *s1 == "");
+   |                    ^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s1.is_empty()`
+   |
+   = note: `-D clippy::comparison-to-empty` implied by `-D warnings`
+
+error: comparison to empty slice
+  --> $DIR/len_zero.rs:98:20
+   |
+LL |     println!("{}", **s2 == "");
+   |                    ^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s2.is_empty()`
+
+error: comparison to empty slice
+  --> $DIR/len_zero.rs:99:20
+   |
+LL |     println!("{}", ***s3 == "");
+   |                    ^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s3.is_empty()`
+
+error: comparison to empty slice
+  --> $DIR/len_zero.rs:100:20
+   |
+LL |     println!("{}", ****s4 == "");
+   |                    ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s4.is_empty()`
+
+error: comparison to empty slice
+  --> $DIR/len_zero.rs:101:20
+   |
+LL |     println!("{}", *****s5 == "");
+   |                    ^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s5.is_empty()`
+
+error: comparison to empty slice
+  --> $DIR/len_zero.rs:102:20
+   |
+LL |     println!("{}", ******(s6) == "");
+   |                    ^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(s6).is_empty()`
+
+error: comparison to empty slice
+  --> $DIR/len_zero.rs:105:20
+   |
+LL |     println!("{}", &**d2s == "");
+   |                    ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(**d2s).is_empty()`
+
 error: length comparison to zero
-  --> $DIR/len_zero.rs:80:8
+  --> $DIR/len_zero.rs:120:8
    |
 LL |     if has_is_empty.len() == 0 {
    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> $DIR/len_zero.rs:83:8
+  --> $DIR/len_zero.rs:123:8
    |
 LL |     if has_is_empty.len() != 0 {
    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> $DIR/len_zero.rs:86:8
+  --> $DIR/len_zero.rs:126:8
    |
 LL |     if has_is_empty.len() > 0 {
    |        ^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to one
-  --> $DIR/len_zero.rs:89:8
+  --> $DIR/len_zero.rs:129:8
    |
 LL |     if has_is_empty.len() < 1 {
    |        ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 
 error: length comparison to one
-  --> $DIR/len_zero.rs:92:8
+  --> $DIR/len_zero.rs:132:8
    |
 LL |     if has_is_empty.len() >= 1 {
    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> $DIR/len_zero.rs:103:8
+  --> $DIR/len_zero.rs:143:8
    |
 LL |     if 0 == has_is_empty.len() {
    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> $DIR/len_zero.rs:106:8
+  --> $DIR/len_zero.rs:146:8
    |
 LL |     if 0 != has_is_empty.len() {
    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> $DIR/len_zero.rs:109:8
+  --> $DIR/len_zero.rs:149:8
    |
 LL |     if 0 < has_is_empty.len() {
    |        ^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to one
-  --> $DIR/len_zero.rs:112:8
+  --> $DIR/len_zero.rs:152:8
    |
 LL |     if 1 <= has_is_empty.len() {
    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to one
-  --> $DIR/len_zero.rs:115:8
+  --> $DIR/len_zero.rs:155:8
    |
 LL |     if 1 > has_is_empty.len() {
    |        ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> $DIR/len_zero.rs:129:8
+  --> $DIR/len_zero.rs:169:8
    |
 LL |     if with_is_empty.len() == 0 {
    |        ^^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `with_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> $DIR/len_zero.rs:142:8
+  --> $DIR/len_zero.rs:182:8
    |
 LL |     if b.len() != 0 {}
    |        ^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!b.is_empty()`
 
-error: aborting due to 14 previous errors
+error: aborting due to 21 previous errors
 
index c9a819ba535449a1b8d90b2324204f74b318a585..638320dd6eec439a76ea745736dd2b7fcfd1672f 100644 (file)
@@ -62,6 +62,11 @@ fn main() {
         panic!("panic5");
     }
     assert!(!a.is_empty(), "with expansion {}", one!());
+    if a.is_empty() {
+        let _ = 0;
+    } else if a.len() == 1 {
+        panic!("panic6");
+    }
 }
 
 fn issue7730(a: u8) {
index 2f62de51cadcd948a98c0b75668aa2f13c6b4a92..8c7e919bf62a10d52bc6a343454b438f89c8857b 100644 (file)
@@ -50,6 +50,11 @@ fn main() {
     assert!(!(b.is_empty() || a.is_empty()), "panic4");
     assert!(!(a.is_empty() || !b.is_empty()), "panic5");
     assert!(!a.is_empty(), "with expansion {}", one!());
+    if a.is_empty() {
+        let _ = 0;
+    } else if a.len() == 1 {
+        panic!("panic6");
+    }
 }
 
 fn issue7730(a: u8) {
index 237638ee1344c60274bb31c1accbcf7f7456cee3..3555ac29243a1cb0d819a368d8bb22bf02aea2de 100644 (file)
@@ -65,7 +65,7 @@ LL | |     }
    | |_____^ help: try instead: `assert!(!a.is_empty(), "with expansion {}", one!());`
 
 error: only a `panic!` in `if`-then statement
-  --> $DIR/manual_assert.rs:73:5
+  --> $DIR/manual_assert.rs:78:5
    |
 LL | /     if a > 2 {
 LL | |         // comment
index 6a4cc2468d4193815b6b43299db873b95d8fb33d..f037c5b8405c721cc6755b1874cf5d47f229206b 100644 (file)
@@ -66,6 +66,11 @@ fn main() {
     if a.is_empty() {
         panic!("with expansion {}", one!())
     }
+    if a.is_empty() {
+        let _ = 0;
+    } else if a.len() == 1 {
+        panic!("panic6");
+    }
 }
 
 fn issue7730(a: u8) {
index 231ba83b1426130a3b6482d8e9cb938aacfced4d..5b2b44c2fdb2bbaa6c960d482f36e051616267fe 100644 (file)
@@ -15,6 +15,19 @@ fn main() {
     assert!('x'.is_ascii_alphabetic());
 
     assert!(matches!('x', 'A'..='Z' | 'a'..='z' | '_'));
+
+    b'0'.is_ascii_digit();
+    b'a'.is_ascii_lowercase();
+    b'A'.is_ascii_uppercase();
+
+    '0'.is_ascii_digit();
+    'a'.is_ascii_lowercase();
+    'A'.is_ascii_uppercase();
+
+    let cool_letter = &'g';
+    cool_letter.is_ascii_digit();
+    cool_letter.is_ascii_lowercase();
+    cool_letter.is_ascii_uppercase();
 }
 
 #[clippy::msrv = "1.23"]
index 39ee6151c56f08ff53b77377e9eb916b437d00a6..c9433f33a1b6f3891e47a391ad150a784c2bc0db 100644 (file)
@@ -15,6 +15,19 @@ fn main() {
     assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
 
     assert!(matches!('x', 'A'..='Z' | 'a'..='z' | '_'));
+
+    (b'0'..=b'9').contains(&b'0');
+    (b'a'..=b'z').contains(&b'a');
+    (b'A'..=b'Z').contains(&b'A');
+
+    ('0'..='9').contains(&'0');
+    ('a'..='z').contains(&'a');
+    ('A'..='Z').contains(&'A');
+
+    let cool_letter = &'g';
+    ('0'..='9').contains(cool_letter);
+    ('a'..='z').contains(cool_letter);
+    ('A'..='Z').contains(cool_letter);
 }
 
 #[clippy::msrv = "1.23"]
index 397cbe05c822ad7fba97b5f46d02fd569e2882fe..ee60188506d6fc08182a897d47a9d3c7ca290aa4 100644 (file)
@@ -43,28 +43,82 @@ LL |     assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_alphabetic()`
 
 error: manual check for common ascii range
-  --> $DIR/manual_is_ascii_check.rs:29:13
+  --> $DIR/manual_is_ascii_check.rs:19:5
+   |
+LL |     (b'0'..=b'9').contains(&b'0');
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'0'.is_ascii_digit()`
+
+error: manual check for common ascii range
+  --> $DIR/manual_is_ascii_check.rs:20:5
+   |
+LL |     (b'a'..=b'z').contains(&b'a');
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'a'.is_ascii_lowercase()`
+
+error: manual check for common ascii range
+  --> $DIR/manual_is_ascii_check.rs:21:5
+   |
+LL |     (b'A'..=b'Z').contains(&b'A');
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'A'.is_ascii_uppercase()`
+
+error: manual check for common ascii range
+  --> $DIR/manual_is_ascii_check.rs:23:5
+   |
+LL |     ('0'..='9').contains(&'0');
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'0'.is_ascii_digit()`
+
+error: manual check for common ascii range
+  --> $DIR/manual_is_ascii_check.rs:24:5
+   |
+LL |     ('a'..='z').contains(&'a');
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'a'.is_ascii_lowercase()`
+
+error: manual check for common ascii range
+  --> $DIR/manual_is_ascii_check.rs:25:5
+   |
+LL |     ('A'..='Z').contains(&'A');
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'A'.is_ascii_uppercase()`
+
+error: manual check for common ascii range
+  --> $DIR/manual_is_ascii_check.rs:28:5
+   |
+LL |     ('0'..='9').contains(cool_letter);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cool_letter.is_ascii_digit()`
+
+error: manual check for common ascii range
+  --> $DIR/manual_is_ascii_check.rs:29:5
+   |
+LL |     ('a'..='z').contains(cool_letter);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cool_letter.is_ascii_lowercase()`
+
+error: manual check for common ascii range
+  --> $DIR/manual_is_ascii_check.rs:30:5
+   |
+LL |     ('A'..='Z').contains(cool_letter);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cool_letter.is_ascii_uppercase()`
+
+error: manual check for common ascii range
+  --> $DIR/manual_is_ascii_check.rs:42:13
    |
 LL |     assert!(matches!(b'1', b'0'..=b'9'));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'1'.is_ascii_digit()`
 
 error: manual check for common ascii range
-  --> $DIR/manual_is_ascii_check.rs:30:13
+  --> $DIR/manual_is_ascii_check.rs:43:13
    |
 LL |     assert!(matches!('X', 'A'..='Z'));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'X'.is_ascii_uppercase()`
 
 error: manual check for common ascii range
-  --> $DIR/manual_is_ascii_check.rs:31:13
+  --> $DIR/manual_is_ascii_check.rs:44:13
    |
 LL |     assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_alphabetic()`
 
 error: manual check for common ascii range
-  --> $DIR/manual_is_ascii_check.rs:41:23
+  --> $DIR/manual_is_ascii_check.rs:54:23
    |
 LL |     const FOO: bool = matches!('x', '0'..='9');
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_digit()`
 
-error: aborting due to 11 previous errors
+error: aborting due to 20 previous errors
 
index 93c86ca24fea3a079c80c8ae7bb32204b29f6be3..28caed9d79df244f074eab27b108794139ca3ac2 100644 (file)
@@ -64,6 +64,13 @@ fn fire() {
         Ok(v) => v,
         Err(()) => return,
     };
+
+    let f = Variant::Bar(1);
+
+    let _value = match f {
+        Variant::Bar(_) | Variant::Baz(_) => (),
+        _ => return,
+    };
 }
 
 fn not_fire() {
index 38be5ac54547368b7fe98d336a1da5acc2e85db7..cd5e9a9ac39c0770fcd41351097e381cfe0f6ec4 100644 (file)
@@ -25,7 +25,7 @@ LL | /         let v = match h() {
 LL | |             (Some(_), Some(_)) | (None, None) => continue,
 LL | |             (Some(v), None) | (None, Some(v)) => v,
 LL | |         };
-   | |__________^ help: consider writing: `let (Some(v), None) | (None, Some(v)) = h() else { continue };`
+   | |__________^ help: consider writing: `let ((Some(v), None) | (None, Some(v))) = h() else { continue };`
 
 error: this could be rewritten as `let...else`
   --> $DIR/manual_let_else_match.rs:49:9
@@ -34,7 +34,7 @@ LL | /         let v = match build_enum() {
 LL | |             _ => continue,
 LL | |             Variant::Bar(v) | Variant::Baz(v) => v,
 LL | |         };
-   | |__________^ help: consider writing: `let Variant::Bar(v) | Variant::Baz(v) = build_enum() else { continue };`
+   | |__________^ help: consider writing: `let (Variant::Bar(v) | Variant::Baz(v)) = build_enum() else { continue };`
 
 error: this could be rewritten as `let...else`
   --> $DIR/manual_let_else_match.rs:57:5
@@ -54,5 +54,14 @@ LL | |         Err(()) => return,
 LL | |     };
    | |______^ help: consider writing: `let Ok(v) = f().map_err(|_| ()) else { return };`
 
-error: aborting due to 6 previous errors
+error: this could be rewritten as `let...else`
+  --> $DIR/manual_let_else_match.rs:70:5
+   |
+LL | /     let _value = match f {
+LL | |         Variant::Bar(_) | Variant::Baz(_) => (),
+LL | |         _ => return,
+LL | |     };
+   | |______^ help: consider writing: `let (Variant::Bar(_) | Variant::Baz(_)) = f else { return };`
+
+error: aborting due to 7 previous errors
 
index 1bd75c806bc94378acadd7f86e5bc533de7548e1..f11330a8916d4adf2ba241ef4495ef772d8fcdf0 100644 (file)
@@ -2,7 +2,7 @@
 // edition:2018
 
 #![warn(clippy::needless_parens_on_range_literals)]
-#![allow(clippy::almost_complete_letter_range)]
+#![allow(clippy::almost_complete_range)]
 
 fn main() {
     let _ = 'a'..='z';
index 7abb8a1adc1bcc4f0178599adc3391c748f73f5b..671c0009e23b7d5b60d8f70f3b6abd5a94dc79cf 100644 (file)
@@ -2,7 +2,7 @@
 // edition:2018
 
 #![warn(clippy::needless_parens_on_range_literals)]
-#![allow(clippy::almost_complete_letter_range)]
+#![allow(clippy::almost_complete_range)]
 
 fn main() {
     let _ = ('a')..=('z');
index f69982d63a898d17ba3b9f6ff417c42ea8442bd8..beec42f08bb05666df617799cc1b4068abfcdb75 100644 (file)
@@ -1,3 +1,4 @@
+#![feature(type_alias_impl_trait)]
 #![warn(clippy::new_ret_no_self)]
 #![allow(dead_code)]
 
@@ -400,3 +401,25 @@ fn new<'b: 'a>(s: &'b str) -> impl Into<RetImplTraitSelfAdt<'b>> {
         }
     }
 }
+
+mod issue10041 {
+    struct Bomb;
+
+    impl Bomb {
+        // Hidden <Rhs = Self> default generic paramter.
+        pub fn new() -> impl PartialOrd {
+            0i32
+        }
+    }
+
+    // TAIT with self-referencing bounds
+    type X = impl std::ops::Add<Output = X>;
+
+    struct Bomb2;
+
+    impl Bomb2 {
+        pub fn new() -> X {
+            0i32
+        }
+    }
+}
index bc13be47927b1c3fa37a75795a316f5c521319ac..2eaebfb5cac50041df6bc18f6c2a78bb79017691 100644 (file)
@@ -1,5 +1,5 @@
 error: methods called `new` usually return `Self`
-  --> $DIR/new_ret_no_self.rs:49:5
+  --> $DIR/new_ret_no_self.rs:50:5
    |
 LL | /     pub fn new(_: String) -> impl R<Item = u32> {
 LL | |         S3
@@ -9,7 +9,7 @@ LL | |     }
    = note: `-D clippy::new-ret-no-self` implied by `-D warnings`
 
 error: methods called `new` usually return `Self`
-  --> $DIR/new_ret_no_self.rs:81:5
+  --> $DIR/new_ret_no_self.rs:82:5
    |
 LL | /     pub fn new() -> u32 {
 LL | |         unimplemented!();
@@ -17,7 +17,7 @@ LL | |     }
    | |_____^
 
 error: methods called `new` usually return `Self`
-  --> $DIR/new_ret_no_self.rs:90:5
+  --> $DIR/new_ret_no_self.rs:91:5
    |
 LL | /     pub fn new(_: String) -> u32 {
 LL | |         unimplemented!();
@@ -25,7 +25,7 @@ LL | |     }
    | |_____^
 
 error: methods called `new` usually return `Self`
-  --> $DIR/new_ret_no_self.rs:126:5
+  --> $DIR/new_ret_no_self.rs:127:5
    |
 LL | /     pub fn new() -> (u32, u32) {
 LL | |         unimplemented!();
@@ -33,7 +33,7 @@ LL | |     }
    | |_____^
 
 error: methods called `new` usually return `Self`
-  --> $DIR/new_ret_no_self.rs:153:5
+  --> $DIR/new_ret_no_self.rs:154:5
    |
 LL | /     pub fn new() -> *mut V {
 LL | |         unimplemented!();
@@ -41,7 +41,7 @@ LL | |     }
    | |_____^
 
 error: methods called `new` usually return `Self`
-  --> $DIR/new_ret_no_self.rs:171:5
+  --> $DIR/new_ret_no_self.rs:172:5
    |
 LL | /     pub fn new() -> Option<u32> {
 LL | |         unimplemented!();
@@ -49,19 +49,19 @@ LL | |     }
    | |_____^
 
 error: methods called `new` usually return `Self`
-  --> $DIR/new_ret_no_self.rs:224:9
+  --> $DIR/new_ret_no_self.rs:225:9
    |
 LL |         fn new() -> String;
    |         ^^^^^^^^^^^^^^^^^^^
 
 error: methods called `new` usually return `Self`
-  --> $DIR/new_ret_no_self.rs:236:9
+  --> $DIR/new_ret_no_self.rs:237:9
    |
 LL |         fn new(_: String) -> String;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: methods called `new` usually return `Self`
-  --> $DIR/new_ret_no_self.rs:271:9
+  --> $DIR/new_ret_no_self.rs:272:9
    |
 LL | /         fn new() -> (u32, u32) {
 LL | |             unimplemented!();
@@ -69,7 +69,7 @@ LL | |         }
    | |_________^
 
 error: methods called `new` usually return `Self`
-  --> $DIR/new_ret_no_self.rs:298:9
+  --> $DIR/new_ret_no_self.rs:299:9
    |
 LL | /         fn new() -> *mut V {
 LL | |             unimplemented!();
@@ -77,7 +77,7 @@ LL | |         }
    | |_________^
 
 error: methods called `new` usually return `Self`
-  --> $DIR/new_ret_no_self.rs:368:9
+  --> $DIR/new_ret_no_self.rs:369:9
    |
 LL | /         fn new(t: T) -> impl Into<i32> {
 LL | |             1
@@ -85,12 +85,28 @@ LL | |         }
    | |_________^
 
 error: methods called `new` usually return `Self`
-  --> $DIR/new_ret_no_self.rs:389:9
+  --> $DIR/new_ret_no_self.rs:390:9
    |
 LL | /         fn new(t: T) -> impl Trait2<(), i32> {
 LL | |             unimplemented!()
 LL | |         }
    | |_________^
 
-error: aborting due to 12 previous errors
+error: methods called `new` usually return `Self`
+  --> $DIR/new_ret_no_self.rs:410:9
+   |
+LL | /         pub fn new() -> impl PartialOrd {
+LL | |             0i32
+LL | |         }
+   | |_________^
+
+error: methods called `new` usually return `Self`
+  --> $DIR/new_ret_no_self.rs:421:9
+   |
+LL | /         pub fn new() -> X {
+LL | |             0i32
+LL | |         }
+   | |_________^
+
+error: aborting due to 14 previous errors
 
index 4c5846fe837eaa8a68ed10ad585271923f0f6588..bca777a890c3b249c2f0ae7bbf61c099a2d0705e 100644 (file)
@@ -39,8 +39,14 @@ static STATIC_VAR_TUPLE: &(u8, u8) = &(1, 2); // ERROR Consider removing 'static
 
 static STATIC_VAR_ARRAY: &[u8; 1] = b"T"; // ERROR Consider removing 'static.
 
+static mut STATIC_MUT_SLICE: &mut [u32] = &mut [0];
+
 fn main() {
     let false_positive: &'static str = "test";
+
+    unsafe {
+        STATIC_MUT_SLICE[0] = 0;
+    }
 }
 
 trait Bar {
index 64a66be1a83c753ff8a786167759fd4f04ea52ef..afe7644816d2e4f0420d04d1547c3080f45d984b 100644 (file)
 
 static STATIC_VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR Consider removing 'static.
 
+static mut STATIC_MUT_SLICE: &'static mut [u32] = &mut [0];
+
 fn main() {
     let false_positive: &'static str = "test";
+
+    unsafe {
+        STATIC_MUT_SLICE[0] = 0;
+    }
 }
 
 trait Bar {
index 0938ebf783ff16888852e0be386dc22c86f1c254..b2cbd2d9d01b0350e7f31710c9fdec05f2cfc6ce 100644 (file)
@@ -97,10 +97,16 @@ LL | static STATIC_VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR Consider removin
    |                          -^^^^^^^-------- help: consider removing `'static`: `&[u8; 1]`
 
 error: statics have by default a `'static` lifetime
-  --> $DIR/redundant_static_lifetimes.rs:65:16
+  --> $DIR/redundant_static_lifetimes.rs:42:31
+   |
+LL | static mut STATIC_MUT_SLICE: &'static mut [u32] = &mut [0];
+   |                              -^^^^^^^---------- help: consider removing `'static`: `&mut [u32]`
+
+error: statics have by default a `'static` lifetime
+  --> $DIR/redundant_static_lifetimes.rs:71:16
    |
 LL |     static V: &'static u8 = &17;
    |               -^^^^^^^--- help: consider removing `'static`: `&u8`
 
-error: aborting due to 17 previous errors
+error: aborting due to 18 previous errors
 
index 689928f0479468fb8c0305b11d1299e01fd4f4ca..2f76b57529607a14ed3165dea40c3ddf0dd9975d 100644 (file)
@@ -4,6 +4,7 @@
 
 // run-rustfix
 
+#![allow(clippy::almost_complete_range)]
 #![allow(clippy::disallowed_names)]
 #![allow(clippy::blocks_in_if_conditions)]
 #![allow(clippy::box_collection)]
@@ -37,6 +38,7 @@
 #![allow(temporary_cstring_as_ptr)]
 #![allow(unknown_lints)]
 #![allow(unused_labels)]
+#![warn(clippy::almost_complete_range)]
 #![warn(clippy::disallowed_names)]
 #![warn(clippy::blocks_in_if_conditions)]
 #![warn(clippy::blocks_in_if_conditions)]
index b74aa650ffd475946adc1f595d0e2d21b4d0fa15..699c0ff464e9fb247989fd0b559c8a35576b63f4 100644 (file)
@@ -4,6 +4,7 @@
 
 // run-rustfix
 
+#![allow(clippy::almost_complete_range)]
 #![allow(clippy::disallowed_names)]
 #![allow(clippy::blocks_in_if_conditions)]
 #![allow(clippy::box_collection)]
@@ -37,6 +38,7 @@
 #![allow(temporary_cstring_as_ptr)]
 #![allow(unknown_lints)]
 #![allow(unused_labels)]
+#![warn(clippy::almost_complete_letter_range)]
 #![warn(clippy::blacklisted_name)]
 #![warn(clippy::block_in_if_condition_expr)]
 #![warn(clippy::block_in_if_condition_stmt)]
index 622a32c5908aeaa3689041a42a6fa6e6f8920be7..9af58dc75a68f41daff7f88a050856295b19ec29 100644 (file)
+error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range`
+  --> $DIR/rename.rs:41:9
+   |
+LL | #![warn(clippy::almost_complete_letter_range)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range`
+   |
+   = note: `-D renamed-and-removed-lints` implied by `-D warnings`
+
 error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names`
-  --> $DIR/rename.rs:40:9
+  --> $DIR/rename.rs:42: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:41:9
+  --> $DIR/rename.rs:43:9
    |
 LL | #![warn(clippy::block_in_if_condition_expr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
 
 error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions`
-  --> $DIR/rename.rs:42:9
+  --> $DIR/rename.rs:44: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:43:9
+  --> $DIR/rename.rs:45: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:44:9
+  --> $DIR/rename.rs:46: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:45:9
+  --> $DIR/rename.rs:47: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:46:9
+  --> $DIR/rename.rs:48: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:47:9
+  --> $DIR/rename.rs:49: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:48:9
+  --> $DIR/rename.rs:50:9
    |
 LL | #![warn(clippy::eval_order_dependence)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
 
 error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
-  --> $DIR/rename.rs:49:9
+  --> $DIR/rename.rs:51: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:50:9
+  --> $DIR/rename.rs:52: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
+  --> $DIR/rename.rs:53: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:52:9
+  --> $DIR/rename.rs:54: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:53:9
+  --> $DIR/rename.rs:55: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:54:9
+  --> $DIR/rename.rs:56: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:55:9
+  --> $DIR/rename.rs:57: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:56:9
+  --> $DIR/rename.rs:58: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:57:9
+  --> $DIR/rename.rs:59: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:58:9
+  --> $DIR/rename.rs:60: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:59:9
+  --> $DIR/rename.rs:61: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:60:9
+  --> $DIR/rename.rs:62: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:61:9
+  --> $DIR/rename.rs:63: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:62:9
+  --> $DIR/rename.rs:64: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:63:9
+  --> $DIR/rename.rs:65: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:64:9
+  --> $DIR/rename.rs:66: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:65:9
+  --> $DIR/rename.rs:67: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:66:9
+  --> $DIR/rename.rs:68:9
    |
 LL | #![warn(clippy::drop_bounds)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
 
 error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:67:9
+  --> $DIR/rename.rs:69:9
    |
 LL | #![warn(clippy::for_loop_over_option)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:68:9
+  --> $DIR/rename.rs:70:9
    |
 LL | #![warn(clippy::for_loop_over_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:69:9
+  --> $DIR/rename.rs:71:9
    |
 LL | #![warn(clippy::for_loops_over_fallibles)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
-  --> $DIR/rename.rs:70:9
+  --> $DIR/rename.rs:72: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:71:9
+  --> $DIR/rename.rs:73: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:72:9
+  --> $DIR/rename.rs:74:9
    |
 LL | #![warn(clippy::invalid_ref)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
 
 error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop`
-  --> $DIR/rename.rs:73:9
+  --> $DIR/rename.rs:75:9
    |
 LL | #![warn(clippy::let_underscore_drop)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop`
 
 error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
-  --> $DIR/rename.rs:74:9
+  --> $DIR/rename.rs:76: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:75:9
+  --> $DIR/rename.rs:77:9
    |
 LL | #![warn(clippy::panic_params)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
 
 error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally`
-  --> $DIR/rename.rs:76:9
+  --> $DIR/rename.rs:78:9
    |
 LL | #![warn(clippy::positional_named_format_parameters)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
 
 error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
-  --> $DIR/rename.rs:77:9
+  --> $DIR/rename.rs:79: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:78:9
+  --> $DIR/rename.rs:80: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:79:9
+  --> $DIR/rename.rs:81:9
    |
 LL | #![warn(clippy::unused_label)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
 
-error: aborting due to 40 previous errors
+error: aborting due to 41 previous errors
 
index 9d0d1124c460ed45b1b5894bd3878b18d15def72..713cff604a1d7d6028c367f5efcf2e4c2de552fb 100644 (file)
@@ -70,6 +70,12 @@ fn seek_to_end<T: Seek>(t: &mut T) {
     t.seek(SeekFrom::End(0));
 }
 
+// This should NOT trigger clippy warning because
+// expr is used here
+fn seek_to_start_in_let<T: Seek>(t: &mut T) {
+    let a = t.seek(SeekFrom::Start(0)).unwrap();
+}
+
 fn main() {
     let mut f = OpenOptions::new()
         .write(true)
index c5bc57cc3a74ce617a96b4dd401a58cca895647b..467003a1a66f684141d3e8be6bc500d3acb99d66 100644 (file)
@@ -70,6 +70,12 @@ fn seek_to_end<T: Seek>(t: &mut T) {
     t.seek(SeekFrom::End(0));
 }
 
+// This should NOT trigger clippy warning because
+// expr is used here
+fn seek_to_start_in_let<T: Seek>(t: &mut T) {
+    let a = t.seek(SeekFrom::Start(0)).unwrap();
+}
+
 fn main() {
     let mut f = OpenOptions::new()
         .write(true)
index 6cce025359fe2918bce42ea6bdbef601d8c74948..342ec00fe7295ad8ec3afd061f1af4dbbc48110c 100644 (file)
@@ -13,7 +13,7 @@ LL |     t.seek(SeekFrom::Start(0));
    |       ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `rewind()`
 
 error: used `seek` to go to the start of the stream
-  --> $DIR/seek_to_start_instead_of_rewind.rs:128:7
+  --> $DIR/seek_to_start_instead_of_rewind.rs:134:7
    |
 LL |     f.seek(SeekFrom::Start(0));
    |       ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `rewind()`
diff --git a/src/tools/clippy/tests/ui/semicolon_inside_block.fixed b/src/tools/clippy/tests/ui/semicolon_inside_block.fixed
new file mode 100644 (file)
index 0000000..42e97e1
--- /dev/null
@@ -0,0 +1,85 @@
+// run-rustfix
+#![allow(
+    unused,
+    clippy::unused_unit,
+    clippy::unnecessary_operation,
+    clippy::no_effect,
+    clippy::single_element_loop
+)]
+#![warn(clippy::semicolon_inside_block)]
+
+macro_rules! m {
+    (()) => {
+        ()
+    };
+    (0) => {{
+        0
+    };};
+    (1) => {{
+        1;
+    }};
+    (2) => {{
+        2;
+    }};
+}
+
+fn unit_fn_block() {
+    ()
+}
+
+#[rustfmt::skip]
+fn main() {
+    { unit_fn_block() }
+    unsafe { unit_fn_block() }
+
+    {
+        unit_fn_block()
+    }
+
+    { unit_fn_block(); }
+    unsafe { unit_fn_block(); }
+
+    { unit_fn_block(); }
+    unsafe { unit_fn_block(); }
+
+    { unit_fn_block(); };
+    unsafe { unit_fn_block(); };
+
+    {
+        unit_fn_block();
+        unit_fn_block();
+    }
+    {
+        unit_fn_block();
+        unit_fn_block();
+    }
+    {
+        unit_fn_block();
+        unit_fn_block();
+    };
+
+    { m!(()); }
+    { m!(()); }
+    { m!(()); };
+    m!(0);
+    m!(1);
+    m!(2);
+
+    for _ in [()] {
+        unit_fn_block();
+    }
+    for _ in [()] {
+        unit_fn_block()
+    }
+
+    let _d = || {
+        unit_fn_block();
+    };
+    let _d = || {
+        unit_fn_block()
+    };
+
+    { unit_fn_block(); };
+
+    unit_fn_block()
+}
diff --git a/src/tools/clippy/tests/ui/semicolon_inside_block.rs b/src/tools/clippy/tests/ui/semicolon_inside_block.rs
new file mode 100644 (file)
index 0000000..f40848f
--- /dev/null
@@ -0,0 +1,85 @@
+// run-rustfix
+#![allow(
+    unused,
+    clippy::unused_unit,
+    clippy::unnecessary_operation,
+    clippy::no_effect,
+    clippy::single_element_loop
+)]
+#![warn(clippy::semicolon_inside_block)]
+
+macro_rules! m {
+    (()) => {
+        ()
+    };
+    (0) => {{
+        0
+    };};
+    (1) => {{
+        1;
+    }};
+    (2) => {{
+        2;
+    }};
+}
+
+fn unit_fn_block() {
+    ()
+}
+
+#[rustfmt::skip]
+fn main() {
+    { unit_fn_block() }
+    unsafe { unit_fn_block() }
+
+    {
+        unit_fn_block()
+    }
+
+    { unit_fn_block() };
+    unsafe { unit_fn_block() };
+
+    { unit_fn_block(); }
+    unsafe { unit_fn_block(); }
+
+    { unit_fn_block(); };
+    unsafe { unit_fn_block(); };
+
+    {
+        unit_fn_block();
+        unit_fn_block()
+    };
+    {
+        unit_fn_block();
+        unit_fn_block();
+    }
+    {
+        unit_fn_block();
+        unit_fn_block();
+    };
+
+    { m!(()) };
+    { m!(()); }
+    { m!(()); };
+    m!(0);
+    m!(1);
+    m!(2);
+
+    for _ in [()] {
+        unit_fn_block();
+    }
+    for _ in [()] {
+        unit_fn_block()
+    }
+
+    let _d = || {
+        unit_fn_block();
+    };
+    let _d = || {
+        unit_fn_block()
+    };
+
+    { unit_fn_block(); };
+
+    unit_fn_block()
+}
diff --git a/src/tools/clippy/tests/ui/semicolon_inside_block.stderr b/src/tools/clippy/tests/ui/semicolon_inside_block.stderr
new file mode 100644 (file)
index 0000000..48d3690
--- /dev/null
@@ -0,0 +1,54 @@
+error: consider moving the `;` inside the block for consistent formatting
+  --> $DIR/semicolon_inside_block.rs:39:5
+   |
+LL |     { unit_fn_block() };
+   |     ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::semicolon-inside-block` implied by `-D warnings`
+help: put the `;` here
+   |
+LL -     { unit_fn_block() };
+LL +     { unit_fn_block(); }
+   |
+
+error: consider moving the `;` inside the block for consistent formatting
+  --> $DIR/semicolon_inside_block.rs:40:5
+   |
+LL |     unsafe { unit_fn_block() };
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: put the `;` here
+   |
+LL -     unsafe { unit_fn_block() };
+LL +     unsafe { unit_fn_block(); }
+   |
+
+error: consider moving the `;` inside the block for consistent formatting
+  --> $DIR/semicolon_inside_block.rs:48:5
+   |
+LL | /     {
+LL | |         unit_fn_block();
+LL | |         unit_fn_block()
+LL | |     };
+   | |______^
+   |
+help: put the `;` here
+   |
+LL ~         unit_fn_block();
+LL ~     }
+   |
+
+error: consider moving the `;` inside the block for consistent formatting
+  --> $DIR/semicolon_inside_block.rs:61:5
+   |
+LL |     { m!(()) };
+   |     ^^^^^^^^^^^
+   |
+help: put the `;` here
+   |
+LL -     { m!(()) };
+LL +     { m!(()); }
+   |
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/semicolon_outside_block.fixed b/src/tools/clippy/tests/ui/semicolon_outside_block.fixed
new file mode 100644 (file)
index 0000000..091eaa7
--- /dev/null
@@ -0,0 +1,85 @@
+// run-rustfix
+#![allow(
+    unused,
+    clippy::unused_unit,
+    clippy::unnecessary_operation,
+    clippy::no_effect,
+    clippy::single_element_loop
+)]
+#![warn(clippy::semicolon_outside_block)]
+
+macro_rules! m {
+    (()) => {
+        ()
+    };
+    (0) => {{
+        0
+    };};
+    (1) => {{
+        1;
+    }};
+    (2) => {{
+        2;
+    }};
+}
+
+fn unit_fn_block() {
+    ()
+}
+
+#[rustfmt::skip]
+fn main() {
+    { unit_fn_block() }
+    unsafe { unit_fn_block() }
+
+    {
+        unit_fn_block()
+    }
+
+    { unit_fn_block() };
+    unsafe { unit_fn_block() };
+
+    { unit_fn_block() };
+    unsafe { unit_fn_block() };
+
+    { unit_fn_block(); };
+    unsafe { unit_fn_block(); };
+
+    {
+        unit_fn_block();
+        unit_fn_block()
+    };
+    {
+        unit_fn_block();
+        unit_fn_block()
+    };
+    {
+        unit_fn_block();
+        unit_fn_block();
+    };
+
+    { m!(()) };
+    { m!(()) };
+    { m!(()); };
+    m!(0);
+    m!(1);
+    m!(2);
+
+    for _ in [()] {
+        unit_fn_block();
+    }
+    for _ in [()] {
+        unit_fn_block()
+    }
+
+    let _d = || {
+        unit_fn_block();
+    };
+    let _d = || {
+        unit_fn_block()
+    };
+
+    { unit_fn_block(); };
+
+    unit_fn_block()
+}
diff --git a/src/tools/clippy/tests/ui/semicolon_outside_block.rs b/src/tools/clippy/tests/ui/semicolon_outside_block.rs
new file mode 100644 (file)
index 0000000..7ce4643
--- /dev/null
@@ -0,0 +1,85 @@
+// run-rustfix
+#![allow(
+    unused,
+    clippy::unused_unit,
+    clippy::unnecessary_operation,
+    clippy::no_effect,
+    clippy::single_element_loop
+)]
+#![warn(clippy::semicolon_outside_block)]
+
+macro_rules! m {
+    (()) => {
+        ()
+    };
+    (0) => {{
+        0
+    };};
+    (1) => {{
+        1;
+    }};
+    (2) => {{
+        2;
+    }};
+}
+
+fn unit_fn_block() {
+    ()
+}
+
+#[rustfmt::skip]
+fn main() {
+    { unit_fn_block() }
+    unsafe { unit_fn_block() }
+
+    {
+        unit_fn_block()
+    }
+
+    { unit_fn_block() };
+    unsafe { unit_fn_block() };
+
+    { unit_fn_block(); }
+    unsafe { unit_fn_block(); }
+
+    { unit_fn_block(); };
+    unsafe { unit_fn_block(); };
+
+    {
+        unit_fn_block();
+        unit_fn_block()
+    };
+    {
+        unit_fn_block();
+        unit_fn_block();
+    }
+    {
+        unit_fn_block();
+        unit_fn_block();
+    };
+
+    { m!(()) };
+    { m!(()); }
+    { m!(()); };
+    m!(0);
+    m!(1);
+    m!(2);
+
+    for _ in [()] {
+        unit_fn_block();
+    }
+    for _ in [()] {
+        unit_fn_block()
+    }
+
+    let _d = || {
+        unit_fn_block();
+    };
+    let _d = || {
+        unit_fn_block()
+    };
+
+    { unit_fn_block(); };
+
+    unit_fn_block()
+}
diff --git a/src/tools/clippy/tests/ui/semicolon_outside_block.stderr b/src/tools/clippy/tests/ui/semicolon_outside_block.stderr
new file mode 100644 (file)
index 0000000..dcc102e
--- /dev/null
@@ -0,0 +1,54 @@
+error: consider moving the `;` outside the block for consistent formatting
+  --> $DIR/semicolon_outside_block.rs:42:5
+   |
+LL |     { unit_fn_block(); }
+   |     ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::semicolon-outside-block` implied by `-D warnings`
+help: put the `;` here
+   |
+LL -     { unit_fn_block(); }
+LL +     { unit_fn_block() };
+   |
+
+error: consider moving the `;` outside the block for consistent formatting
+  --> $DIR/semicolon_outside_block.rs:43:5
+   |
+LL |     unsafe { unit_fn_block(); }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: put the `;` here
+   |
+LL -     unsafe { unit_fn_block(); }
+LL +     unsafe { unit_fn_block() };
+   |
+
+error: consider moving the `;` outside the block for consistent formatting
+  --> $DIR/semicolon_outside_block.rs:52:5
+   |
+LL | /     {
+LL | |         unit_fn_block();
+LL | |         unit_fn_block();
+LL | |     }
+   | |_____^
+   |
+help: put the `;` here
+   |
+LL ~         unit_fn_block()
+LL ~     };
+   |
+
+error: consider moving the `;` outside the block for consistent formatting
+  --> $DIR/semicolon_outside_block.rs:62:5
+   |
+LL |     { m!(()); }
+   |     ^^^^^^^^^^^
+   |
+help: put the `;` here
+   |
+LL -     { m!(()); }
+LL +     { m!(()) };
+   |
+
+error: aborting due to 4 previous errors
+
index df2256e4f97de98afe0285e587ac9924c000fb3a..506187fc125736f778df20459bfd641c4350901a 100644 (file)
@@ -25,6 +25,12 @@ fn str_lit_as_bytes() {
     let includestr = include_bytes!("string_lit_as_bytes.rs");
 
     let _ = b"string with newline\t\n";
+
+    let _ = match "x".as_bytes() {
+        b"xx" => 0,
+        [b'x', ..] => 1,
+        _ => 2,
+    };
 }
 
 fn main() {}
index c6bf8f732ed9f615d1ea2d660d6ed7602513270b..2c339f1ddb819334b446e0007f6c5e6146965f29 100644 (file)
@@ -25,6 +25,12 @@ fn str_lit_as_bytes() {
     let includestr = include_str!("string_lit_as_bytes.rs").as_bytes();
 
     let _ = "string with newline\t\n".as_bytes();
+
+    let _ = match "x".as_bytes() {
+        b"xx" => 0,
+        [b'x', ..] => 1,
+        _ => 2,
+    };
 }
 
 fn main() {}
index 96cc0877960ec00c627a896f5eb54cafc633f2c1..52b5343c351e6e42365e484869c1b4dd4160c996 100644 (file)
@@ -26,4 +26,7 @@ fn main() {
             panic!("p4 {var}");
         }
     }
+
+    assert!(var == 1, "p5 {}", var);
+    debug_assert!(var == 1, "p6 {}", var);
 }
index faf8ca4d3a797aa2e989571786cd8c317a2e6652..ee72065e28abf3bfb0c118de65166efd65a7f6a4 100644 (file)
@@ -26,4 +26,7 @@ fn main() {
             panic!("p4 {var}");
         }
     }
+
+    assert!(var == 1, "p5 {var}");
+    debug_assert!(var == 1, "p6 {var}");
 }
index 0f09c45f41324b94da38117a4d885deabe904c0f..fc7b125080e766296e83e69e253dd481640b4e11 100644 (file)
@@ -47,5 +47,29 @@ LL -         panic!("p3 {var}", var = var);
 LL +         panic!("p3 {var}");
    |
 
-error: aborting due to 4 previous errors
+error: variables can be used directly in the `format!` string
+  --> $DIR/uninlined_format_args_panic.rs:30:5
+   |
+LL |     assert!(var == 1, "p5 {}", var);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: change this to
+   |
+LL -     assert!(var == 1, "p5 {}", var);
+LL +     assert!(var == 1, "p5 {var}");
+   |
+
+error: variables can be used directly in the `format!` string
+  --> $DIR/uninlined_format_args_panic.rs:31:5
+   |
+LL |     debug_assert!(var == 1, "p6 {}", var);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: change this to
+   |
+LL -     debug_assert!(var == 1, "p6 {}", var);
+LL +     debug_assert!(var == 1, "p6 {var}");
+   |
+
+error: aborting due to 6 previous errors
 
index 6421c5bbed2f5a05a6b5523d8560f36a374ca6c3..b4a0a0f496e400d7bdb3c4d8f9444c12cb6549f9 100644 (file)
@@ -26,4 +26,7 @@ fn main() {
             panic!("p4 {var}");
         }
     }
+
+    assert!(var == 1, "p5 {}", var);
+    debug_assert!(var == 1, "p6 {}", var);
 }
index ddeda795f81793e8d70d7109a16c958a4821f7f0..345f6d604c4f005028cfda81242cbc275ba6923b 100644 (file)
@@ -454,3 +454,23 @@ mod issue_9771b {
         Key(v.to_vec())
     }
 }
+
+// This is a watered down version of the code in: https://github.com/oxigraph/rio
+// The ICE is triggered by the call to `to_owned` on this line:
+// https://github.com/oxigraph/rio/blob/66635b9ff8e5423e58932353fa40d6e64e4820f7/testsuite/src/parser_evaluator.rs#L116
+mod issue_10021 {
+    #![allow(unused)]
+
+    pub struct Iri<T>(T);
+
+    impl<T: AsRef<str>> Iri<T> {
+        pub fn parse(iri: T) -> Result<Self, ()> {
+            unimplemented!()
+        }
+    }
+
+    pub fn parse_w3c_rdf_test_file(url: &str) -> Result<(), ()> {
+        let base_iri = Iri::parse(url.to_owned())?;
+        Ok(())
+    }
+}
index 95d2576733cd75ea8e42bf0ea127fb8983f7e451..7eb53df39e5b7dace2e82dd95030c53282b01919 100644 (file)
@@ -454,3 +454,23 @@ pub fn from(c: &[u8]) -> Key<Vec<u8>> {
         Key(v.to_vec())
     }
 }
+
+// This is a watered down version of the code in: https://github.com/oxigraph/rio
+// The ICE is triggered by the call to `to_owned` on this line:
+// https://github.com/oxigraph/rio/blob/66635b9ff8e5423e58932353fa40d6e64e4820f7/testsuite/src/parser_evaluator.rs#L116
+mod issue_10021 {
+    #![allow(unused)]
+
+    pub struct Iri<T>(T);
+
+    impl<T: AsRef<str>> Iri<T> {
+        pub fn parse(iri: T) -> Result<Self, ()> {
+            unimplemented!()
+        }
+    }
+
+    pub fn parse_w3c_rdf_test_file(url: &str) -> Result<(), ()> {
+        let base_iri = Iri::parse(url.to_owned())?;
+        Ok(())
+    }
+}
diff --git a/src/tools/clippy/tests/ui/zero_ptr_no_std.fixed b/src/tools/clippy/tests/ui/zero_ptr_no_std.fixed
new file mode 100644 (file)
index 0000000..8906c77
--- /dev/null
@@ -0,0 +1,21 @@
+// run-rustfix
+
+#![feature(lang_items, start, libc)]
+#![no_std]
+#![deny(clippy::zero_ptr)]
+
+#[start]
+fn main(_argc: isize, _argv: *const *const u8) -> isize {
+    let _ = core::ptr::null::<usize>();
+    let _ = core::ptr::null_mut::<f64>();
+    let _: *const u8 = core::ptr::null();
+    0
+}
+
+#[panic_handler]
+fn panic(_info: &core::panic::PanicInfo) -> ! {
+    loop {}
+}
+
+#[lang = "eh_personality"]
+extern "C" fn eh_personality() {}
diff --git a/src/tools/clippy/tests/ui/zero_ptr_no_std.rs b/src/tools/clippy/tests/ui/zero_ptr_no_std.rs
new file mode 100644 (file)
index 0000000..379c1b1
--- /dev/null
@@ -0,0 +1,21 @@
+// run-rustfix
+
+#![feature(lang_items, start, libc)]
+#![no_std]
+#![deny(clippy::zero_ptr)]
+
+#[start]
+fn main(_argc: isize, _argv: *const *const u8) -> isize {
+    let _ = 0 as *const usize;
+    let _ = 0 as *mut f64;
+    let _: *const u8 = 0 as *const _;
+    0
+}
+
+#[panic_handler]
+fn panic(_info: &core::panic::PanicInfo) -> ! {
+    loop {}
+}
+
+#[lang = "eh_personality"]
+extern "C" fn eh_personality() {}
diff --git a/src/tools/clippy/tests/ui/zero_ptr_no_std.stderr b/src/tools/clippy/tests/ui/zero_ptr_no_std.stderr
new file mode 100644 (file)
index 0000000..d92bb4a
--- /dev/null
@@ -0,0 +1,26 @@
+error: `0 as *const _` detected
+  --> $DIR/zero_ptr_no_std.rs:9:13
+   |
+LL |     let _ = 0 as *const usize;
+   |             ^^^^^^^^^^^^^^^^^ help: try: `core::ptr::null::<usize>()`
+   |
+note: the lint level is defined here
+  --> $DIR/zero_ptr_no_std.rs:5:9
+   |
+LL | #![deny(clippy::zero_ptr)]
+   |         ^^^^^^^^^^^^^^^^
+
+error: `0 as *mut _` detected
+  --> $DIR/zero_ptr_no_std.rs:10:13
+   |
+LL |     let _ = 0 as *mut f64;
+   |             ^^^^^^^^^^^^^ help: try: `core::ptr::null_mut::<f64>()`
+
+error: `0 as *const _` detected
+  --> $DIR/zero_ptr_no_std.rs:11:24
+   |
+LL |     let _: *const u8 = 0 as *const _;
+   |                        ^^^^^^^^^^^^^ help: try: `core::ptr::null()`
+
+error: aborting due to 3 previous errors
+
index 7a85386a3df4b8fc9934fe30010e5f87820fe12d..c721e9969c9aa67497c32ab03d2510e6e6ecaf11 100644 (file)
@@ -2,7 +2,6 @@
 #![warn(rust_2018_idioms, unused_lifetimes)]
 #![allow(clippy::single_match_else)]
 
-use rustc_tools_util::VersionInfo;
 use std::fs;
 
 #[test]
index acb476ee69628efc987a0785bae0ddb36ea85b46..6f50ef932e11260ffbc86b75820f2b4aea76f3fd 100644 (file)
@@ -1,7 +1,7 @@
 [relabel]
 allow-unauthenticated = [
     "A-*", "C-*", "E-*", "I-*", "L-*", "P-*", "S-*", "T-*",
-    "good-first-issue"
+    "good-first-issue", "beta-nominated"
 ]
 
 # Allows shortcuts like `@rustbot ready`
index e5b1eb2e4870696691a5f1672ea90f194665a865..ab629e4711b10c0e2ca8e5fec502336575f2ab9a 100644 (file)
@@ -22,8 +22,9 @@
 };
 use rustc_span::def_id::{CrateNum, DefId};
 use rustc_span::Symbol;
-use rustc_target::abi::Size;
+use rustc_target::abi::{Size, Align};
 use rustc_target::spec::abi::Abi;
+use rustc_const_eval::const_eval::CheckAlignment;
 
 use crate::{
     concurrency::{data_race, weak_memory},
@@ -752,8 +753,12 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
     const PANIC_ON_ALLOC_FAIL: bool = false;
 
     #[inline(always)]
-    fn enforce_alignment(ecx: &MiriInterpCx<'mir, 'tcx>) -> bool {
-        ecx.machine.check_alignment != AlignmentCheck::None
+    fn enforce_alignment(ecx: &MiriInterpCx<'mir, 'tcx>) -> CheckAlignment {
+        if ecx.machine.check_alignment == AlignmentCheck::None {
+            CheckAlignment::No
+        } else {
+            CheckAlignment::Error
+        }
     }
 
     #[inline(always)]
@@ -761,6 +766,15 @@ fn use_addr_for_alignment_check(ecx: &MiriInterpCx<'mir, 'tcx>) -> bool {
         ecx.machine.check_alignment == AlignmentCheck::Int
     }
 
+    fn alignment_check_failed(
+        _ecx: &InterpCx<'mir, 'tcx, Self>,
+        has: Align,
+        required: Align,
+        _check: CheckAlignment,
+    ) -> InterpResult<'tcx, ()> {
+        throw_ub!(AlignmentCheckFailed { has, required })
+    }
+
     #[inline(always)]
     fn enforce_validity(ecx: &MiriInterpCx<'mir, 'tcx>) -> bool {
         ecx.machine.validate
index 8e7c39e72b68bddf1dd817c524adc4f31bc432db..c1450aedc31406edb76091c475999f6d7b109487 100644 (file)
@@ -46,6 +46,7 @@ macro_rules! t {
 struct Config {
     verbose: bool,
     sequential: bool,
+    batch: bool,
     bind: SocketAddr,
 }
 
@@ -54,6 +55,7 @@ pub fn default() -> Config {
         Config {
             verbose: false,
             sequential: false,
+            batch: false,
             bind: if cfg!(target_os = "android") || cfg!(windows) {
                 ([0, 0, 0, 0], 12345).into()
             } else {
@@ -75,6 +77,7 @@ pub fn parse_args() -> Config {
                 }
                 "--bind" => next_is_bind = true,
                 "--sequential" => config.sequential = true,
+                "--batch" => config.batch = true,
                 "--verbose" | "-v" => config.verbose = true,
                 "--help" | "-h" => {
                     show_help();
@@ -100,6 +103,7 @@ fn show_help() {
 OPTIONS:
     --bind <IP>:<PORT>   Specify IP address and port to listen for requests, e.g. "0.0.0.0:12345"
     --sequential         Run only one test at a time
+    --batch              Send stdout and stderr in batch instead of streaming
     -v, --verbose        Show status messages
     -h, --help           Show this help screen
 "#,
@@ -280,22 +284,30 @@ fn handle_run(socket: TcpStream, work: &Path, tmp: &Path, lock: &Mutex<()>, conf
     // Some tests assume RUST_TEST_TMPDIR exists
     cmd.env("RUST_TEST_TMPDIR", tmp.to_owned());
 
-    // Spawn the child and ferry over stdout/stderr to the socket in a framed
-    // fashion (poor man's style)
-    let mut child =
-        t!(cmd.stdin(Stdio::null()).stdout(Stdio::piped()).stderr(Stdio::piped()).spawn());
-    drop(lock);
-    let mut stdout = child.stdout.take().unwrap();
-    let mut stderr = child.stderr.take().unwrap();
     let socket = Arc::new(Mutex::new(reader.into_inner()));
-    let socket2 = socket.clone();
-    let thread = thread::spawn(move || my_copy(&mut stdout, 0, &*socket2));
-    my_copy(&mut stderr, 1, &*socket);
-    thread.join().unwrap();
 
-    // Finally send over the exit status.
-    let status = t!(child.wait());
+    let status = if config.batch {
+        let child =
+            t!(cmd.stdin(Stdio::null()).stdout(Stdio::piped()).stderr(Stdio::piped()).output());
+        batch_copy(&child.stdout, 0, &*socket);
+        batch_copy(&child.stderr, 1, &*socket);
+        child.status
+    } else {
+        // Spawn the child and ferry over stdout/stderr to the socket in a framed
+        // fashion (poor man's style)
+        let mut child =
+            t!(cmd.stdin(Stdio::null()).stdout(Stdio::piped()).stderr(Stdio::piped()).spawn());
+        drop(lock);
+        let mut stdout = child.stdout.take().unwrap();
+        let mut stderr = child.stderr.take().unwrap();
+        let socket2 = socket.clone();
+        let thread = thread::spawn(move || my_copy(&mut stdout, 0, &*socket2));
+        my_copy(&mut stderr, 1, &*socket);
+        thread.join().unwrap();
+        t!(child.wait())
+    };
 
+    // Finally send over the exit status.
     let (which, code) = get_status_code(&status);
 
     t!(socket.lock().unwrap().write_all(&[
@@ -368,6 +380,17 @@ fn my_copy(src: &mut dyn Read, which: u8, dst: &Mutex<dyn Write>) {
     }
 }
 
+fn batch_copy(buf: &[u8], which: u8, dst: &Mutex<dyn Write>) {
+    let n = buf.len();
+    let mut dst = dst.lock().unwrap();
+    t!(dst.write_all(&[which, (n >> 24) as u8, (n >> 16) as u8, (n >> 8) as u8, (n >> 0) as u8,]));
+    if n > 0 {
+        t!(dst.write_all(buf));
+        // Marking buf finished
+        t!(dst.write_all(&[which, 0, 0, 0, 0,]));
+    }
+}
+
 fn read_u32(r: &mut dyn Read) -> u32 {
     let mut len = [0; 4];
     t!(r.read_exact(&mut len));
index 610e322e12963e63854e0b3ba08b5300762abacd..1b119e4113e32bf9543255aae9810fd742b437da 100644 (file)
@@ -11,8 +11,8 @@
 
 // A few of those error codes can't be tested but all the others can and *should* be tested!
 const EXEMPTED_FROM_TEST: &[&str] = &[
-    "E0313", "E0377", "E0461", "E0462", "E0465", "E0476", "E0490", "E0514", "E0519", "E0523",
-    "E0554", "E0640", "E0717", "E0729", "E0789",
+    "E0313", "E0461", "E0462", "E0465", "E0476", "E0490", "E0514", "E0519", "E0523", "E0554",
+    "E0640", "E0717", "E0729", "E0789",
 ];
 
 // Some error codes don't have any tests apparently...
index b0b11cafca5a8a20be5482dca060a6403e61623a..6714c63ee62a143a923f84088101cc99ec1142d1 100644 (file)
@@ -35,15 +35,26 @@ fn main() {
 
     let bad = std::sync::Arc::new(AtomicBool::new(false));
 
+    let drain_handles = |handles: &mut VecDeque<ScopedJoinHandle<'_, ()>>| {
+        // poll all threads for completion before awaiting the oldest one
+        for i in (0..handles.len()).rev() {
+            if handles[i].is_finished() {
+                handles.swap_remove_back(i).unwrap().join().unwrap();
+            }
+        }
+
+        while handles.len() >= concurrency.get() {
+            handles.pop_front().unwrap().join().unwrap();
+        }
+    };
+
     scope(|s| {
         let mut handles: VecDeque<ScopedJoinHandle<'_, ()>> =
             VecDeque::with_capacity(concurrency.get());
 
         macro_rules! check {
             ($p:ident $(, $args:expr)* ) => {
-                while handles.len() >= concurrency.get() {
-                    handles.pop_front().unwrap().join().unwrap();
-                }
+                drain_handles(&mut handles);
 
                 let handle = s.spawn(|| {
                     let mut flag = false;
@@ -97,9 +108,8 @@ macro_rules! check {
         check!(alphabetical, &library_path);
 
         let collected = {
-            while handles.len() >= concurrency.get() {
-                handles.pop_front().unwrap().join().unwrap();
-            }
+            drain_handles(&mut handles);
+
             let mut flag = false;
             let r = features::check(&src_path, &compiler_path, &library_path, &mut flag, verbose);
             if flag {
index e3a094caf919aaa43c2f369d923193e0891fd4fb..f91e38262f64ff8fd1800c99b1cc10ec85856569 100644 (file)
@@ -17,7 +17,7 @@
 //! `// ignore-tidy-CHECK-NAME`.
 
 use crate::walk::{filter_dirs, walk};
-use regex::Regex;
+use regex::{Regex, RegexSet};
 use std::path::Path;
 
 /// Error code markdown is restricted to 80 columns because they can be
@@ -225,6 +225,7 @@ fn skip(path: &Path) -> bool {
         .chain(PROBLEMATIC_CONSTS.iter().map(|v| format!("{:x}", v)))
         .chain(PROBLEMATIC_CONSTS.iter().map(|v| format!("{:X}", v)))
         .collect();
+    let problematic_regex = RegexSet::new(problematic_consts_strings.as_slice()).unwrap();
     walk(path, &mut skip, &mut |entry, contents| {
         let file = entry.path();
         let filename = file.file_name().unwrap().to_string_lossy();
@@ -281,7 +282,27 @@ fn skip(path: &Path) -> bool {
         let mut trailing_new_lines = 0;
         let mut lines = 0;
         let mut last_safety_comment = false;
+        let is_test = file.components().any(|c| c.as_os_str() == "tests");
+        // scanning the whole file for multiple needles at once is more efficient than
+        // executing lines times needles separate searches.
+        let any_problematic_line = problematic_regex.is_match(contents);
         for (i, line) in contents.split('\n').enumerate() {
+            if line.is_empty() {
+                if i == 0 {
+                    leading_new_lines = true;
+                }
+                trailing_new_lines += 1;
+                continue;
+            } else {
+                trailing_new_lines = 0;
+            }
+
+            let trimmed = line.trim();
+
+            if !trimmed.starts_with("//") {
+                lines += 1;
+            }
+
             let mut err = |msg: &str| {
                 tidy_error!(bad, "{}:{}: {}", file.display(), i + 1, msg);
             };
@@ -308,28 +329,29 @@ fn skip(path: &Path) -> bool {
                 suppressible_tidy_err!(err, skip_cr, "CR character");
             }
             if filename != "style.rs" {
-                if line.contains("TODO") {
+                if trimmed.contains("TODO") {
                     err("TODO is deprecated; use FIXME")
                 }
-                if line.contains("//") && line.contains(" XXX") {
+                if trimmed.contains("//") && trimmed.contains(" XXX") {
                     err("XXX is deprecated; use FIXME")
                 }
-                for s in problematic_consts_strings.iter() {
-                    if line.contains(s) {
-                        err("Don't use magic numbers that spell things (consider 0x12345678)");
+                if any_problematic_line {
+                    for s in problematic_consts_strings.iter() {
+                        if trimmed.contains(s) {
+                            err("Don't use magic numbers that spell things (consider 0x12345678)");
+                        }
                     }
                 }
             }
-            let is_test = || file.components().any(|c| c.as_os_str() == "tests");
             // for now we just check libcore
-            if line.contains("unsafe {") && !line.trim().starts_with("//") && !last_safety_comment {
-                if file.components().any(|c| c.as_os_str() == "core") && !is_test() {
+            if trimmed.contains("unsafe {") && !trimmed.starts_with("//") && !last_safety_comment {
+                if file.components().any(|c| c.as_os_str() == "core") && !is_test {
                     suppressible_tidy_err!(err, skip_undocumented_unsafe, "undocumented unsafe");
                 }
             }
-            if line.contains("// SAFETY:") {
+            if trimmed.contains("// SAFETY:") {
                 last_safety_comment = true;
-            } else if line.trim().starts_with("//") || line.trim().is_empty() {
+            } else if trimmed.starts_with("//") || trimmed.is_empty() {
                 // keep previous value
             } else {
                 last_safety_comment = false;
@@ -337,7 +359,8 @@ fn skip(path: &Path) -> bool {
             if (line.starts_with("// Copyright")
                 || line.starts_with("# Copyright")
                 || line.starts_with("Copyright"))
-                && (line.contains("Rust Developers") || line.contains("Rust Project Developers"))
+                && (trimmed.contains("Rust Developers")
+                    || trimmed.contains("Rust Project Developers"))
             {
                 suppressible_tidy_err!(
                     err,
@@ -351,18 +374,6 @@ fn skip(path: &Path) -> bool {
             if filename.ends_with(".cpp") && line.contains("llvm_unreachable") {
                 err(LLVM_UNREACHABLE_INFO);
             }
-            if line.is_empty() {
-                if i == 0 {
-                    leading_new_lines = true;
-                }
-                trailing_new_lines += 1;
-            } else {
-                trailing_new_lines = 0;
-            }
-
-            if !line.trim().starts_with("//") {
-                lines += 1;
-            }
         }
         if leading_new_lines {
             let mut err = |_| {
index 02c364dabf960cbc72b10e2edd0ca52bb2f45dc6..f07ff43efe987fec445e76d8102f6c2bbdcabd4a 100644 (file)
@@ -1,51 +1,43 @@
-//! Run `x.py` from any subdirectory of a rust compiler checkout.
+//! Run bootstrap from any subdirectory of a rust compiler checkout.
 //!
 //! We prefer `exec`, to avoid adding an extra process in the process tree.
 //! However, since `exec` isn't available on Windows, we indirect through
 //! `exec_or_status`, which will call `exec` on unix and `status` on Windows.
 //!
-//! We use `python`, `python3`, or `python2` as the python interpreter to run
-//! `x.py`, in that order of preference.
+//! We use `powershell.exe x.ps1` on Windows, and `sh -c x` on Unix, those are
+//! the ones that call `x.py`. We use `sh -c` on Unix, because it is a standard.
+//! We also don't use `pwsh` on Windows, because it is not installed by default;
 
 use std::{
-    env::{self, consts::EXE_EXTENSION},
-    io,
+    env, io,
+    path::Path,
     process::{self, Command, ExitStatus},
 };
 
-const PYTHON: &str = "python";
-const PYTHON2: &str = "python2";
-const PYTHON3: &str = "python3";
-
-fn python() -> &'static str {
-    let val = match env::var_os("PATH") {
-        Some(val) => val,
-        None => return PYTHON,
-    };
-
-    let mut python2 = false;
-    let mut python3 = false;
-
-    for dir in env::split_paths(&val) {
-        // `python` should always take precedence over python2 / python3 if it exists
-        if dir.join(PYTHON).with_extension(EXE_EXTENSION).exists() {
-            return PYTHON;
-        }
+#[cfg(windows)]
+fn x_command(dir: &Path) -> Command {
+    let mut cmd = Command::new("powershell.exe");
+    cmd.args([
+        "-NoLogo",
+        "-NoProfile",
+        "-NonInteractive",
+        "-ExecutionPolicy",
+        "RemoteSigned",
+        "-Command",
+        "./x.ps1",
+    ])
+    .current_dir(dir);
+    cmd
+}
 
-        python2 |= dir.join(PYTHON2).with_extension(EXE_EXTENSION).exists();
-        python3 |= dir.join(PYTHON3).with_extension(EXE_EXTENSION).exists();
-    }
+#[cfg(unix)]
+fn x_command(dir: &Path) -> Command {
+    Command::new(dir.join("x"))
+}
 
-    // try 3 before 2
-    if python3 {
-        PYTHON3
-    } else if python2 {
-        PYTHON2
-    } else {
-        // Python was not found on path, so exit
-        eprintln!("Unable to find python in your PATH. Please check it is installed.");
-        process::exit(1);
-    }
+#[cfg(not(any(windows, unix)))]
+fn x_command(_dir: &Path) -> Command {
+    compile_error!("Unsupported platform");
 }
 
 #[cfg(unix)]
@@ -72,15 +64,15 @@ fn main() {
         let candidate = dir.join("x.py");
 
         if candidate.exists() {
-            let mut python = Command::new(python());
+            let mut cmd = x_command(dir);
 
-            python.arg(&candidate).args(env::args().skip(1)).current_dir(dir);
+            cmd.args(env::args().skip(1)).current_dir(dir);
 
-            let result = exec_or_status(&mut python);
+            let result = exec_or_status(&mut cmd);
 
             match result {
                 Err(error) => {
-                    eprintln!("Failed to invoke `{}`: {}", candidate.display(), error);
+                    eprintln!("Failed to invoke `{:?}`: {}", cmd, error);
                 }
                 Ok(status) => {
                     process::exit(status.code().unwrap_or(1));