]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #104091 - BelovDV:issue-103044, r=petrochenkov
authorbors <bors@rust-lang.org>
Tue, 15 Nov 2022 00:38:08 +0000 (00:38 +0000)
committerbors <bors@rust-lang.org>
Tue, 15 Nov 2022 00:38:08 +0000 (00:38 +0000)
Wrap bundled static libraries into object files

Fixes #103044 (not sure, couldn't test locally)

Bundled static libraries should be wrapped into object files as it's done for metadata file.

r? `@petrochenkov`

1044 files changed:
.git-blame-ignore-revs
.mailmap
.reuse/dep5
Cargo.lock
LICENSES/BSD-2-Clause.txt [deleted file]
compiler/rustc_ast/src/ast.rs
compiler/rustc_ast/src/lib.rs
compiler/rustc_ast/src/mut_visit.rs
compiler/rustc_ast/src/token.rs
compiler/rustc_ast/src/util/case.rs [new file with mode: 0644]
compiler/rustc_ast/src/util/literal.rs
compiler/rustc_ast/src/visit.rs
compiler/rustc_ast_lowering/src/expr.rs
compiler/rustc_ast_lowering/src/pat.rs
compiler/rustc_ast_pretty/src/pprust/state/expr.rs
compiler/rustc_borrowck/src/borrow_set.rs
compiler/rustc_borrowck/src/borrowck_errors.rs
compiler/rustc_borrowck/src/constraint_generation.rs
compiler/rustc_borrowck/src/constraints/mod.rs
compiler/rustc_borrowck/src/consumers.rs
compiler/rustc_borrowck/src/dataflow.rs
compiler/rustc_borrowck/src/def_use.rs
compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs
compiler/rustc_borrowck/src/diagnostics/find_use.rs
compiler/rustc_borrowck/src/diagnostics/mod.rs
compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
compiler/rustc_borrowck/src/diagnostics/region_errors.rs
compiler/rustc_borrowck/src/diagnostics/region_name.rs
compiler/rustc_borrowck/src/diagnostics/var_name.rs
compiler/rustc_borrowck/src/facts.rs
compiler/rustc_borrowck/src/invalidation.rs
compiler/rustc_borrowck/src/lib.rs
compiler/rustc_borrowck/src/location.rs
compiler/rustc_borrowck/src/member_constraints.rs
compiler/rustc_borrowck/src/nll.rs
compiler/rustc_borrowck/src/path_utils.rs
compiler/rustc_borrowck/src/place_ext.rs
compiler/rustc_borrowck/src/places_conflict.rs
compiler/rustc_borrowck/src/prefixes.rs
compiler/rustc_borrowck/src/region_infer/dump_mir.rs
compiler/rustc_borrowck/src/region_infer/graphviz.rs
compiler/rustc_borrowck/src/region_infer/opaque_types.rs
compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs
compiler/rustc_borrowck/src/region_infer/values.rs
compiler/rustc_borrowck/src/renumber.rs
compiler/rustc_borrowck/src/session_diagnostics.rs
compiler/rustc_borrowck/src/type_check/free_region_relations.rs
compiler/rustc_borrowck/src/type_check/mod.rs
compiler/rustc_borrowck/src/used_muts.rs
compiler/rustc_builtin_macros/src/assert/context.rs
compiler/rustc_builtin_macros/src/cfg_accessible.rs
compiler/rustc_builtin_macros/src/concat.rs
compiler/rustc_builtin_macros/src/concat_bytes.rs
compiler/rustc_builtin_macros/src/derive.rs
compiler/rustc_builtin_macros/src/deriving/bounds.rs
compiler/rustc_builtin_macros/src/deriving/clone.rs
compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
compiler/rustc_builtin_macros/src/deriving/debug.rs
compiler/rustc_builtin_macros/src/deriving/decodable.rs
compiler/rustc_builtin_macros/src/deriving/default.rs
compiler/rustc_builtin_macros/src/deriving/encodable.rs
compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
compiler/rustc_builtin_macros/src/deriving/hash.rs
compiler/rustc_builtin_macros/src/deriving/mod.rs
compiler/rustc_builtin_macros/src/lib.rs
compiler/rustc_builtin_macros/src/source_util.rs
compiler/rustc_builtin_macros/src/test.rs
compiler/rustc_codegen_cranelift/src/constant.rs
compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
compiler/rustc_codegen_cranelift/src/value_and_place.rs
compiler/rustc_codegen_gcc/src/type_.rs
compiler/rustc_codegen_llvm/src/attributes.rs
compiler/rustc_codegen_llvm/src/back/archive.rs
compiler/rustc_codegen_llvm/src/back/lto.rs
compiler/rustc_codegen_llvm/src/back/write.rs
compiler/rustc_codegen_llvm/src/consts.rs
compiler/rustc_codegen_llvm/src/context.rs
compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
compiler/rustc_codegen_llvm/src/errors.rs [new file with mode: 0644]
compiler/rustc_codegen_llvm/src/intrinsic.rs
compiler/rustc_codegen_llvm/src/lib.rs
compiler/rustc_codegen_llvm/src/llvm_util.rs
compiler/rustc_codegen_llvm/src/mono_item.rs
compiler/rustc_codegen_llvm/src/type_of.rs
compiler/rustc_codegen_ssa/src/back/link.rs
compiler/rustc_codegen_ssa/src/back/linker.rs
compiler/rustc_codegen_ssa/src/back/write.rs
compiler/rustc_codegen_ssa/src/base.rs
compiler/rustc_codegen_ssa/src/glue.rs
compiler/rustc_codegen_ssa/src/mir/place.rs
compiler/rustc_const_eval/src/const_eval/eval_queries.rs
compiler/rustc_const_eval/src/interpret/eval_context.rs
compiler/rustc_const_eval/src/interpret/intrinsics.rs
compiler/rustc_const_eval/src/interpret/memory.rs
compiler/rustc_const_eval/src/interpret/operand.rs
compiler/rustc_const_eval/src/interpret/place.rs
compiler/rustc_const_eval/src/interpret/step.rs
compiler/rustc_const_eval/src/interpret/traits.rs
compiler/rustc_const_eval/src/transform/check_consts/check.rs
compiler/rustc_data_structures/Cargo.toml
compiler/rustc_data_structures/src/intern.rs
compiler/rustc_driver/src/lib.rs
compiler/rustc_error_codes/src/error_codes/E0207.md
compiler/rustc_error_codes/src/error_codes/E0706.md
compiler/rustc_error_messages/locales/en-US/borrowck.ftl
compiler/rustc_error_messages/locales/en-US/codegen_llvm.ftl [new file with mode: 0644]
compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl
compiler/rustc_error_messages/locales/en-US/infer.ftl
compiler/rustc_error_messages/locales/en-US/parser.ftl
compiler/rustc_error_messages/locales/en-US/passes.ftl
compiler/rustc_error_messages/src/lib.rs
compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
compiler/rustc_errors/src/diagnostic.rs
compiler/rustc_errors/src/diagnostic_builder.rs
compiler/rustc_errors/src/diagnostic_impls.rs
compiler/rustc_errors/src/emitter.rs
compiler/rustc_errors/src/translation.rs
compiler/rustc_expand/src/base.rs
compiler/rustc_expand/src/expand.rs
compiler/rustc_expand/src/mbe.rs
compiler/rustc_expand/src/mbe/macro_parser.rs
compiler/rustc_expand/src/mbe/macro_rules.rs
compiler/rustc_expand/src/proc_macro.rs
compiler/rustc_expand/src/proc_macro_server.rs
compiler/rustc_feature/src/accepted.rs
compiler/rustc_feature/src/active.rs
compiler/rustc_feature/src/builtin_attrs.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/check/intrinsic.rs
compiler/rustc_hir_analysis/src/check/wfcheck.rs
compiler/rustc_hir_analysis/src/coherence/builtin.rs
compiler/rustc_hir_analysis/src/collect.rs
compiler/rustc_hir_analysis/src/collect/lifetimes.rs
compiler/rustc_hir_analysis/src/collect/type_of.rs
compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
compiler/rustc_hir_analysis/src/lib.rs
compiler/rustc_hir_typeck/src/_match.rs
compiler/rustc_hir_typeck/src/autoderef.rs
compiler/rustc_hir_typeck/src/check.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/errors.rs
compiler/rustc_hir_typeck/src/expr.rs
compiler/rustc_hir_typeck/src/fallback.rs
compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
compiler/rustc_hir_typeck/src/generator_interior/mod.rs
compiler/rustc_hir_typeck/src/lib.rs
compiler/rustc_hir_typeck/src/method/confirm.rs
compiler/rustc_hir_typeck/src/method/mod.rs
compiler/rustc_hir_typeck/src/method/probe.rs
compiler/rustc_hir_typeck/src/method/suggest.rs
compiler/rustc_hir_typeck/src/op.rs
compiler/rustc_hir_typeck/src/pat.rs
compiler/rustc_hir_typeck/src/place_op.rs
compiler/rustc_infer/src/errors/mod.rs
compiler/rustc_infer/src/errors/note_and_explain.rs
compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
compiler/rustc_infer/src/infer/error_reporting/mod.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs [new file with mode: 0644]
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
compiler/rustc_infer/src/infer/mod.rs
compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
compiler/rustc_infer/src/infer/region_constraints/mod.rs
compiler/rustc_infer/src/lib.rs
compiler/rustc_infer/src/traits/error_reporting/mod.rs
compiler/rustc_interface/src/lib.rs
compiler/rustc_interface/src/util.rs
compiler/rustc_lexer/src/lib.rs
compiler/rustc_lexer/src/unescape.rs
compiler/rustc_lexer/src/unescape/tests.rs
compiler/rustc_lint/src/context.rs
compiler/rustc_lint/src/levels.rs
compiler/rustc_lint/src/lib.rs
compiler/rustc_lint/src/unused.rs
compiler/rustc_llvm/build.rs
compiler/rustc_macros/src/diagnostics/error.rs
compiler/rustc_middle/src/hir/map/mod.rs
compiler/rustc_middle/src/infer/canonical.rs
compiler/rustc_middle/src/lib.rs
compiler/rustc_middle/src/middle/privacy.rs
compiler/rustc_middle/src/mir/interpret/mod.rs
compiler/rustc_middle/src/mir/mod.rs
compiler/rustc_middle/src/query/mod.rs
compiler/rustc_middle/src/traits/mod.rs
compiler/rustc_middle/src/ty/consts.rs
compiler/rustc_middle/src/ty/context.rs
compiler/rustc_middle/src/ty/error.rs
compiler/rustc_middle/src/ty/fold.rs
compiler/rustc_middle/src/ty/layout.rs
compiler/rustc_middle/src/ty/mod.rs
compiler/rustc_middle/src/ty/print/pretty.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/visit.rs
compiler/rustc_middle/src/ty/vtable.rs
compiler/rustc_middle/src/values.rs
compiler/rustc_mir_build/src/build/custom/mod.rs [new file with mode: 0644]
compiler/rustc_mir_build/src/build/custom/parse.rs [new file with mode: 0644]
compiler/rustc_mir_build/src/build/custom/parse/instruction.rs [new file with mode: 0644]
compiler/rustc_mir_build/src/build/expr/as_constant.rs
compiler/rustc_mir_build/src/build/mod.rs
compiler/rustc_mir_build/src/thir/constant.rs
compiler/rustc_mir_build/src/thir/cx/expr.rs
compiler/rustc_mir_build/src/thir/cx/mod.rs
compiler/rustc_mir_build/src/thir/pattern/mod.rs
compiler/rustc_mir_transform/src/check_unsafety.rs
compiler/rustc_mir_transform/src/const_prop.rs
compiler/rustc_mir_transform/src/const_prop_lint.rs
compiler/rustc_mir_transform/src/pass_manager.rs
compiler/rustc_mir_transform/src/required_consts.rs
compiler/rustc_parse/src/errors.rs
compiler/rustc_parse/src/lexer/mod.rs
compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
compiler/rustc_parse/src/parser/attr_wrapper.rs
compiler/rustc_parse/src/parser/diagnostics.rs
compiler/rustc_parse/src/parser/expr.rs
compiler/rustc_parse/src/parser/item.rs
compiler/rustc_parse/src/parser/mod.rs
compiler/rustc_parse/src/parser/path.rs
compiler/rustc_parse/src/parser/stmt.rs
compiler/rustc_parse/src/parser/ty.rs
compiler/rustc_parse_format/src/lib.rs
compiler/rustc_passes/src/check_attr.rs
compiler/rustc_passes/src/errors.rs
compiler/rustc_passes/src/hir_stats.rs
compiler/rustc_passes/src/liveness.rs
compiler/rustc_passes/src/stability.rs
compiler/rustc_privacy/src/lib.rs
compiler/rustc_query_impl/src/on_disk_cache.rs
compiler/rustc_query_impl/src/profiling_support.rs
compiler/rustc_query_system/src/cache.rs
compiler/rustc_query_system/src/dep_graph/dep_node.rs
compiler/rustc_query_system/src/dep_graph/graph.rs
compiler/rustc_query_system/src/dep_graph/mod.rs
compiler/rustc_query_system/src/ich/hcx.rs
compiler/rustc_query_system/src/query/config.rs
compiler/rustc_query_system/src/query/job.rs
compiler/rustc_query_system/src/query/plumbing.rs
compiler/rustc_query_system/src/values.rs
compiler/rustc_resolve/src/build_reduced_graph.rs
compiler/rustc_resolve/src/diagnostics.rs
compiler/rustc_resolve/src/effective_visibilities.rs
compiler/rustc_resolve/src/late.rs
compiler/rustc_resolve/src/late/diagnostics.rs
compiler/rustc_resolve/src/lib.rs
compiler/rustc_resolve/src/macros.rs
compiler/rustc_session/src/config.rs
compiler/rustc_span/src/source_map.rs
compiler/rustc_span/src/source_map/tests.rs
compiler/rustc_span/src/symbol.rs
compiler/rustc_symbol_mangling/src/v0.rs
compiler/rustc_target/src/abi/call/loongarch.rs [new file with mode: 0644]
compiler/rustc_target/src/abi/call/mod.rs
compiler/rustc_target/src/abi/mod.rs
compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
compiler/rustc_target/src/spec/aarch64_apple_ios.rs
compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs
compiler/rustc_target/src/spec/aarch64_apple_ios_sim.rs
compiler/rustc_target/src/spec/aarch64_apple_tvos.rs
compiler/rustc_target/src/spec/aarch64_apple_watchos_sim.rs
compiler/rustc_target/src/spec/aarch64_unknown_nto_qnx_710.rs [new file with mode: 0644]
compiler/rustc_target/src/spec/apple_base.rs
compiler/rustc_target/src/spec/apple_sdk_base.rs [deleted file]
compiler/rustc_target/src/spec/arm64_32_apple_watchos.rs
compiler/rustc_target/src/spec/armv7_apple_ios.rs
compiler/rustc_target/src/spec/armv7k_apple_watchos.rs
compiler/rustc_target/src/spec/armv7s_apple_ios.rs
compiler/rustc_target/src/spec/i386_apple_ios.rs
compiler/rustc_target/src/spec/i686_apple_darwin.rs
compiler/rustc_target/src/spec/linux_kernel_base.rs [deleted file]
compiler/rustc_target/src/spec/mod.rs
compiler/rustc_target/src/spec/nto_qnx_base.rs [new file with mode: 0644]
compiler/rustc_target/src/spec/tests/tests_impl.rs
compiler/rustc_target/src/spec/windows_gnullvm_base.rs
compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
compiler/rustc_target/src/spec/x86_64_apple_ios.rs
compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs
compiler/rustc_target/src/spec/x86_64_apple_tvos.rs
compiler/rustc_target/src/spec/x86_64_apple_watchos_sim.rs
compiler/rustc_target/src/spec/x86_64_pc_nto_qnx710.rs [new file with mode: 0644]
compiler/rustc_target/src/spec/x86_64_unknown_none_linuxkernel.rs [deleted file]
compiler/rustc_trait_selection/src/autoderef.rs
compiler/rustc_trait_selection/src/lib.rs
compiler/rustc_trait_selection/src/traits/auto_trait.rs
compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
compiler/rustc_trait_selection/src/traits/engine.rs
compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs [new file with mode: 0644]
compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
compiler/rustc_trait_selection/src/traits/fulfill.rs
compiler/rustc_trait_selection/src/traits/misc.rs
compiler/rustc_trait_selection/src/traits/mod.rs
compiler/rustc_trait_selection/src/traits/on_unimplemented.rs [deleted file]
compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
compiler/rustc_trait_selection/src/traits/project.rs
compiler/rustc_trait_selection/src/traits/query/normalize.rs
compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
compiler/rustc_trait_selection/src/traits/select/mod.rs
compiler/rustc_trait_selection/src/traits/specialize/mod.rs
compiler/rustc_trait_selection/src/traits/wf.rs
compiler/rustc_traits/src/chalk/db.rs
compiler/rustc_traits/src/chalk/lowering.rs
compiler/rustc_traits/src/dropck_outlives.rs
compiler/rustc_ty_utils/src/consts.rs
compiler/rustc_ty_utils/src/layout.rs
config.toml.example
library/alloc/src/alloc.rs
library/alloc/src/alloc/tests.rs
library/alloc/src/boxed.rs
library/alloc/src/collections/btree/map.rs
library/alloc/src/collections/btree/node/tests.rs
library/alloc/src/collections/btree/set.rs
library/alloc/src/collections/mod.rs
library/alloc/src/collections/vec_deque/tests.rs
library/core/benches/iter.rs
library/core/benches/lib.rs
library/core/src/alloc/layout.rs
library/core/src/array/mod.rs
library/core/src/cmp.rs
library/core/src/default.rs
library/core/src/error.rs
library/core/src/hash/mod.rs
library/core/src/hash/sip.rs
library/core/src/hint.rs
library/core/src/intrinsics.rs
library/core/src/intrinsics/mir.rs [new file with mode: 0644]
library/core/src/iter/adapters/array_chunks.rs
library/core/src/lib.rs
library/core/src/macros/mod.rs
library/core/src/mem/mod.rs
library/core/src/num/int_macros.rs
library/core/src/num/nonzero.rs
library/core/src/num/uint_macros.rs
library/core/src/ops/deref.rs
library/core/src/ops/function.rs
library/core/src/ops/index.rs
library/core/src/option.rs
library/core/src/panicking.rs
library/core/src/pin.rs
library/core/src/prelude/v1.rs
library/core/src/ptr/const_ptr.rs
library/core/src/ptr/mod.rs
library/core/src/ptr/mut_ptr.rs
library/core/src/slice/mod.rs
library/core/src/time.rs
library/core/src/tuple.rs
library/core/tests/hash/mod.rs
library/core/tests/hash/sip.rs
library/core/tests/iter/adapters/array_chunks.rs
library/core/tests/lib.rs
library/core/tests/option.rs
library/portable-simd/crates/core_simd/src/intrinsics.rs
library/portable-simd/crates/core_simd/src/ops.rs
library/proc_macro/src/lib.rs
library/std/Cargo.toml
library/std/src/collections/hash/map.rs
library/std/src/lib.rs
library/std/src/path.rs
library/std/src/personality/gcc.rs
library/std/src/prelude/v1.rs
library/std/src/sync/condvar.rs
library/std/src/sync/mod.rs
library/std/src/sync/mpmc/array.rs [new file with mode: 0644]
library/std/src/sync/mpmc/context.rs [new file with mode: 0644]
library/std/src/sync/mpmc/counter.rs [new file with mode: 0644]
library/std/src/sync/mpmc/error.rs [new file with mode: 0644]
library/std/src/sync/mpmc/list.rs [new file with mode: 0644]
library/std/src/sync/mpmc/mod.rs [new file with mode: 0644]
library/std/src/sync/mpmc/select.rs [new file with mode: 0644]
library/std/src/sync/mpmc/utils.rs [new file with mode: 0644]
library/std/src/sync/mpmc/waker.rs [new file with mode: 0644]
library/std/src/sync/mpmc/zero.rs [new file with mode: 0644]
library/std/src/sync/mpsc/blocking.rs [deleted file]
library/std/src/sync/mpsc/cache_aligned.rs [deleted file]
library/std/src/sync/mpsc/mod.rs
library/std/src/sync/mpsc/mpsc_queue.rs [deleted file]
library/std/src/sync/mpsc/mpsc_queue/tests.rs [deleted file]
library/std/src/sync/mpsc/oneshot.rs [deleted file]
library/std/src/sync/mpsc/shared.rs [deleted file]
library/std/src/sync/mpsc/spsc_queue.rs [deleted file]
library/std/src/sync/mpsc/spsc_queue/tests.rs [deleted file]
library/std/src/sync/mpsc/stream.rs [deleted file]
library/std/src/sync/mpsc/sync.rs [deleted file]
library/std/src/sync/mpsc/tests.rs
library/std/src/sync/mutex.rs
library/std/src/sync/rwlock.rs
library/std/src/sys/hermit/mod.rs
library/std/src/sys/itron/condvar.rs
library/std/src/sys/itron/mutex.rs
library/std/src/sys/sgx/condvar.rs
library/std/src/sys/sgx/mutex.rs
library/std/src/sys/sgx/rwlock.rs
library/std/src/sys/sgx/rwlock/tests.rs
library/std/src/sys/solid/rwlock.rs
library/std/src/sys/unix/locks/fuchsia_mutex.rs
library/std/src/sys/unix/locks/futex_condvar.rs
library/std/src/sys/unix/locks/futex_mutex.rs
library/std/src/sys/unix/locks/futex_rwlock.rs
library/std/src/sys/unix/locks/mod.rs
library/std/src/sys/unix/locks/pthread_condvar.rs
library/std/src/sys/unix/locks/pthread_mutex.rs
library/std/src/sys/unix/locks/pthread_rwlock.rs
library/std/src/sys/unsupported/locks/condvar.rs
library/std/src/sys/unsupported/locks/mod.rs
library/std/src/sys/unsupported/locks/mutex.rs
library/std/src/sys/unsupported/locks/rwlock.rs
library/std/src/sys/wasm/mod.rs
library/std/src/sys/windows/locks/condvar.rs
library/std/src/sys/windows/locks/mod.rs
library/std/src/sys/windows/locks/mutex.rs
library/std/src/sys/windows/locks/rwlock.rs
library/std/src/sys_common/condvar.rs [deleted file]
library/std/src/sys_common/condvar/check.rs [deleted file]
library/std/src/sys_common/mod.rs
library/std/src/sys_common/mutex.rs [deleted file]
library/std/src/sys_common/remutex.rs
library/std/src/sys_common/rwlock.rs [deleted file]
library/std/src/thread/local/tests.rs
library/std/src/time.rs
library/unwind/Cargo.toml
library/unwind/src/lib.rs
library/unwind/src/libunwind.rs
src/bootstrap/Cargo.lock
src/bootstrap/Cargo.toml
src/bootstrap/bin/main.rs
src/bootstrap/builder.rs
src/bootstrap/builder/tests.rs
src/bootstrap/channel.rs
src/bootstrap/compile.rs
src/bootstrap/config.rs
src/bootstrap/dist.rs
src/bootstrap/doc.rs
src/bootstrap/download.rs [new file with mode: 0644]
src/bootstrap/flags.rs
src/bootstrap/format.rs
src/bootstrap/lib.rs
src/bootstrap/native.rs
src/bootstrap/run.rs
src/bootstrap/sanity.rs
src/bootstrap/setup.rs
src/bootstrap/tarball.rs
src/bootstrap/test.rs
src/bootstrap/tool.rs
src/bootstrap/toolstate.rs
src/bootstrap/util.rs
src/ci/docker/host-x86_64/dist-s390x-linux/Dockerfile
src/ci/docker/host-x86_64/dist-various-2/Dockerfile
src/ci/docker/host-x86_64/dist-x86_64-netbsd/Dockerfile
src/ci/docker/host-x86_64/dist-x86_64-netbsd/build-netbsd-toolchain.sh
src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh
src/ci/run.sh
src/doc/book
src/doc/nomicon
src/doc/reference
src/doc/rust-by-example
src/doc/rustc-dev-guide
src/doc/rustc/src/SUMMARY.md
src/doc/rustc/src/linker-plugin-lto.md
src/doc/rustc/src/platform-support.md
src/doc/rustc/src/platform-support/nto-qnx.md [new file with mode: 0644]
src/doc/rustc/src/platform-support/unknown-uefi.md
src/librustdoc/clean/inline.rs
src/librustdoc/clean/mod.rs
src/librustdoc/clean/types.rs
src/librustdoc/clean/utils.rs
src/librustdoc/config.rs
src/librustdoc/html/format.rs
src/librustdoc/html/layout.rs
src/librustdoc/html/render/context.rs
src/librustdoc/html/render/mod.rs
src/librustdoc/html/render/print_item.rs
src/librustdoc/html/sources.rs
src/librustdoc/html/static/css/noscript.css
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/main.js
src/librustdoc/html/static/js/settings.js
src/librustdoc/html/static/js/source-script.js
src/librustdoc/json/conversions.rs
src/librustdoc/passes/collect_intra_doc_links.rs
src/llvm-project
src/stage0.json
src/test/assembly/strict_provenance.rs [new file with mode: 0644]
src/test/codegen/abi-efiapi.rs
src/test/codegen/auxiliary/static_dllimport_aux.rs [new file with mode: 0644]
src/test/codegen/enum-match.rs [new file with mode: 0644]
src/test/codegen/issue-81408-dllimport-thinlto-windows.rs [new file with mode: 0644]
src/test/debuginfo/mutex.rs
src/test/debuginfo/rwlock-read.rs
src/test/incremental/issue-101518.rs [new file with mode: 0644]
src/test/mir-opt/building/custom/references.immut_ref.built.after.mir [new file with mode: 0644]
src/test/mir-opt/building/custom/references.mut_ref.built.after.mir [new file with mode: 0644]
src/test/mir-opt/building/custom/references.rs [new file with mode: 0644]
src/test/mir-opt/building/custom/simple_assign.rs [new file with mode: 0644]
src/test/mir-opt/building/custom/simple_assign.simple.built.after.mir [new file with mode: 0644]
src/test/mir-opt/building/custom/simple_assign.simple_ref.built.after.mir [new file with mode: 0644]
src/test/run-make-fulldeps/link-dedup/Makefile
src/test/run-make-fulldeps/link-dedup/depa.rs
src/test/run-make-fulldeps/split-debuginfo/Makefile
src/test/run-make-fulldeps/split-debuginfo/baz.rs [new file with mode: 0644]
src/test/run-make/valid-print-requests/valid-print-requests.stderr
src/test/rustdoc-gui/code-tags.goml
src/test/rustdoc-gui/docblock-code-block-line-number.goml
src/test/rustdoc-gui/item-decl-colors.goml
src/test/rustdoc-gui/no-docblock.goml
src/test/rustdoc-gui/notable-trait.goml
src/test/rustdoc-gui/search-no-result.goml [new file with mode: 0644]
src/test/rustdoc-gui/search-result-display.goml
src/test/rustdoc-gui/settings.goml
src/test/rustdoc-gui/source-code-page.goml
src/test/rustdoc-gui/src-font-size.goml
src/test/rustdoc-gui/target.goml [new file with mode: 0644]
src/test/rustdoc-gui/trait-sidebar-item-order.goml
src/test/rustdoc-gui/type-declation-overflow.goml
src/test/rustdoc-ui/issue-103997.rs [new file with mode: 0644]
src/test/rustdoc-ui/issue-103997.stderr [new file with mode: 0644]
src/test/rustdoc/check-source-code-urls-to-def.rs
src/test/rustdoc/doc-notable_trait-slice.bare_fn_matches.html [new file with mode: 0644]
src/test/rustdoc/doc-notable_trait-slice.rs
src/test/rustdoc/doc-notable_trait.bare-fn.html [new file with mode: 0644]
src/test/rustdoc/doc-notable_trait.rs
src/test/rustdoc/doc-notable_trait.some-struct-new.html [new file with mode: 0644]
src/test/rustdoc/doc-notable_trait.wrap-me.html [new file with mode: 0644]
src/test/rustdoc/multiple-import-levels.rs [new file with mode: 0644]
src/test/rustdoc/spotlight-from-dependency.odd.html [new file with mode: 0644]
src/test/rustdoc/spotlight-from-dependency.rs
src/test/ui/abi/homogenous-floats-target-feature-mixup.rs [new file with mode: 0644]
src/test/ui/argument-suggestions/formal-and-expected-differ.rs [new file with mode: 0644]
src/test/ui/argument-suggestions/formal-and-expected-differ.stderr [new file with mode: 0644]
src/test/ui/asm/naked-invalid-attr.stderr
src/test/ui/associated-type-bounds/duplicate.rs
src/test/ui/associated-type-bounds/duplicate.stderr
src/test/ui/async-await/issues/issue-65159.rs
src/test/ui/async-await/issues/issue-65159.stderr
src/test/ui/attributes/key-value-non-ascii.rs
src/test/ui/attributes/key-value-non-ascii.stderr
src/test/ui/borrowck/async-reference-generality.rs [new file with mode: 0644]
src/test/ui/borrowck/async-reference-generality.stderr [new file with mode: 0644]
src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue-2.stderr
src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.stderr
src/test/ui/borrowck/issue-11493.stderr
src/test/ui/borrowck/issue-17545.stderr
src/test/ui/borrowck/issue-36082.fixed
src/test/ui/borrowck/issue-36082.rs
src/test/ui/borrowck/issue-36082.stderr
src/test/ui/borrowck/issue-82126-mismatched-subst-and-hir.rs
src/test/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr
src/test/ui/chalkify/trait-objects.stderr
src/test/ui/check-cfg/well-known-values.stderr
src/test/ui/cleanup-rvalue-scopes-cf.stderr
src/test/ui/closures/2229_closure_analysis/match/issue-87097.stderr
src/test/ui/closures/supertrait-hint-references-assoc-ty.rs [new file with mode: 0644]
src/test/ui/codegen/issue-99551.rs
src/test/ui/conditional-compilation/cfg-attr-multi-true.stderr
src/test/ui/conditional-compilation/cfg_accessible-not_sure.rs
src/test/ui/const-generics/min_const_generics/macro-fail.rs
src/test/ui/const-generics/min_const_generics/macro-fail.stderr
src/test/ui/consts/const-eval/const-eval-intrinsic-promotion.stderr
src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr
src/test/ui/consts/const-eval/dont_promote_unstable_const_fn_cross_crate.stderr
src/test/ui/consts/const-eval/promoted_const_fn_fail.stderr
src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.stderr
src/test/ui/consts/const-eval/promoted_raw_ptr_ops.stderr
src/test/ui/consts/const-eval/transmute-const-promotion.stderr
src/test/ui/consts/const-eval/union_promotion.stderr
src/test/ui/consts/const-int-conversion.stderr
src/test/ui/consts/const-int-overflowing.stderr
src/test/ui/consts/const-int-rotate.stderr
src/test/ui/consts/const-int-sign.stderr
src/test/ui/consts/const-int-wrapping.stderr
src/test/ui/consts/const-mut-refs/mut_ref_in_final.stderr
src/test/ui/consts/const-ptr-nonnull.stderr
src/test/ui/consts/const-ptr-unique.stderr
src/test/ui/consts/control-flow/interior-mutability.stderr
src/test/ui/consts/fn_trait_refs.rs [new file with mode: 0644]
src/test/ui/consts/invalid-const-in-body.rs [new file with mode: 0644]
src/test/ui/consts/invalid-const-in-body.stderr [new file with mode: 0644]
src/test/ui/consts/issue-104155.rs [new file with mode: 0644]
src/test/ui/consts/issue-54224.stderr
src/test/ui/consts/issue-54954.rs [new file with mode: 0644]
src/test/ui/consts/issue-54954.stderr [new file with mode: 0644]
src/test/ui/consts/min_const_fn/promotion.stderr
src/test/ui/consts/promote-not.stderr
src/test/ui/consts/promote_const_let.stderr
src/test/ui/consts/promoted-const-drop.stderr
src/test/ui/consts/qualif-union.stderr
src/test/ui/did_you_mean/issue-103909.stderr
src/test/ui/dropck/issue-54943-1.rs [new file with mode: 0644]
src/test/ui/dropck/issue-54943-2.rs [new file with mode: 0644]
src/test/ui/dyn-star/issue-102430.rs [new file with mode: 0644]
src/test/ui/enum-discriminant/get_discr.rs [new file with mode: 0644]
src/test/ui/enum-discriminant/issue-46519.rs [new file with mode: 0644]
src/test/ui/error-codes/E0282.rs
src/test/ui/error-codes/E0401.rs
src/test/ui/error-codes/E0401.stderr
src/test/ui/feature-gates/feature-gate-abi-efiapi.rs [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-abi-efiapi.stderr [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-abi.rs
src/test/ui/feature-gates/feature-gate-abi.stderr
src/test/ui/feature-gates/feature-gate-custom_mir.rs [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-custom_mir.stderr [new file with mode: 0644]
src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr
src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs
src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr
src/test/ui/fmt/unicode-escape-spans.rs [new file with mode: 0644]
src/test/ui/fmt/unicode-escape-spans.stderr [new file with mode: 0644]
src/test/ui/generator/auto-trait-regions.stderr
src/test/ui/generator/issue-52398.stderr
src/test/ui/generator/issue-57084.stderr
src/test/ui/generator/match-bindings.stderr
src/test/ui/generator/reborrow-mut-upvar.stderr
src/test/ui/generator/too-live-local-in-immovable-gen.stderr
src/test/ui/generator/yield-in-args-rev.stderr
src/test/ui/generator/yield-in-box.stderr
src/test/ui/generator/yield-in-initializer.stderr
src/test/ui/generator/yield-subtype.stderr
src/test/ui/generic-associated-types/bugs/hrtb-implied-1.stderr
src/test/ui/generic-associated-types/bugs/issue-100013.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/bugs/issue-100013.stderr [new file with mode: 0644]
src/test/ui/generic-associated-types/bugs/issue-80626.rs
src/test/ui/generic-associated-types/bugs/issue-80626.stderr [deleted file]
src/test/ui/generic-associated-types/issue-87750.rs
src/test/ui/generic-associated-types/issue-87750.stderr [deleted file]
src/test/ui/generic-associated-types/projection-bound-cycle-generic.rs
src/test/ui/generic-associated-types/projection-bound-cycle-generic.stderr
src/test/ui/generic-associated-types/projection-bound-cycle.rs
src/test/ui/generic-associated-types/projection-bound-cycle.stderr
src/test/ui/higher-rank-trait-bounds/issue-36139-normalize-closure-sig.rs [new file with mode: 0644]
src/test/ui/higher-rank-trait-bounds/issue-43623.rs [new file with mode: 0644]
src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90950.rs [new file with mode: 0644]
src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90950.stderr [new file with mode: 0644]
src/test/ui/higher-rank-trait-bounds/normalize-under-binder/norm-before-method-resolution.rs [new file with mode: 0644]
src/test/ui/higher-rank-trait-bounds/normalize-under-binder/norm-before-method-resolution.stderr [new file with mode: 0644]
src/test/ui/impl-trait/cross-return-site-inference.rs
src/test/ui/impl-trait/cross-return-site-inference.stderr
src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2021.stderr
src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.rs
src/test/ui/impl-trait/impl-fn-parsing-ambiguities.rs
src/test/ui/impl-trait/in-trait/generics-mismatch.rs [new file with mode: 0644]
src/test/ui/impl-trait/in-trait/generics-mismatch.stderr [new file with mode: 0644]
src/test/ui/impl-trait/in-trait/method-signature-matches.rs [new file with mode: 0644]
src/test/ui/impl-trait/in-trait/method-signature-matches.stderr [new file with mode: 0644]
src/test/ui/impl-trait/in-trait/specialization-broken.rs [new file with mode: 0644]
src/test/ui/impl-trait/in-trait/specialization-broken.stderr [new file with mode: 0644]
src/test/ui/impl-trait/in-trait/specialization-substs-remap.rs [new file with mode: 0644]
src/test/ui/impl-trait/issues/issue-92305.rs
src/test/ui/impl-trait/issues/issue-92305.stderr
src/test/ui/impl-trait/nested-rpit-hrtb.rs
src/test/ui/implied-bounds/hrlt-implied-trait-bounds-guard.rs
src/test/ui/implied-bounds/hrlt-implied-trait-bounds-guard.stderr
src/test/ui/inference/cannot-infer-async.rs
src/test/ui/inference/cannot-infer-closure.rs
src/test/ui/inference/issue-103587.rs [new file with mode: 0644]
src/test/ui/inference/issue-103587.stderr [new file with mode: 0644]
src/test/ui/inference/issue-71732.rs
src/test/ui/inference/issue-72616.rs
src/test/ui/inference/issue-72616.stderr
src/test/ui/inference/question-mark-type-infer.rs
src/test/ui/issues/auxiliary/issue-75907.rs [deleted file]
src/test/ui/issues/issue-10969.rs [deleted file]
src/test/ui/issues/issue-10969.stderr [deleted file]
src/test/ui/issues/issue-11612.rs [deleted file]
src/test/ui/issues/issue-12552.rs [deleted file]
src/test/ui/issues/issue-12552.stderr [deleted file]
src/test/ui/issues/issue-1460.stderr
src/test/ui/issues/issue-16256.stderr
src/test/ui/issues/issue-32655.stderr
src/test/ui/issues/issue-35675.rs [deleted file]
src/test/ui/issues/issue-35675.stderr [deleted file]
src/test/ui/issues/issue-36139-normalize-closure-sig.rs [deleted file]
src/test/ui/issues/issue-3707.stderr
src/test/ui/issues/issue-43623.rs [deleted file]
src/test/ui/issues/issue-46519.rs [deleted file]
src/test/ui/issues/issue-47184.stderr
src/test/ui/issues/issue-47511.rs [deleted file]
src/test/ui/issues/issue-47511.stderr [deleted file]
src/test/ui/issues/issue-50687-ice-on-borrow.rs [deleted file]
src/test/ui/issues/issue-50687-ice-on-borrow.stderr [deleted file]
src/test/ui/issues/issue-52049.stderr
src/test/ui/issues/issue-5216.rs [deleted file]
src/test/ui/issues/issue-5216.stderr [deleted file]
src/test/ui/issues/issue-52240.rs [deleted file]
src/test/ui/issues/issue-52240.stderr [deleted file]
src/test/ui/issues/issue-54943-1.rs [deleted file]
src/test/ui/issues/issue-54943-2.rs [deleted file]
src/test/ui/issues/issue-54943.rs [deleted file]
src/test/ui/issues/issue-54943.stderr [deleted file]
src/test/ui/issues/issue-54954.rs [deleted file]
src/test/ui/issues/issue-54954.stderr [deleted file]
src/test/ui/issues/issue-5927.rs [deleted file]
src/test/ui/issues/issue-5927.stderr [deleted file]
src/test/ui/issues/issue-69396-const-no-type-in-macro.stderr
src/test/ui/issues/issue-7013.rs [deleted file]
src/test/ui/issues/issue-7013.stderr [deleted file]
src/test/ui/issues/issue-71584.rs
src/test/ui/issues/issue-75907.rs [deleted file]
src/test/ui/issues/issue-75907.stderr [deleted file]
src/test/ui/issues/issue-75907_b.rs [deleted file]
src/test/ui/issues/issue-75907_b.stderr [deleted file]
src/test/ui/iterators/collect-into-array.rs
src/test/ui/iterators/collect-into-array.stderr
src/test/ui/iterators/collect-into-slice.rs
src/test/ui/iterators/collect-into-slice.stderr
src/test/ui/late-bound-lifetimes/auxiliary/upstream_alias.rs [new file with mode: 0644]
src/test/ui/late-bound-lifetimes/cross_crate_alias.rs [new file with mode: 0644]
src/test/ui/late-bound-lifetimes/downgraded_to_early_through_alias.rs [new file with mode: 0644]
src/test/ui/late-bound-lifetimes/issue-47511.rs [new file with mode: 0644]
src/test/ui/late-bound-lifetimes/late_bound_through_alias.rs [new file with mode: 0644]
src/test/ui/late-bound-lifetimes/mismatched_arg_count.rs [new file with mode: 0644]
src/test/ui/late-bound-lifetimes/mismatched_arg_count.stderr [new file with mode: 0644]
src/test/ui/lifetimes/borrowck-let-suggestion.stderr
src/test/ui/lint/fn_must_use.stderr
src/test/ui/lint/issue-103435-extra-parentheses.fixed [new file with mode: 0644]
src/test/ui/lint/issue-103435-extra-parentheses.rs [new file with mode: 0644]
src/test/ui/lint/issue-103435-extra-parentheses.stderr [new file with mode: 0644]
src/test/ui/lint/unused/must-use-box-from-raw.stderr
src/test/ui/lint/unused/must_use-array.stderr
src/test/ui/lint/unused/must_use-in-stdlib-traits.stderr
src/test/ui/lint/unused/must_use-trait.stderr
src/test/ui/lint/unused/must_use-unit.stderr
src/test/ui/lint/unused/unused-async.rs
src/test/ui/lint/unused/unused-async.stderr
src/test/ui/lint/unused/unused-closure.stderr
src/test/ui/lint/unused/unused-result.stderr
src/test/ui/lint/unused/unused-supertrait.stderr
src/test/ui/lint/unused/unused_attributes-must_use.stderr
src/test/ui/match/issue-12552.rs [new file with mode: 0644]
src/test/ui/match/issue-12552.stderr [new file with mode: 0644]
src/test/ui/never_type/exhaustive_patterns.rs [new file with mode: 0644]
src/test/ui/never_type/exhaustive_patterns.stderr [new file with mode: 0644]
src/test/ui/nll/borrowed-temporary-error.stderr
src/test/ui/nll/closure-requirements/escape-argument-callee.stderr
src/test/ui/nll/closure-requirements/escape-argument.stderr
src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr
src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr
src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr
src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr
src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr
src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr
src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr
src/test/ui/nll/issue-48623-generator.stderr
src/test/ui/nll/issue-54943.rs [new file with mode: 0644]
src/test/ui/nll/issue-54943.stderr [new file with mode: 0644]
src/test/ui/nll/issue-57265-return-type-wf-check.stderr
src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr
src/test/ui/nll/user-annotations/ascribed-type-wf.rs [new file with mode: 0644]
src/test/ui/nll/user-annotations/patterns.stderr
src/test/ui/parser/byte-literals.rs
src/test/ui/parser/byte-literals.stderr
src/test/ui/parser/byte-string-literals.rs
src/test/ui/parser/byte-string-literals.stderr
src/test/ui/parser/issue-103451.rs [new file with mode: 0644]
src/test/ui/parser/issue-103451.stderr [new file with mode: 0644]
src/test/ui/parser/issue-103748-ICE-wrong-braces.rs [new file with mode: 0644]
src/test/ui/parser/issue-103748-ICE-wrong-braces.stderr [new file with mode: 0644]
src/test/ui/parser/item-kw-case-mismatch.fixed [new file with mode: 0644]
src/test/ui/parser/item-kw-case-mismatch.rs [new file with mode: 0644]
src/test/ui/parser/item-kw-case-mismatch.stderr [new file with mode: 0644]
src/test/ui/parser/label-after-block-like.rs [new file with mode: 0644]
src/test/ui/parser/label-after-block-like.stderr [new file with mode: 0644]
src/test/ui/parser/raw/raw-byte-string-literals.rs
src/test/ui/parser/raw/raw-byte-string-literals.stderr
src/test/ui/parser/unicode-control-codepoints.rs
src/test/ui/parser/unicode-control-codepoints.stderr
src/test/ui/parser/use-colon-as-mod-sep.rs [new file with mode: 0644]
src/test/ui/parser/use-colon-as-mod-sep.stderr [new file with mode: 0644]
src/test/ui/pattern/issue-52240.rs [new file with mode: 0644]
src/test/ui/pattern/issue-52240.stderr [new file with mode: 0644]
src/test/ui/pin-macro/lifetime_errors_on_promotion_misusage.stderr
src/test/ui/privacy/auxiliary/issue-75907.rs [new file with mode: 0644]
src/test/ui/privacy/effective_visibilities.rs
src/test/ui/privacy/effective_visibilities.stderr
src/test/ui/privacy/effective_visibilities_glob.rs [new file with mode: 0644]
src/test/ui/privacy/effective_visibilities_glob.stderr [new file with mode: 0644]
src/test/ui/privacy/issue-75907.rs [new file with mode: 0644]
src/test/ui/privacy/issue-75907.stderr [new file with mode: 0644]
src/test/ui/privacy/issue-75907_b.rs [new file with mode: 0644]
src/test/ui/privacy/issue-75907_b.stderr [new file with mode: 0644]
src/test/ui/proc-macro/expand-expr.rs
src/test/ui/proc-macro/expand-expr.stderr
src/test/ui/regions/issue-11612.rs [new file with mode: 0644]
src/test/ui/regions/regions-free-region-ordering-caller1.stderr
src/test/ui/regions/regions-var-type-out-of-scope.stderr
src/test/ui/resolve/issue-103474.rs [new file with mode: 0644]
src/test/ui/resolve/issue-103474.stderr [new file with mode: 0644]
src/test/ui/resolve/issue-2356.stderr
src/test/ui/resolve/issue-35675.rs [new file with mode: 0644]
src/test/ui/resolve/issue-35675.stderr [new file with mode: 0644]
src/test/ui/resolve/issue-5927.rs [new file with mode: 0644]
src/test/ui/resolve/issue-5927.stderr [new file with mode: 0644]
src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr
src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-gate.rs [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-gate.stderr [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.rs [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.stderr [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-use.rs [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.rs [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.rs [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-impl-non-const-specialized-impl.rs [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-impl-non-const-specialized-impl.stderr [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/specialization/default-keyword.rs [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.rs [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/specializing-constness.rs
src/test/ui/rfc-2632-const-trait-impl/specializing-constness.stderr
src/test/ui/sanitize/memory-passing.rs [new file with mode: 0644]
src/test/ui/self/class-missing-self.stderr
src/test/ui/sized/coinductive-1-gat.rs [new file with mode: 0644]
src/test/ui/sized/coinductive-1.rs [new file with mode: 0644]
src/test/ui/sized/coinductive-2.rs [new file with mode: 0644]
src/test/ui/sized/recursive-type-1.rs [new file with mode: 0644]
src/test/ui/sized/recursive-type-2.rs [new file with mode: 0644]
src/test/ui/sized/recursive-type-2.stderr [new file with mode: 0644]
src/test/ui/span/borrowck-let-suggestion-suffixes.rs
src/test/ui/span/borrowck-let-suggestion-suffixes.stderr
src/test/ui/span/borrowck-ref-into-rvalue.stderr
src/test/ui/span/issue-15480.stderr
src/test/ui/span/regions-close-over-borrowed-ref-in-obj.stderr
src/test/ui/span/slice-borrow.stderr
src/test/ui/static/issue-5216.rs [new file with mode: 0644]
src/test/ui/static/issue-5216.stderr [new file with mode: 0644]
src/test/ui/static/static-drop-scope.stderr
src/test/ui/static/static-reference-to-fn-2.stderr
src/test/ui/static/static-region-bound.stderr
src/test/ui/statics/issue-44373.stderr
src/test/ui/suggestions/assoc_fn_without_self.stderr
src/test/ui/suggestions/if-let-typo.stderr
src/test/ui/suggestions/inner_type2.rs
src/test/ui/suggestions/inner_type2.stderr
src/test/ui/suggestions/issue-102354.stderr
src/test/ui/suggestions/issue-104086-suggest-let.rs [new file with mode: 0644]
src/test/ui/suggestions/issue-104086-suggest-let.stderr [new file with mode: 0644]
src/test/ui/suggestions/multibyte-escapes.rs
src/test/ui/suggestions/multibyte-escapes.stderr
src/test/ui/suggestions/option-to-bool.rs [new file with mode: 0644]
src/test/ui/suggestions/option-to-bool.stderr [new file with mode: 0644]
src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish-placeholder.rs [new file with mode: 0644]
src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish-placeholder.stderr [new file with mode: 0644]
src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish-through-deref.stderr
src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish.fixed [new file with mode: 0644]
src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish.rs
src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish.stderr
src/test/ui/suggestions/unnecessary_dot_for_floating_point_literal.rs [new file with mode: 0644]
src/test/ui/suggestions/unnecessary_dot_for_floating_point_literal.stderr [new file with mode: 0644]
src/test/ui/target-feature/tied-features-cli.one.stderr
src/test/ui/target-feature/tied-features-cli.three.stderr
src/test/ui/target-feature/tied-features-cli.two.stderr
src/test/ui/traits/invalid_operator_trait.rs [new file with mode: 0644]
src/test/ui/traits/invalid_operator_trait.stderr [new file with mode: 0644]
src/test/ui/traits/issue-7013.rs [new file with mode: 0644]
src/test/ui/traits/issue-7013.stderr [new file with mode: 0644]
src/test/ui/traits/issue-77982.stderr
src/test/ui/traits/issue-82830.rs
src/test/ui/traits/issue-82830.stderr [deleted file]
src/test/ui/traits/suggest-fully-qualified-closure.rs [new file with mode: 0644]
src/test/ui/traits/suggest-fully-qualified-closure.stderr [new file with mode: 0644]
src/test/ui/traits/trait-upcasting/basic.rs
src/test/ui/traits/trait-upcasting/correct-supertrait-substitution.rs
src/test/ui/traits/trait-upcasting/diamond.rs
src/test/ui/traits/trait-upcasting/invalid-upcast.rs
src/test/ui/traits/trait-upcasting/invalid-upcast.stderr
src/test/ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs
src/test/ui/traits/trait-upcasting/lifetime.rs
src/test/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.rs
src/test/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.stderr
src/test/ui/traits/trait-upcasting/replace-vptr.rs
src/test/ui/traits/trait-upcasting/struct.rs
src/test/ui/traits/trait-upcasting/subtrait-method.rs
src/test/ui/traits/trait-upcasting/subtrait-method.stderr
src/test/ui/traits/trait-upcasting/type-checking-test-1.rs
src/test/ui/traits/trait-upcasting/type-checking-test-1.stderr
src/test/ui/traits/trait-upcasting/type-checking-test-2.rs
src/test/ui/traits/trait-upcasting/type-checking-test-2.stderr
src/test/ui/traits/trait-upcasting/type-checking-test-3.polonius.stderr
src/test/ui/traits/trait-upcasting/type-checking-test-3.rs
src/test/ui/traits/trait-upcasting/type-checking-test-3.stderr
src/test/ui/traits/trait-upcasting/type-checking-test-4.polonius.stderr
src/test/ui/traits/trait-upcasting/type-checking-test-4.rs
src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr
src/test/ui/type/issue-103271.rs [new file with mode: 0644]
src/test/ui/type/issue-103271.stderr [new file with mode: 0644]
src/test/ui/typeck/issue-103899.rs [new file with mode: 0644]
src/test/ui/typeck/issue-103899.stderr [new file with mode: 0644]
src/test/ui/typeck/issue-10969.rs [new file with mode: 0644]
src/test/ui/typeck/issue-10969.stderr [new file with mode: 0644]
src/test/ui/typeck/issue-50687-ice-on-borrow.rs [new file with mode: 0644]
src/test/ui/typeck/issue-50687-ice-on-borrow.stderr [new file with mode: 0644]
src/test/ui/use/use-crate-self.rs [new file with mode: 0644]
src/test/ui/use/use-crate-self.stderr [new file with mode: 0644]
src/test/ui/where-clauses/higher-ranked-fn-type.rs
src/test/ui/where-clauses/higher-ranked-fn-type.verbose.stderr
src/tools/build-manifest/README.md
src/tools/build-manifest/src/main.rs
src/tools/build-manifest/src/manifest.rs
src/tools/build-manifest/src/versions.rs
src/tools/cargo
src/tools/clippy/clippy_utils/src/sugg.rs
src/tools/clippy/tests/ui/crashes/ice-6250.stderr
src/tools/linkchecker/main.rs
src/tools/miri/.github/workflows/ci.yml
src/tools/miri/.gitpod.yml
src/tools/miri/CONTRIBUTING.md
src/tools/miri/README.md
src/tools/miri/cargo-miri/src/phases.rs
src/tools/miri/cargo-miri/src/setup.rs
src/tools/miri/miri
src/tools/miri/rust-version
src/tools/miri/rustup-toolchain [deleted file]
src/tools/miri/src/concurrency/init_once.rs
src/tools/miri/src/concurrency/sync.rs
src/tools/miri/src/eval.rs
src/tools/miri/src/lib.rs
src/tools/miri/src/shims/unix/sync.rs
src/tools/miri/src/shims/windows/foreign_items.rs
src/tools/miri/src/shims/windows/sync.rs
src/tools/miri/src/stacked_borrows/mod.rs
src/tools/miri/tests/fail/stacked_borrows/newtype_pair_retagging.rs
src/tools/miri/tests/fail/stacked_borrows/newtype_retagging.rs
src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut_option.rs
src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut_option.stderr
src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut_tuple.rs
src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr
src/tools/miri/tests/fail/stacked_borrows/return_invalid_shr_option.rs
src/tools/miri/tests/fail/stacked_borrows/return_invalid_shr_option.stderr
src/tools/miri/tests/fail/stacked_borrows/return_invalid_shr_tuple.rs
src/tools/miri/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr
src/tools/miri/tests/pass/concurrency/sync.rs
src/tools/miri/tests/pass/concurrency/sync_nopreempt.rs
src/tools/miri/tests/pass/concurrency/windows_condvar_shared.rs [new file with mode: 0644]
src/tools/miri/tests/pass/concurrency/windows_condvar_shared.stdout [new file with mode: 0644]
src/tools/miri/tests/pass/concurrency/windows_init_once.rs
src/tools/miri/tests/pass/integer-ops.rs
src/tools/miri/tests/pass/panic/concurrent-panic.rs
src/tools/miri/tests/pass/stacked-borrows/no_field_retagging.rs [new file with mode: 0644]
src/tools/miri/tests/pass/stacked-borrows/stack-printing.stdout
src/tools/remote-test-server/src/main.rs
src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/bug_report.md
src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/critical_nightly_regression.md
src/tools/rust-analyzer/.github/workflows/release.yaml
src/tools/rust-analyzer/crates/hir-def/src/pretty.rs
src/tools/rust-analyzer/crates/hir-def/src/type_ref.rs
src/tools/rust-analyzer/crates/hir-ty/src/display.rs
src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs
src/tools/rust-analyzer/crates/hir/src/lib.rs
src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_explicit_type.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_return_type.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_comment_block.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_integer_literal.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_into_to_from.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_let_else_to_match.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_match_to_let_else.rs [new file with mode: 0644]
src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_projection_method.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_local_variable.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_lifetime.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_match_arms.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_from_mod_rs.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_module_to_file.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_to_mod_rs.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/number_representation.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_method_call.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/raw_string.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_or_with_or_else.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/unnecessary_async.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_tuple.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type_in_result.rs
src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
src/tools/rust-analyzer/crates/ide-assists/src/tests.rs
src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs
src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
src/tools/rust-analyzer/crates/ide-db/src/search.rs
src/tools/rust-analyzer/crates/ide/src/moniker.rs
src/tools/rust-analyzer/crates/ide/src/rename.rs
src/tools/rust-analyzer/crates/ide/src/signature_help.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
src/tools/rust-analyzer/crates/syntax/src/validation.rs
src/tools/rust-analyzer/docs/dev/guide.md
src/tools/rust-analyzer/docs/user/generated_config.adoc
src/tools/rust-analyzer/docs/user/manual.adoc
src/tools/rust-analyzer/editors/code/package-lock.json
src/tools/rust-analyzer/editors/code/package.json
src/tools/rust-analyzer/triagebot.toml
src/tools/rustdoc-gui/tester.js
src/tools/rustfmt/src/expr.rs
src/tools/rustfmt/src/utils.rs
src/tools/tidy/src/ui_tests.rs
triagebot.toml

index 307e22b0df1fd0968174cb1fe43721d5935119b6..b40066d05d355ec05aef4c9c018aa56586bea2bd 100644 (file)
@@ -4,3 +4,5 @@ a06baa56b95674fc626b3c3fd680d6a65357fe60
 95e00bfed801e264e9c4ac817004153ca0f19eb6
 # reformat with new rustfmt
 971c549ca334b7b7406e61e958efcca9c4152822
+# refactor infcx building
+283abbf0e7d20176f76006825b5c52e9a4234e4c
index 564a68955d30140ddac06e48ad00a19a00096a2b..f887d29096e038fe5eab11d838095fe916dfa97c 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -217,7 +217,7 @@ Hsiang-Cheng Yang <rick68@users.noreply.github.com>
 Ian Jackson <ijackson@chiark.greenend.org.uk> <ian.jackson@citrix.com>
 Ian Jackson <ijackson@chiark.greenend.org.uk> <ijackson+github@slimy.greenend.org.uk>
 Ian Jackson <ijackson@chiark.greenend.org.uk> <iwj@xenproject.org>
-Ibraheem Ahmed <ibrah1440@gmail.com>
+Ibraheem Ahmed <ibraheem@ibraheem.ca> <ibrah1440@gmail.com>
 Ilyong Cho <ilyoan@gmail.com>
 inquisitivecrystal <22333129+inquisitivecrystal@users.noreply.github.com>
 Irina Popa <irinagpopa@gmail.com>
index e040f73b9e1f7ecba73a62ac925c7bd45d2370af..5135f92a9d82ef47d0c4650c0f295b51dd80a3fc 100644 (file)
@@ -6,11 +6,6 @@ Files: *
 Copyright: The Rust Project Developers (see https://thanks.rust-lang.org)
 License: MIT or Apache-2.0
 
-Files: library/std/src/sync/mpsc/mpsc_queue.rs
-       library/std/src/sync/mpsc/spsc_queue.rs
-Copyright: 2010-2011 Dmitry Vyukov
-License: BSD-2-Clause
-
 Files: src/librustdoc/html/static/fonts/FiraSans*
 Copyright: 2014, Mozilla Foundation, 2014, Telefonica S.A.
 License: OFL-1.1
index f230f50212a3b841ef1b5aff6dc5c9db566b55bb..23481488563bd46a9f5e2753b60bb2496751f0f1 100644 (file)
@@ -4,41 +4,26 @@ version = 3
 
 [[package]]
 name = "addr2line"
-version = "0.16.0"
+version = "0.17.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e61f2b7f93d2c7d2b08263acaa4a363b3e276806c68af6134c44f523bf1aacd"
+checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b"
 dependencies = [
  "compiler_builtins",
- "gimli 0.25.0",
+ "gimli",
  "rustc-std-workspace-alloc",
  "rustc-std-workspace-core",
 ]
 
-[[package]]
-name = "addr2line"
-version = "0.17.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b"
-dependencies = [
- "gimli 0.26.1",
-]
-
 [[package]]
 name = "adler"
-version = "0.2.3"
+version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
+checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
 dependencies = [
  "compiler_builtins",
  "rustc-std-workspace-core",
 ]
 
-[[package]]
-name = "adler"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
-
 [[package]]
 name = "ahash"
 version = "0.7.4"
@@ -185,12 +170,12 @@ version = "0.3.66"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7"
 dependencies = [
- "addr2line 0.17.0",
+ "addr2line",
  "cc",
  "cfg-if 1.0.0",
  "libc",
- "miniz_oxide 0.5.3",
- "object 0.29.0",
+ "miniz_oxide",
+ "object",
  "rustc-demangle",
 ]
 
@@ -288,7 +273,7 @@ dependencies = [
 
 [[package]]
 name = "cargo"
-version = "0.67.0"
+version = "0.68.0"
 dependencies = [
  "anyhow",
  "atty",
@@ -488,9 +473,9 @@ version = "0.1.0"
 
 [[package]]
 name = "cc"
-version = "1.0.73"
+version = "1.0.76"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
+checksum = "76a284da2e6fe2092f2353e51713435363112dfd60030e22add80be333fb928f"
 dependencies = [
  "jobserver",
 ]
@@ -1295,15 +1280,15 @@ checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d"
 
 [[package]]
 name = "flate2"
-version = "1.0.16"
+version = "1.0.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68c90b0fc46cf89d227cc78b40e494ff81287a92dd07631e5af0d06fe3cf885e"
+checksum = "b39522e96686d38f4bc984b9198e3a0613264abaebaff2c5c918bfa6b6da09af"
 dependencies = [
- "cfg-if 0.1.10",
+ "cfg-if 1.0.0",
  "crc32fast",
  "libc",
  "libz-sys",
- "miniz_oxide 0.4.0",
+ "miniz_oxide",
 ]
 
 [[package]]
@@ -1545,25 +1530,17 @@ dependencies = [
  "wasi 0.9.0+wasi-snapshot-preview1",
 ]
 
-[[package]]
-name = "gimli"
-version = "0.25.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f0a01e0497841a3b2db4f8afa483cce65f7e96a3498bd6c541734792aeac8fe7"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
-]
-
 [[package]]
 name = "gimli"
 version = "0.26.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4"
 dependencies = [
+ "compiler_builtins",
  "fallible-iterator",
  "indexmap",
+ "rustc-std-workspace-alloc",
+ "rustc-std-workspace-core",
  "stable_deref_trait",
 ]
 
@@ -2228,25 +2205,16 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
 
 [[package]]
 name = "miniz_oxide"
-version = "0.4.0"
+version = "0.5.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be0f75932c1f6cfae3c04000e40114adf955636e19040f9c0a2c380702aa1c7f"
+checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc"
 dependencies = [
- "adler 0.2.3",
+ "adler",
  "compiler_builtins",
  "rustc-std-workspace-alloc",
  "rustc-std-workspace-core",
 ]
 
-[[package]]
-name = "miniz_oxide"
-version = "0.5.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc"
-dependencies = [
- "adler 1.0.2",
-]
-
 [[package]]
 name = "miow"
 version = "0.3.7"
@@ -2346,29 +2314,20 @@ dependencies = [
  "libc",
 ]
 
-[[package]]
-name = "object"
-version = "0.26.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "39f37e50073ccad23b6d09bcb5b263f4e76d3bb6038e4a3c08e52162ffa8abc2"
-dependencies = [
- "compiler_builtins",
- "memchr",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
-]
-
 [[package]]
 name = "object"
 version = "0.29.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53"
 dependencies = [
+ "compiler_builtins",
  "crc32fast",
  "flate2",
  "hashbrown",
  "indexmap",
  "memchr",
+ "rustc-std-workspace-alloc",
+ "rustc-std-workspace-core",
 ]
 
 [[package]]
@@ -2522,7 +2481,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
 dependencies = [
  "lock_api",
- "parking_lot_core 0.9.3",
+ "parking_lot_core 0.9.4",
 ]
 
 [[package]]
@@ -2541,15 +2500,15 @@ dependencies = [
 
 [[package]]
 name = "parking_lot_core"
-version = "0.9.3"
+version = "0.9.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929"
+checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0"
 dependencies = [
  "cfg-if 1.0.0",
  "libc",
  "redox_syscall",
  "smallvec",
- "windows-sys 0.36.1",
+ "windows-sys 0.42.0",
 ]
 
 [[package]]
@@ -2774,9 +2733,9 @@ dependencies = [
 
 [[package]]
 name = "psm"
-version = "0.1.16"
+version = "0.1.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd136ff4382c4753fc061cb9e4712ab2af263376b95bbd5bd8cd50c020b78e69"
+checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874"
 dependencies = [
  "cc",
 ]
@@ -3305,7 +3264,7 @@ dependencies = [
  "cstr",
  "libc",
  "measureme",
- "object 0.29.0",
+ "object",
  "rustc-demangle",
  "rustc_ast",
  "rustc_attr",
@@ -3339,7 +3298,7 @@ dependencies = [
  "itertools",
  "jobserver",
  "libc",
- "object 0.29.0",
+ "object",
  "pathdiff",
  "regex",
  "rustc_arena",
@@ -4677,9 +4636,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
 
 [[package]]
 name = "stacker"
-version = "0.1.14"
+version = "0.1.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90939d5171a4420b3ff5fbc8954d641e7377335454c259dcb80786f3f21dc9b4"
+checksum = "c886bd4480155fd3ef527d45e9ac8dd7118a898a46530b7b94c3e21866259fce"
 dependencies = [
  "cc",
  "cfg-if 1.0.0",
@@ -4698,7 +4657,7 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
 name = "std"
 version = "0.0.0"
 dependencies = [
- "addr2line 0.16.0",
+ "addr2line",
  "alloc",
  "cfg-if 1.0.0",
  "compiler_builtins",
@@ -4708,8 +4667,8 @@ dependencies = [
  "hashbrown",
  "hermit-abi 0.2.6",
  "libc",
- "miniz_oxide 0.4.0",
- "object 0.26.2",
+ "miniz_oxide",
+ "object",
  "panic_abort",
  "panic_unwind",
  "profiler_builtins",
@@ -4926,9 +4885,9 @@ version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e6cb0c7868d7f90407531108ab03263d9452a8811b7cdd87675343a40d4aa254"
 dependencies = [
- "gimli 0.26.1",
+ "gimli",
  "hashbrown",
- "object 0.29.0",
+ "object",
  "tracing",
 ]
 
@@ -5499,17 +5458,25 @@ dependencies = [
 
 [[package]]
 name = "windows-sys"
-version = "0.36.1"
+version = "0.42.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
+checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
 dependencies = [
- "windows_aarch64_msvc 0.36.1",
- "windows_i686_gnu 0.36.1",
- "windows_i686_msvc 0.36.1",
- "windows_x86_64_gnu 0.36.1",
- "windows_x86_64_msvc 0.36.1",
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc 0.42.0",
+ "windows_i686_gnu 0.42.0",
+ "windows_i686_msvc 0.42.0",
+ "windows_x86_64_gnu 0.42.0",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc 0.42.0",
 ]
 
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
+
 [[package]]
 name = "windows_aarch64_msvc"
 version = "0.28.0"
@@ -5518,9 +5485,9 @@ checksum = "52695a41e536859d5308cc613b4a022261a274390b25bd29dfff4bf08505f3c2"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.36.1"
+version = "0.42.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
+checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
 
 [[package]]
 name = "windows_i686_gnu"
@@ -5530,9 +5497,9 @@ checksum = "f54725ac23affef038fecb177de6c9bf065787c2f432f79e3c373da92f3e1d8a"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.36.1"
+version = "0.42.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
+checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
 
 [[package]]
 name = "windows_i686_msvc"
@@ -5542,9 +5509,9 @@ checksum = "51d5158a43cc43623c0729d1ad6647e62fa384a3d135fd15108d37c683461f64"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.36.1"
+version = "0.42.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
+checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
 
 [[package]]
 name = "windows_x86_64_gnu"
@@ -5554,9 +5521,15 @@ checksum = "bc31f409f565611535130cfe7ee8e6655d3fa99c1c61013981e491921b5ce954"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.36.1"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.42.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
+checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
 
 [[package]]
 name = "windows_x86_64_msvc"
@@ -5566,9 +5539,9 @@ checksum = "3f2b8c7cbd3bfdddd9ab98769f9746a7fad1bca236554cd032b78d768bc0e89f"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.36.1"
+version = "0.42.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
+checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
 
 [[package]]
 name = "xattr"
diff --git a/LICENSES/BSD-2-Clause.txt b/LICENSES/BSD-2-Clause.txt
deleted file mode 100644 (file)
index 5f662b3..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-Copyright (c) <year> <owner> 
-
-Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
index 4ef43735a62c8eac79b0499268553cfd223e91d3..c999b06b0ab2d5b3cc247bb63c94f1596bc061b9 100644 (file)
@@ -1208,7 +1208,7 @@ pub fn precedence(&self) -> ExprPrecedence {
             ExprKind::Tup(_) => ExprPrecedence::Tup,
             ExprKind::Binary(op, ..) => ExprPrecedence::Binary(op.node),
             ExprKind::Unary(..) => ExprPrecedence::Unary,
-            ExprKind::Lit(_) => ExprPrecedence::Lit,
+            ExprKind::Lit(_) | ExprKind::IncludedBytes(..) => ExprPrecedence::Lit,
             ExprKind::Type(..) | ExprKind::Cast(..) => ExprPrecedence::Cast,
             ExprKind::Let(..) => ExprPrecedence::Let,
             ExprKind::If(..) => ExprPrecedence::If,
@@ -1446,6 +1446,12 @@ pub enum ExprKind {
     /// with an optional value to be returned.
     Yeet(Option<P<Expr>>),
 
+    /// Bytes included via `include_bytes!`
+    /// Added for optimization purposes to avoid the need to escape
+    /// large binary blobs - should always behave like [`ExprKind::Lit`]
+    /// with a `ByteStr` literal.
+    IncludedBytes(Lrc<[u8]>),
+
     /// Placeholder for an expression that wasn't syntactically well formed in some way.
     Err,
 }
index eeb7e56e2b12448e3b465fd29cfd6c716a76b468..9c1dfeb1a61428920e20e4ac69f61e9913701094 100644 (file)
@@ -29,6 +29,7 @@
 extern crate tracing;
 
 pub mod util {
+    pub mod case;
     pub mod classify;
     pub mod comments;
     pub mod literal;
index b970e57e0173c444a5dddef1862087d6036c35d9..3ab8267263d116506ba99ab75cc0e7096675dfc6 100644 (file)
@@ -1428,7 +1428,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
         }
         ExprKind::Try(expr) => vis.visit_expr(expr),
         ExprKind::TryBlock(body) => vis.visit_block(body),
-        ExprKind::Lit(_) | ExprKind::Err => {}
+        ExprKind::Lit(_) | ExprKind::IncludedBytes(..) | ExprKind::Err => {}
     }
     vis.visit_id(id);
     vis.visit_span(span);
index 83b10d906e297980ff3b96095bbd1db7a6cd18eb..f6aac0b55f1ab56c391159e517f3dc92f6aa45f0 100644 (file)
@@ -5,6 +5,7 @@
 
 use crate::ast;
 use crate::ptr::P;
+use crate::util::case::Case;
 
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::Lrc;
@@ -615,6 +616,15 @@ pub fn is_keyword(&self, kw: Symbol) -> bool {
         self.is_non_raw_ident_where(|id| id.name == kw)
     }
 
+    /// Returns `true` if the token is a given keyword, `kw` or if `case` is `Insensitive` and this token is an identifier equal to `kw` ignoring the case.
+    pub fn is_keyword_case(&self, kw: Symbol, case: Case) -> bool {
+        self.is_keyword(kw)
+            || (case == Case::Insensitive
+                && self.is_non_raw_ident_where(|id| {
+                    id.name.as_str().to_lowercase() == kw.as_str().to_lowercase()
+                }))
+    }
+
     pub fn is_path_segment_keyword(&self) -> bool {
         self.is_non_raw_ident_where(Ident::is_path_segment_keyword)
     }
diff --git a/compiler/rustc_ast/src/util/case.rs b/compiler/rustc_ast/src/util/case.rs
new file mode 100644 (file)
index 0000000..1afd7de
--- /dev/null
@@ -0,0 +1,6 @@
+/// Whatever to ignore case (`fn` vs `Fn` vs `FN`) or not. Used for recovering.
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub enum Case {
+    Sensitive,
+    Insensitive,
+}
index 536b385606c69c5fa98c91a2c4f23eb4558d6b71..e267f8cd10027d349f8dacb4a8d808cc88df76f9 100644 (file)
@@ -2,12 +2,10 @@
 
 use crate::ast::{self, Lit, LitKind};
 use crate::token::{self, Token};
-
-use rustc_lexer::unescape::{unescape_byte, unescape_char};
-use rustc_lexer::unescape::{unescape_byte_literal, unescape_literal, Mode};
+use rustc_data_structures::sync::Lrc;
+use rustc_lexer::unescape::{byte_from_char, unescape_byte, unescape_char, unescape_literal, Mode};
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::Span;
-
 use std::ascii;
 
 pub enum LitError {
@@ -109,13 +107,11 @@ pub fn from_token_lit(lit: token::Lit) -> Result<LitKind, LitError> {
                 let s = symbol.as_str();
                 let mut buf = Vec::with_capacity(s.len());
                 let mut error = Ok(());
-                unescape_byte_literal(&s, Mode::ByteStr, &mut |_, unescaped_byte| {
-                    match unescaped_byte {
-                        Ok(c) => buf.push(c),
-                        Err(err) => {
-                            if err.is_fatal() {
-                                error = Err(LitError::LexerError);
-                            }
+                unescape_literal(&s, Mode::ByteStr, &mut |_, c| match c {
+                    Ok(c) => buf.push(byte_from_char(c)),
+                    Err(err) => {
+                        if err.is_fatal() {
+                            error = Err(LitError::LexerError);
                         }
                     }
                 });
@@ -127,13 +123,11 @@ pub fn from_token_lit(lit: token::Lit) -> Result<LitKind, LitError> {
                 let bytes = if s.contains('\r') {
                     let mut buf = Vec::with_capacity(s.len());
                     let mut error = Ok(());
-                    unescape_byte_literal(&s, Mode::RawByteStr, &mut |_, unescaped_byte| {
-                        match unescaped_byte {
-                            Ok(c) => buf.push(c),
-                            Err(err) => {
-                                if err.is_fatal() {
-                                    error = Err(LitError::LexerError);
-                                }
+                    unescape_literal(&s, Mode::RawByteStr, &mut |_, c| match c {
+                        Ok(c) => buf.push(byte_from_char(c)),
+                        Err(err) => {
+                            if err.is_fatal() {
+                                error = Err(LitError::LexerError);
                             }
                         }
                     });
@@ -238,6 +232,13 @@ pub fn from_lit_kind(kind: LitKind, span: Span) -> Lit {
         Lit { token_lit: kind.to_token_lit(), kind, span }
     }
 
+    /// Recovers an AST literal from a string of bytes produced by `include_bytes!`.
+    /// This requires ASCII-escaping the string, which can result in poor performance
+    /// for very large strings of bytes.
+    pub fn from_included_bytes(bytes: &Lrc<[u8]>, span: Span) -> Lit {
+        Self::from_lit_kind(LitKind::ByteStr(bytes.clone()), span)
+    }
+
     /// Losslessly convert an AST literal into a token.
     pub fn to_token(&self) -> Token {
         let kind = match self.token_lit.kind {
index 6f56c1ef0e8daa6ff4e5fad425bd1171a51cc4f6..da0545ce80c373f3e94ddd4c4a6c08b70333b2db 100644 (file)
@@ -251,7 +251,7 @@ fn visit_inline_asm_sym(&mut self, sym: &'ast InlineAsmSym) {
 macro_rules! walk_list {
     ($visitor: expr, $method: ident, $list: expr $(, $($extra_args: expr),* )?) => {
         {
-            #[cfg_attr(not(bootstrap), allow(for_loops_over_fallibles))]
+            #[allow(for_loops_over_fallibles)]
             for elem in $list {
                 $visitor.$method(elem $(, $($extra_args,)* )?)
             }
@@ -901,7 +901,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
         }
         ExprKind::Try(ref subexpression) => visitor.visit_expr(subexpression),
         ExprKind::TryBlock(ref body) => visitor.visit_block(body),
-        ExprKind::Lit(_) | ExprKind::Err => {}
+        ExprKind::Lit(_) | ExprKind::IncludedBytes(..) | ExprKind::Err => {}
     }
 
     visitor.visit_expr_post(expression)
index ec9c3935020566aee76eeef1bf82fc9092125762..a4ae493af86bf6a23fc3b0df42d6138c6454e85d 100644 (file)
@@ -87,6 +87,10 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
                 ExprKind::Lit(ref l) => {
                     hir::ExprKind::Lit(respan(self.lower_span(l.span), l.kind.clone()))
                 }
+                ExprKind::IncludedBytes(ref bytes) => hir::ExprKind::Lit(respan(
+                    self.lower_span(e.span),
+                    LitKind::ByteStr(bytes.clone()),
+                )),
                 ExprKind::Cast(ref expr, ref ty) => {
                     let expr = self.lower_expr(expr);
                     let ty =
index 1af1633b5244badd53899e8002d189de5a4bfda3..7fdfc79164b48fba2142824f1b829ace1af07094 100644 (file)
@@ -323,7 +323,10 @@ fn lower_range_end(&mut self, e: &RangeEnd, has_end: bool) -> hir::RangeEnd {
     // ```
     fn lower_expr_within_pat(&mut self, expr: &Expr, allow_paths: bool) -> &'hir hir::Expr<'hir> {
         match expr.kind {
-            ExprKind::Lit(..) | ExprKind::ConstBlock(..) | ExprKind::Err => {}
+            ExprKind::Lit(..)
+            | ExprKind::ConstBlock(..)
+            | ExprKind::IncludedBytes(..)
+            | ExprKind::Err => {}
             ExprKind::Path(..) if allow_paths => {}
             ExprKind::Unary(UnOp::Neg, ref inner) if matches!(inner.kind, ExprKind::Lit(_)) => {}
             _ => {
index bcefa8ce0b9ce6ca8ff078b10e3fb3cc8d722a0d..930276242c3c361f9e72f525348ff09335ba5031 100644 (file)
@@ -322,6 +322,10 @@ pub(super) fn print_expr_outer_attr_style(&mut self, expr: &ast::Expr, is_inline
             ast::ExprKind::Lit(ref lit) => {
                 self.print_literal(lit);
             }
+            ast::ExprKind::IncludedBytes(ref bytes) => {
+                let lit = ast::Lit::from_included_bytes(bytes, expr.span);
+                self.print_literal(&lit)
+            }
             ast::ExprKind::Cast(ref expr, ref ty) => {
                 let prec = AssocOp::As.precedence() as i8;
                 self.print_expr_maybe_paren(expr, prec);
index 41279588e633460af12450b463bfad4f7b3b27ea..563ff056ae467245b67f5bacee32f7c2b5817ff0 100644 (file)
@@ -1,3 +1,5 @@
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
 use crate::nll::ToRegionVid;
 use crate::path_utils::allow_two_phase_borrow;
 use crate::place_ext::PlaceExt;
index 08ea00d71ef9d246620a96d91f16b1afde05dc0c..01be379120dc7483c088daa4005b744bb386dfb8 100644 (file)
@@ -8,9 +8,18 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
     pub(crate) fn cannot_move_when_borrowed(
         &self,
         span: Span,
-        desc: &str,
+        borrow_span: Span,
+        place: &str,
+        borrow_place: &str,
+        value_place: &str,
     ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
-        struct_span_err!(self, span, E0505, "cannot move out of {} because it is borrowed", desc,)
+        self.infcx.tcx.sess.create_err(crate::session_diagnostics::MoveBorrow {
+            place,
+            span,
+            borrow_place,
+            value_place,
+            borrow_span,
+        })
     }
 
     pub(crate) fn cannot_use_when_mutably_borrowed(
index f185e402fc6dee77ea3b749fc9a4400b7d9b5094..11b31c3f14028e72dbe20df6d6e3db3a6ec21f1a 100644 (file)
@@ -1,3 +1,5 @@
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
 use rustc_infer::infer::InferCtxt;
 use rustc_middle::mir::visit::TyContext;
 use rustc_middle::mir::visit::Visitor;
index 9d9c4abb0aa57c460961d9dca8b8478dafbd9f0c..84a93e5f72e9dd3b508782306ea15fc46d653995 100644 (file)
@@ -1,3 +1,6 @@
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
+
 use rustc_data_structures::graph::scc::Sccs;
 use rustc_index::vec::IndexVec;
 use rustc_middle::mir::ConstraintCategory;
index b162095f8a6cdf0692738aaaa1fe3d4205782ca4..86da767f322738fae52365b52cc0366d1b6fe311 100644 (file)
@@ -1,3 +1,5 @@
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
 //! This file provides API for compiler consumers.
 
 use rustc_hir::def_id::LocalDefId;
index 9f7a4d49989ab6b3aeddac712161c6168a120de3..8070c0e6710ee0e1288cb9a0284fab5d47f8617f 100644 (file)
@@ -1,3 +1,5 @@
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
 use rustc_data_structures::fx::FxHashMap;
 use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::{self, BasicBlock, Body, Location, Place};
index a5c0d77429de82d7f0812c58efd06ffbd1d75f77..8e62a0198be46987733c4ad7c0608aff65cc84bf 100644 (file)
@@ -1,3 +1,5 @@
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
 use rustc_middle::mir::visit::{
     MutatingUseContext, NonMutatingUseContext, NonUseContext, PlaceContext,
 };
index dac6abe37f5891d3e3667be00defec2bf8184374..b99bfda1a51fe661c6366505486bca5d9c8f76b8 100644 (file)
@@ -1,3 +1,6 @@
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
+
 use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
 use rustc_infer::infer::canonical::Canonical;
 use rustc_infer::infer::error_reporting::nice_region_error::NiceRegionError;
@@ -158,6 +161,7 @@ fn nice_error(
         error_region: Option<ty::Region<'tcx>>,
     ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>;
 
+    #[instrument(level = "debug", skip(self, mbcx))]
     fn report_error(
         &self,
         mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
@@ -167,6 +171,7 @@ fn report_error(
     ) {
         let tcx = mbcx.infcx.tcx;
         let base_universe = self.base_universe();
+        debug!(?base_universe);
 
         let Some(adjusted_universe) =
             placeholder.universe.as_u32().checked_sub(base_universe.as_u32())
@@ -389,6 +394,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
     )
 }
 
+#[instrument(level = "debug", skip(infcx, region_var_origin, universe_of_region))]
 fn try_extract_error_from_region_constraints<'tcx>(
     infcx: &InferCtxt<'tcx>,
     placeholder_region: ty::Region<'tcx>,
index 8987a51757cd50ff2fa23fc72aba03839c4d4d59..9e0aa57b2553fba87dfbab9ef2f19689da0a12ce 100644 (file)
@@ -224,10 +224,7 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
                 }
             }
 
-            use_spans.var_span_label_path_only(
-                &mut err,
-                format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()),
-            );
+            use_spans.var_path_only_subdiag(&mut err, desired_action);
 
             if !is_loop_move {
                 err.span_label(
@@ -404,10 +401,7 @@ fn report_use_of_uninitialized(
         let used = desired_action.as_general_verb_in_past_tense();
         let mut err =
             struct_span_err!(self, span, E0381, "{used} binding {desc}{isnt_initialized}");
-        use_spans.var_span_label_path_only(
-            &mut err,
-            format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()),
-        );
+        use_spans.var_path_only_subdiag(&mut err, desired_action);
 
         if let InitializationRequiringAction::PartialAssignment
         | InitializationRequiringAction::Assignment = desired_action
@@ -673,16 +667,16 @@ pub(crate) fn report_move_out_while_borrowed(
         let move_spans = self.move_spans(place.as_ref(), location);
         let span = move_spans.args_or_use();
 
-        let mut err =
-            self.cannot_move_when_borrowed(span, &self.describe_any_place(place.as_ref()));
-        err.span_label(borrow_span, format!("borrow of {} occurs here", borrow_msg));
-        err.span_label(span, format!("move out of {} occurs here", value_msg));
-
-        borrow_spans.var_span_label_path_only(
-            &mut err,
-            format!("borrow occurs due to use{}", borrow_spans.describe()),
+        let mut err = self.cannot_move_when_borrowed(
+            span,
+            borrow_span,
+            &self.describe_any_place(place.as_ref()),
+            &borrow_msg,
+            &value_msg,
         );
 
+        borrow_spans.var_path_only_subdiag(&mut err, crate::InitializationRequiringAction::Borrow);
+
         move_spans.var_span_label(
             &mut err,
             format!("move occurs due to use{}", move_spans.describe()),
@@ -724,16 +718,15 @@ pub(crate) fn report_use_while_mutably_borrowed(
             borrow_span,
             &self.describe_any_place(borrow.borrowed_place.as_ref()),
         );
-
-        borrow_spans.var_span_label(
-            &mut err,
-            {
-                let place = &borrow.borrowed_place;
-                let desc_place = self.describe_any_place(place.as_ref());
-                format!("borrow occurs due to use of {}{}", desc_place, borrow_spans.describe())
-            },
-            "mutable",
-        );
+        borrow_spans.var_subdiag(&mut err, Some(borrow.kind), |kind, var_span| {
+            use crate::session_diagnostics::CaptureVarCause::*;
+            let place = &borrow.borrowed_place;
+            let desc_place = self.describe_any_place(place.as_ref());
+            match kind {
+                Some(_) => BorrowUsePlaceGenerator { place: desc_place, var_span },
+                None => BorrowUsePlaceClosure { place: desc_place, var_span },
+            }
+        });
 
         self.explain_why_borrow_contains_point(location, borrow, None)
             .add_explanation_to_diagnostic(
@@ -1551,7 +1544,7 @@ fn report_temporary_value_does_not_live_long_enough(
         }
 
         let mut err = self.temporary_value_borrowed_for_too_long(proper_span);
-        err.span_label(proper_span, "creates a temporary which is freed while still in use");
+        err.span_label(proper_span, "creates a temporary value which is freed while still in use");
         err.span_label(drop_span, "temporary value is freed at the end of this statement");
 
         match explanation {
index b3edc35dc3642cc7c5963bcec53782801dd22656..498e9834354b7ff851da549230f7b2707ef43c28 100644 (file)
@@ -1,3 +1,6 @@
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
+
 use std::collections::BTreeSet;
 
 use rustc_middle::mir::visit::{PlaceContext, Visitor};
index b5a3081e56a7a50f9899603b8b2797fef13c1bb9..15f42e26cbf4a7aeca1bac947ac0b58b4836c3aa 100644 (file)
@@ -1,3 +1,6 @@
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
+
 use std::collections::VecDeque;
 use std::rc::Rc;
 
index 534d9ecae6e6f0788d336bc7ac8b03110cc02482..7f26af67c71b214485777b90ea0e97029650bafb 100644 (file)
@@ -595,11 +595,34 @@ pub(super) fn args_span_label(self, err: &mut Diagnostic, message: impl Into<Str
         }
     }
 
-    // Add a span label to the use of the captured variable, if it exists.
-    // only adds label to the `path_span`
-    pub(super) fn var_span_label_path_only(self, err: &mut Diagnostic, message: impl Into<String>) {
-        if let UseSpans::ClosureUse { path_span, .. } = self {
-            err.span_label(path_span, message);
+    /// Add a span label to the use of the captured variable, if it exists.
+    /// only adds label to the `path_span`
+    pub(super) fn var_path_only_subdiag(
+        self,
+        err: &mut Diagnostic,
+        action: crate::InitializationRequiringAction,
+    ) {
+        use crate::session_diagnostics::CaptureVarPathUseCause::*;
+        use crate::InitializationRequiringAction::*;
+        if let UseSpans::ClosureUse { generator_kind, path_span, .. } = self {
+            match generator_kind {
+                Some(_) => {
+                    err.subdiagnostic(match action {
+                        Borrow => BorrowInGenerator { path_span },
+                        MatchOn | Use => UseInGenerator { path_span },
+                        Assignment => AssignInGenerator { path_span },
+                        PartialAssignment => AssignPartInGenerator { path_span },
+                    });
+                }
+                None => {
+                    err.subdiagnostic(match action {
+                        Borrow => BorrowInClosure { path_span },
+                        MatchOn | Use => UseInClosure { path_span },
+                        Assignment => AssignInClosure { path_span },
+                        PartialAssignment => AssignPartInClosure { path_span },
+                    });
+                }
+            }
         }
     }
 
@@ -623,6 +646,35 @@ pub(super) fn var_span_label(
         }
     }
 
+    /// Add a subdiagnostic to the use of the captured variable, if it exists.
+    pub(super) fn var_subdiag(
+        self,
+        err: &mut Diagnostic,
+        kind: Option<rustc_middle::mir::BorrowKind>,
+        f: impl Fn(Option<GeneratorKind>, Span) -> crate::session_diagnostics::CaptureVarCause,
+    ) {
+        use crate::session_diagnostics::CaptureVarKind::*;
+        if let UseSpans::ClosureUse { generator_kind, capture_kind_span, path_span, .. } = self {
+            if capture_kind_span != path_span {
+                err.subdiagnostic(match kind {
+                    Some(kd) => match kd {
+                        rustc_middle::mir::BorrowKind::Shared
+                        | rustc_middle::mir::BorrowKind::Shallow
+                        | rustc_middle::mir::BorrowKind::Unique => {
+                            Immute { kind_span: capture_kind_span }
+                        }
+
+                        rustc_middle::mir::BorrowKind::Mut { .. } => {
+                            Mut { kind_span: capture_kind_span }
+                        }
+                    },
+                    None => Move { kind_span: capture_kind_span },
+                });
+            };
+            err.subdiagnostic(f(generator_kind, path_span));
+        }
+    }
+
     /// Returns `false` if this place is not used in a closure.
     pub(super) fn for_closure(&self) -> bool {
         match *self {
index 8ad40c0aa0a5d032f3e2f5b9af56a6ee3cacc189..7457369aa58cb42bad748f68492f6d9c79462e88 100644 (file)
@@ -1,6 +1,4 @@
-use rustc_errors::{
-    Applicability, Diagnostic, DiagnosticBuilder, EmissionGuarantee, ErrorGuaranteed,
-};
+use rustc_errors::{Applicability, Diagnostic};
 use rustc_hir as hir;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::Node;
@@ -629,25 +627,20 @@ pub(crate) fn report_mutability_error(
         self.buffer_error(err);
     }
 
-    fn suggest_map_index_mut_alternatives(
-        &self,
-        ty: Ty<'_>,
-        err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
-        span: Span,
-    ) {
+    fn suggest_map_index_mut_alternatives(&self, ty: Ty<'tcx>, err: &mut Diagnostic, span: Span) {
         let Some(adt) = ty.ty_adt_def() else { return };
         let did = adt.did();
         if self.infcx.tcx.is_diagnostic_item(sym::HashMap, did)
             || self.infcx.tcx.is_diagnostic_item(sym::BTreeMap, did)
         {
-            struct V<'a, 'b, 'tcx, G: EmissionGuarantee> {
+            struct V<'a, 'tcx> {
                 assign_span: Span,
-                err: &'a mut DiagnosticBuilder<'b, G>,
+                err: &'a mut Diagnostic,
                 ty: Ty<'tcx>,
                 suggested: bool,
             }
-            impl<'a, 'b: 'a, 'hir, 'tcx, G: EmissionGuarantee> Visitor<'hir> for V<'a, 'b, 'tcx, G> {
-                fn visit_stmt(&mut self, stmt: &'hir hir::Stmt<'hir>) {
+            impl<'a, 'tcx> Visitor<'tcx> for V<'a, 'tcx> {
+                fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) {
                     hir::intravisit::walk_stmt(self, stmt);
                     let expr = match stmt.kind {
                         hir::StmtKind::Semi(expr) | hir::StmtKind::Expr(expr) => expr,
@@ -705,7 +698,7 @@ fn visit_stmt(&mut self, stmt: &'hir hir::Stmt<'hir>) {
                                     ),
                                     (rv.span.shrink_to_hi(), ")".to_string()),
                                 ],
-                            ].into_iter(),
+                            ],
                             Applicability::MachineApplicable,
                         );
                         self.suggested = true;
index 196ddbe8d5046696ad2e1756d1a89acc3dda9598..76f249dac5181439f4a437402e0d0aa68a38eb0a 100644 (file)
@@ -2,7 +2,7 @@
 #![deny(rustc::diagnostic_outside_of_impl)]
 //! Error reporting machinery for lifetime errors.
 
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan};
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
@@ -276,7 +276,7 @@ pub(crate) fn report_region_errors(&mut self, nll_errors: RegionErrors<'tcx>) {
     fn get_impl_ident_and_self_ty_from_trait(
         &self,
         def_id: DefId,
-        trait_objects: &FxHashSet<DefId>,
+        trait_objects: &FxIndexSet<DefId>,
     ) -> Option<(Ident, &'tcx hir::Ty<'tcx>)> {
         let tcx = self.infcx.tcx;
         match tcx.hir().get_if_local(def_id) {
@@ -830,7 +830,7 @@ fn maybe_suggest_constrain_dyn_trait_impl(
         };
         debug!(?param);
 
-        let mut visitor = TraitObjectVisitor(FxHashSet::default());
+        let mut visitor = TraitObjectVisitor(FxIndexSet::default());
         visitor.visit_ty(param.param_ty);
 
         let Some((ident, self_ty)) =
@@ -843,7 +843,7 @@ fn maybe_suggest_constrain_dyn_trait_impl(
     fn suggest_constrain_dyn_trait_in_impl(
         &self,
         err: &mut Diagnostic,
-        found_dids: &FxHashSet<DefId>,
+        found_dids: &FxIndexSet<DefId>,
         ident: Ident,
         self_ty: &hir::Ty<'_>,
     ) -> bool {
index c044dbaba47e2faab5170228d73bd7c571302c0d..f9741bacd17028bf46d0d7f04a9c61f7b8feca6a 100644 (file)
@@ -355,7 +355,7 @@ fn give_name_from_error_region(&self, fr: RegionVid) -> Option<RegionName> {
                     })
                 }
 
-                ty::BoundRegionKind::BrAnon(_) => None,
+                ty::BoundRegionKind::BrAnon(..) => None,
             },
 
             ty::ReLateBound(..) | ty::ReVar(..) | ty::RePlaceholder(..) | ty::ReErased => None,
index 9ba29f04b1a9aa4cffc27b0ea8539bb3cd3098d9..b385f95b67c6f992a12841c02b77b7bed01b8f35 100644 (file)
@@ -1,3 +1,6 @@
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
+
 use crate::Upvar;
 use crate::{nll::ToRegionVid, region_infer::RegionInferenceContext};
 use rustc_index::vec::{Idx, IndexVec};
index 22134d5a71ce119fae2437214c056c223fcd4c47..51ed27c167d3844971e445036bb0a4584524e210 100644 (file)
@@ -1,3 +1,5 @@
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
 use crate::location::{LocationIndex, LocationTable};
 use crate::BorrowIndex;
 use polonius_engine::AllFacts as PoloniusFacts;
index 3157f861d93bec9fc047fd81d750d218d2248f7b..f5317a143aed7157d0801da0e688c7bd7a090246 100644 (file)
@@ -1,3 +1,5 @@
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
 use rustc_data_structures::graph::dominators::Dominators;
 use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::{self, BasicBlock, Body, Location, NonDivergingIntrinsic, Place, Rvalue};
index abfe253d43df7edbf41cfdbba0e7c3bd474a56ae..4a4887f19702f91149c053108308eaf0333c77d0 100644 (file)
@@ -18,6 +18,7 @@
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::graph::dominators::Dominators;
+use rustc_data_structures::vec_map::VecMap;
 use rustc_errors::{Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
@@ -129,6 +130,19 @@ fn mir_borrowck<'tcx>(
 ) -> &'tcx BorrowCheckResult<'tcx> {
     let (input_body, promoted) = tcx.mir_promoted(def);
     debug!("run query mir_borrowck: {}", tcx.def_path_str(def.did.to_def_id()));
+
+    if input_body.borrow().should_skip() {
+        debug!("Skipping borrowck because of injected body");
+        // Let's make up a borrowck result! Fun times!
+        let result = BorrowCheckResult {
+            concrete_opaque_types: VecMap::new(),
+            closure_requirements: None,
+            used_mut_upvars: SmallVec::new(),
+            tainted_by_errors: None,
+        };
+        return tcx.arena.alloc(result);
+    }
+
     let hir_owner = tcx.hir().local_def_id_to_hir_id(def.did).owner;
 
     let infcx =
index 877944d3d70cb961195ac89e926ca12a39ef2467..9fa7e218b1b6f65ceb09a92420043f5f823f41f1 100644 (file)
@@ -1,3 +1,5 @@
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_middle::mir::{BasicBlock, Body, Location};
 
index 43253a2aab00cfdd52515ff260643c096acda344..b48f9f97daad8d76dc07b541f445206f55fa7e8c 100644 (file)
@@ -1,3 +1,5 @@
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_index::vec::IndexVec;
index 4e0205f8d43a14616d40ebb23361979b907bbd8f..f8856b56d140bae139a7d069159b8bb813b28dd6 100644 (file)
@@ -1,3 +1,5 @@
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
 //! The entry point of the NLL borrow checker.
 
 use rustc_data_structures::vec_map::VecMap;
index b2c8dfc82c206a05a098114c65f05c93756b345c..f8a99a2699e6ff0cf3c89c3c62ab576f6278e72c 100644 (file)
@@ -1,3 +1,5 @@
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
 use crate::borrow_set::{BorrowData, BorrowSet, TwoPhaseActivation};
 use crate::places_conflict;
 use crate::AccessDepth;
index 93d202e49a159fc4173a852ce879d0941e3d16de..9f6b1fdfcb54085853bb49c34a070b95c3358ec7 100644 (file)
@@ -1,3 +1,5 @@
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
 use crate::borrow_set::LocalsStateAtExit;
 use rustc_hir as hir;
 use rustc_middle::mir::ProjectionElem;
index 0e71efd6f8d3e2ffc79b59bb06610ace769fa066..8a87d1972ebf35613c8673285a0e43880112a666 100644 (file)
@@ -1,3 +1,5 @@
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
 use crate::ArtificialField;
 use crate::Overlap;
 use crate::{AccessDepth, Deep, Shallow};
index 2b50cbac9a02da128786fa86e3ed5d80dcfa8b44..6f281349863763f0cbb578f0a93102ef6ec19b81 100644 (file)
@@ -1,3 +1,5 @@
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
 //! From the NLL RFC: "The deep [aka 'supporting'] prefixes for an
 //! place are formed by stripping away fields and derefs, except that
 //! we stop when we reach the deref of a shared reference. [...] "
index cc9450999525a9550be1ebdc942ec12270cdc0cd..6524b594e44dc02083d629688966c151ae0965c5 100644 (file)
@@ -1,3 +1,5 @@
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
 //! As part of generating the regions, if you enable `-Zdump-mir=nll`,
 //! we will generate an annotated copy of the MIR that includes the
 //! state of region inference. This code handles emitting the region
index f31ccd74ca6f72b198346dfcd908fa6e4ba8c057..2e15586e03b3bb49ec35331d11cdeaa9d9026b25 100644 (file)
@@ -1,3 +1,5 @@
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
 //! This module provides linkage between RegionInferenceContext and
 //! `rustc_graphviz` traits, specialized to attaching borrowck analysis
 //! data to rendered labels.
index 95ea42b584a3a6d502798fb28467597764193927..dd222485daf2c01b3188ff5abaa564065fa69246 100644 (file)
@@ -299,8 +299,8 @@ fn infer_opaque_definition_from_instantiation(
         if errors.is_empty() {
             definition_ty
         } else {
-            infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
-            self.tcx.ty_error()
+            let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
+            self.tcx.ty_error_with_guaranteed(reported)
         }
     }
 }
index 1e6798eee3df8b056cf4379d05c8e294f2e54df7..167f664609698e8b26011e134c887d85855f7e79 100644 (file)
@@ -1,3 +1,5 @@
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
 use crate::constraints::ConstraintSccIndex;
 use crate::RegionInferenceContext;
 use itertools::Itertools;
index de20a4bb465c207c6e77a6b4c47280b8c822e3d1..7498ddccf196a1fc136f07cac6e20768c606ce60 100644 (file)
@@ -1,3 +1,5 @@
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_index::bit_set::SparseBitMatrix;
 use rustc_index::interval::IntervalSet;
index f3023769081f205777cd4a238ae3cf31d24d4755..084754830bdbfa8dda894e2f0621e6dd7ebe575d 100644 (file)
@@ -1,3 +1,5 @@
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
 use rustc_index::vec::IndexVec;
 use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
 use rustc_middle::mir::visit::{MutVisitor, TyContext};
index fe24f85fae10a53545d1f0183f0326bb1381b632..577332c0744b84dd8447af7ab3519a33ef18abe0 100644 (file)
@@ -148,3 +148,95 @@ pub(crate) enum RequireStaticErr {
         multi_span: MultiSpan,
     },
 }
+
+#[derive(Subdiagnostic)]
+pub(crate) enum CaptureVarPathUseCause {
+    #[label(borrowck_borrow_due_to_use_generator)]
+    BorrowInGenerator {
+        #[primary_span]
+        path_span: Span,
+    },
+    #[label(borrowck_use_due_to_use_generator)]
+    UseInGenerator {
+        #[primary_span]
+        path_span: Span,
+    },
+    #[label(borrowck_assign_due_to_use_generator)]
+    AssignInGenerator {
+        #[primary_span]
+        path_span: Span,
+    },
+    #[label(borrowck_assign_part_due_to_use_generator)]
+    AssignPartInGenerator {
+        #[primary_span]
+        path_span: Span,
+    },
+    #[label(borrowck_borrow_due_to_use_closure)]
+    BorrowInClosure {
+        #[primary_span]
+        path_span: Span,
+    },
+    #[label(borrowck_use_due_to_use_closure)]
+    UseInClosure {
+        #[primary_span]
+        path_span: Span,
+    },
+    #[label(borrowck_assign_due_to_use_closure)]
+    AssignInClosure {
+        #[primary_span]
+        path_span: Span,
+    },
+    #[label(borrowck_assign_part_due_to_use_closure)]
+    AssignPartInClosure {
+        #[primary_span]
+        path_span: Span,
+    },
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum CaptureVarKind {
+    #[label(borrowck_capture_immute)]
+    Immute {
+        #[primary_span]
+        kind_span: Span,
+    },
+    #[label(borrowck_capture_mut)]
+    Mut {
+        #[primary_span]
+        kind_span: Span,
+    },
+    #[label(borrowck_capture_move)]
+    Move {
+        #[primary_span]
+        kind_span: Span,
+    },
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum CaptureVarCause {
+    #[label(borrowck_var_borrow_by_use_place_in_generator)]
+    BorrowUsePlaceGenerator {
+        place: String,
+        #[primary_span]
+        var_span: Span,
+    },
+    #[label(borrowck_var_borrow_by_use_place_in_closure)]
+    BorrowUsePlaceClosure {
+        place: String,
+        #[primary_span]
+        var_span: Span,
+    },
+}
+
+#[derive(Diagnostic)]
+#[diag(borrowck_cannot_move_when_borrowed, code = "E0505")]
+pub(crate) struct MoveBorrow<'a> {
+    pub place: &'a str,
+    pub borrow_place: &'a str,
+    pub value_place: &'a str,
+    #[primary_span]
+    #[label(move_label)]
+    pub span: Span,
+    #[label]
+    pub borrow_span: Span,
+}
index 02909592637d8cb1c3bed880cf79b8fdf8a2224a..14cfc3613bf0c890357dc20e8e4d4db2846f41aa 100644 (file)
@@ -247,12 +247,13 @@ pub(crate) fn create(mut self) -> CreateResult<'tcx> {
                     .and(type_op::normalize::Normalize::new(ty))
                     .fully_perform(self.infcx)
                     .unwrap_or_else(|_| {
-                        self.infcx
+                        let reported = self
+                            .infcx
                             .tcx
                             .sess
                             .delay_span_bug(span, &format!("failed to normalize {:?}", ty));
                         TypeOpOutput {
-                            output: self.infcx.tcx.ty_error(),
+                            output: self.infcx.tcx.ty_error_with_guaranteed(reported),
                             constraints: None,
                             error_info: None,
                         }
index 50af229baaaedf297abc0ab836c3a655b6fbdb7c..6ccc29b09c0a5d9646acb03f130f29ec579530a0 100644 (file)
@@ -1,3 +1,5 @@
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
 //! This pass type-checks the MIR to ensure it is not broken.
 
 use std::rc::Rc;
@@ -233,11 +235,11 @@ pub(crate) fn type_check<'mir, 'tcx>(
             let mut hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type);
             trace!("finalized opaque type {:?} to {:#?}", opaque_type_key, hidden_type.ty.kind());
             if hidden_type.has_non_region_infer() {
-                infcx.tcx.sess.delay_span_bug(
+                let reported = infcx.tcx.sess.delay_span_bug(
                     decl.hidden_type.span,
                     &format!("could not resolve {:#?}", hidden_type.ty.kind()),
                 );
-                hidden_type.ty = infcx.tcx.ty_error();
+                hidden_type.ty = infcx.tcx.ty_error_with_guaranteed(reported);
             }
 
             (opaque_type_key, (hidden_type, decl.origin))
index 8833753b12c5d53da2c6b77ce1386999bbb97d4f..e297b1230ea0c58b2bf273cc8dbf886c9e495cb4 100644 (file)
@@ -1,3 +1,5 @@
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
 use rustc_data_structures::fx::FxHashSet;
 use rustc_middle::mir::visit::{PlaceContext, Visitor};
 use rustc_middle::mir::{
index bb6839360262af885d807408c1a2d7ed4cdb78d5..f72cd14bea0436e574a7a0f90ee26af58552fe72 100644 (file)
@@ -303,6 +303,7 @@ fn manage_cond_expr(&mut self, expr: &mut P<Expr>) {
             | ExprKind::Field(_, _)
             | ExprKind::ForLoop(_, _, _, _)
             | ExprKind::If(_, _, _)
+            | ExprKind::IncludedBytes(..)
             | ExprKind::InlineAsm(_)
             | ExprKind::Let(_, _, _)
             | ExprKind::Lit(_)
index cb5359dd1e27e6b6bfc9c58337ccf0c07ce5b417..86df3c44eb334e7b51aa65ad268417f170162c4b 100644 (file)
@@ -34,6 +34,7 @@ fn expand(
         span: Span,
         meta_item: &ast::MetaItem,
         item: Annotatable,
+        _is_derive_const: bool,
     ) -> ExpandResult<Vec<Annotatable>, Annotatable> {
         let template = AttributeTemplate { list: Some("path"), ..Default::default() };
         let attr = &ecx.attribute(meta_item.clone());
index 41f4e8c234d5adc004c8a44710e238fb89494cdd..01454d0e98e699cc14096654cc5c50ebd780f0d9 100644 (file)
@@ -43,6 +43,9 @@ pub fn expand_concat(
                     has_errors = true;
                 }
             },
+            ast::ExprKind::IncludedBytes(..) => {
+                cx.span_err(e.span, "cannot concatenate a byte string literal")
+            }
             ast::ExprKind::Err => {
                 has_errors = true;
             }
index 66e86bf2182672e0453f24aa3837623ea1a43b72..4886ca786a588bc5de61de819a1f49e4884bb25e 100644 (file)
@@ -108,6 +108,16 @@ fn handle_array_element(
                 None
             }
         },
+        ast::ExprKind::IncludedBytes(..) => {
+            if !*has_errors {
+                cx.struct_span_err(expr.span, "cannot concatenate doubly nested array")
+                    .note("byte strings are treated as arrays of bytes")
+                    .help("try flattening the array")
+                    .emit();
+            }
+            *has_errors = true;
+            None
+        }
         _ => {
             missing_literals.push(expr.span);
             None
@@ -167,6 +177,9 @@ pub fn expand_concat_bytes(
                     has_errors = true;
                 }
             },
+            ast::ExprKind::IncludedBytes(ref bytes) => {
+                accumulator.extend_from_slice(bytes);
+            }
             ast::ExprKind::Err => {
                 has_errors = true;
             }
index e0fb7affb3498438de838549ceba3624654f3cd6..01f237e6ab5fa3d085a9b1e09ab103bc31e97dc9 100644 (file)
@@ -10,7 +10,7 @@
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
 
-pub(crate) struct Expander;
+pub(crate) struct Expander(pub bool);
 
 impl MultiItemModifier for Expander {
     fn expand(
@@ -19,6 +19,7 @@ fn expand(
         span: Span,
         meta_item: &ast::MetaItem,
         item: Annotatable,
+        _: bool,
     ) -> ExpandResult<Vec<Annotatable>, Annotatable> {
         let sess = ecx.sess;
         if report_bad_target(sess, &item, span) {
@@ -58,20 +59,20 @@ fn expand(
                         report_path_args(sess, &meta);
                         meta.path
                     })
-                    .map(|path| (path, dummy_annotatable(), None))
+                    .map(|path| (path, dummy_annotatable(), None, self.0))
                     .collect();
 
                 // Do not configure or clone items unless necessary.
                 match &mut resolutions[..] {
                     [] => {}
-                    [(_, first_item, _), others @ ..] => {
+                    [(_, first_item, ..), others @ ..] => {
                         *first_item = cfg_eval(
                             sess,
                             features,
                             item.clone(),
                             ecx.current_expansion.lint_node_id,
                         );
-                        for (_, item, _) in others {
+                        for (_, item, _, _) in others {
                             *item = first_item.clone();
                         }
                     }
index 7bd344467d03213130aa32ae46fad4f47875d853..345db700298a81813d544b00197b4a89b1daba3f 100644 (file)
@@ -12,6 +12,7 @@ pub fn expand_deriving_copy(
     mitem: &MetaItem,
     item: &Annotatable,
     push: &mut dyn FnMut(Annotatable),
+    is_const: bool,
 ) {
     let trait_def = TraitDef {
         span,
@@ -22,6 +23,7 @@ pub fn expand_deriving_copy(
         supports_unions: true,
         methods: Vec::new(),
         associated_types: Vec::new(),
+        is_const,
     };
 
     trait_def.expand(cx, mitem, item, push);
index fa8685f5f4e5650882fa957c2368faa80e0abc0e..55cbb65472328bd88554fb009226f98cb14a8829 100644 (file)
@@ -14,6 +14,7 @@ pub fn expand_deriving_clone(
     mitem: &MetaItem,
     item: &Annotatable,
     push: &mut dyn FnMut(Annotatable),
+    is_const: bool,
 ) {
     // The simple form is `fn clone(&self) -> Self { *self }`, possibly with
     // some additional `AssertParamIsClone` assertions.
@@ -87,6 +88,7 @@ pub fn expand_deriving_clone(
             combine_substructure: substructure,
         }],
         associated_types: Vec::new(),
+        is_const,
     };
 
     trait_def.expand_ext(cx, mitem, item, push, is_simple)
index eab67b0d354cf7dd18be1b785c514c4debe47517..6190b7a8c779eb385bc4db2b7c05b4b8bd815c03 100644 (file)
@@ -15,6 +15,7 @@ pub fn expand_deriving_eq(
     mitem: &MetaItem,
     item: &Annotatable,
     push: &mut dyn FnMut(Annotatable),
+    is_const: bool,
 ) {
     let span = cx.with_def_site_ctxt(span);
     let inline = cx.meta_word(span, sym::inline);
@@ -42,6 +43,7 @@ pub fn expand_deriving_eq(
             })),
         }],
         associated_types: Vec::new(),
+        is_const,
     };
 
     super::inject_impl_of_structural_trait(cx, span, item, path_std!(marker::StructuralEq), push);
index 7f117981a9a2fe73fdece52da04079838e815e0f..d2412b20a09c80d251d1aeaf90cd2b39a62bd2ed 100644 (file)
@@ -13,6 +13,7 @@ pub fn expand_deriving_ord(
     mitem: &MetaItem,
     item: &Annotatable,
     push: &mut dyn FnMut(Annotatable),
+    is_const: bool,
 ) {
     let inline = cx.meta_word(span, sym::inline);
     let attrs = thin_vec![cx.attribute(inline)];
@@ -34,6 +35,7 @@ pub fn expand_deriving_ord(
             combine_substructure: combine_substructure(Box::new(|a, b, c| cs_cmp(a, b, c))),
         }],
         associated_types: Vec::new(),
+        is_const,
     };
 
     trait_def.expand(cx, mitem, item, push)
index 236cbccaf9fee6286494c1bfc08173c01f04716f..353f28fc45fb70f59cebb83084b7e1e02e5443eb 100644 (file)
@@ -14,6 +14,7 @@ pub fn expand_deriving_partial_eq(
     mitem: &MetaItem,
     item: &Annotatable,
     push: &mut dyn FnMut(Annotatable),
+    is_const: bool,
 ) {
     fn cs_eq(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
         let base = true;
@@ -89,6 +90,7 @@ fn cs_eq(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOr
         supports_unions: false,
         methods,
         associated_types: Vec::new(),
+        is_const,
     };
     trait_def.expand(cx, mitem, item, push)
 }
index 4173403a1b84a4f4007d77aae5376ffc3e63a109..e7458b23ef3879e62332d938ee655b2da0d5c75f 100644 (file)
@@ -13,6 +13,7 @@ pub fn expand_deriving_partial_ord(
     mitem: &MetaItem,
     item: &Annotatable,
     push: &mut dyn FnMut(Annotatable),
+    is_const: bool,
 ) {
     let ordering_ty = Path(path_std!(cmp::Ordering));
     let ret_ty =
@@ -43,6 +44,7 @@ pub fn expand_deriving_partial_ord(
         supports_unions: false,
         methods: vec![partial_cmp_def],
         associated_types: Vec::new(),
+        is_const,
     };
     trait_def.expand(cx, mitem, item, push)
 }
index 2cf614ed9476c9435b50d7aaced16f097bb3cc39..e6d5759bb5210dd99ef6aecf2eba1d71f6a6bad4 100644 (file)
@@ -13,6 +13,7 @@ pub fn expand_deriving_debug(
     mitem: &MetaItem,
     item: &Annotatable,
     push: &mut dyn FnMut(Annotatable),
+    is_const: bool,
 ) {
     // &mut ::std::fmt::Formatter
     let fmtr = Ref(Box::new(Path(path_std!(fmt::Formatter))), ast::Mutability::Mut);
@@ -37,6 +38,7 @@ pub fn expand_deriving_debug(
             })),
         }],
         associated_types: Vec::new(),
+        is_const,
     };
     trait_def.expand(cx, mitem, item, push)
 }
index d669f616802feda4bf06d489b3eaf7966977dd1a..37aa665e5c607e26ed86b9440fc8b31720d1551d 100644 (file)
@@ -16,6 +16,7 @@ pub fn expand_deriving_rustc_decodable(
     mitem: &MetaItem,
     item: &Annotatable,
     push: &mut dyn FnMut(Annotatable),
+    is_const: bool,
 ) {
     let krate = sym::rustc_serialize;
     let typaram = sym::__D;
@@ -55,6 +56,7 @@ pub fn expand_deriving_rustc_decodable(
             })),
         }],
         associated_types: Vec::new(),
+        is_const,
     };
 
     trait_def.expand(cx, mitem, item, push)
index 17df9fb279ad6b808e57840c5d417e1639d8a144..234957ab8a16b7ea1e76ef2b7f8fa4849db5db8a 100644 (file)
@@ -16,6 +16,7 @@ pub fn expand_deriving_default(
     mitem: &ast::MetaItem,
     item: &Annotatable,
     push: &mut dyn FnMut(Annotatable),
+    is_const: bool,
 ) {
     item.visit_with(&mut DetectNonVariantDefaultAttr { cx });
 
@@ -47,6 +48,7 @@ pub fn expand_deriving_default(
             })),
         }],
         associated_types: Vec::new(),
+        is_const,
     };
     trait_def.expand(cx, mitem, item, push)
 }
index f83f58b97d38ffb3566af5ad883ca3984e69b2aa..baacaa8b979e184906b2f0f593266ca4c2e7fac6 100644 (file)
@@ -100,6 +100,7 @@ pub fn expand_deriving_rustc_encodable(
     mitem: &MetaItem,
     item: &Annotatable,
     push: &mut dyn FnMut(Annotatable),
+    is_const: bool,
 ) {
     let krate = sym::rustc_serialize;
     let typaram = sym::__S;
@@ -139,6 +140,7 @@ pub fn expand_deriving_rustc_encodable(
             })),
         }],
         associated_types: Vec::new(),
+        is_const,
     };
 
     trait_def.expand(cx, mitem, item, push)
index 16ee3aa89bb1237967b3a7a16e2c65bd447ca8de..3972c3b493410b277991d12cea7fa45c16de51ff 100644 (file)
 use rustc_attr as attr;
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::Span;
+use rustc_span::{Span, DUMMY_SP};
 use std::cell::RefCell;
 use std::iter;
 use std::ops::Not;
@@ -204,6 +204,8 @@ pub struct TraitDef<'a> {
     pub methods: Vec<MethodDef<'a>>,
 
     pub associated_types: Vec<(Ident, Ty)>,
+
+    pub is_const: bool,
 }
 
 pub struct MethodDef<'a> {
@@ -730,7 +732,7 @@ fn create_derived_impl(
                 unsafety: ast::Unsafe::No,
                 polarity: ast::ImplPolarity::Positive,
                 defaultness: ast::Defaultness::Final,
-                constness: ast::Const::No,
+                constness: if self.is_const { ast::Const::Yes(DUMMY_SP) } else { ast::Const::No },
                 generics: trait_generics,
                 of_trait: opt_trait_ref,
                 self_ty: self_type,
index 6e9d5f08b9443dd22cc0ec40d828e6070306f405..8fb1a4ba262abda904460b7bf5b290d86c99c105 100644 (file)
@@ -13,6 +13,7 @@ pub fn expand_deriving_hash(
     mitem: &MetaItem,
     item: &Annotatable,
     push: &mut dyn FnMut(Annotatable),
+    is_const: bool,
 ) {
     let path = Path::new_(pathvec_std!(hash::Hash), vec![], PathKind::Std);
 
@@ -39,6 +40,7 @@ pub fn expand_deriving_hash(
             })),
         }],
         associated_types: Vec::new(),
+        is_const,
     };
 
     hash_trait_def.expand(cx, mitem, item, push);
index ee346047a0bc0c2fb54b7ef50bedd1f9e8ac2a01..73a1df5d426d264fdb5ad7a1d008c2a575418449 100644 (file)
 
 pub mod generic;
 
-pub(crate) struct BuiltinDerive(
-    pub(crate) fn(&mut ExtCtxt<'_>, Span, &MetaItem, &Annotatable, &mut dyn FnMut(Annotatable)),
-);
+pub(crate) type BuiltinDeriveFn =
+    fn(&mut ExtCtxt<'_>, Span, &MetaItem, &Annotatable, &mut dyn FnMut(Annotatable), bool);
+
+pub(crate) struct BuiltinDerive(pub(crate) BuiltinDeriveFn);
 
 impl MultiItemModifier for BuiltinDerive {
     fn expand(
@@ -49,6 +50,7 @@ fn expand(
         span: Span,
         meta_item: &MetaItem,
         item: Annotatable,
+        is_derive_const: bool,
     ) -> ExpandResult<Vec<Annotatable>, Annotatable> {
         // FIXME: Built-in derives often forget to give spans contexts,
         // so we are doing it here in a centralized way.
@@ -57,21 +59,28 @@ fn expand(
         match item {
             Annotatable::Stmt(stmt) => {
                 if let ast::StmtKind::Item(item) = stmt.into_inner().kind {
-                    (self.0)(ecx, span, meta_item, &Annotatable::Item(item), &mut |a| {
-                        // Cannot use 'ecx.stmt_item' here, because we need to pass 'ecx'
-                        // to the function
-                        items.push(Annotatable::Stmt(P(ast::Stmt {
-                            id: ast::DUMMY_NODE_ID,
-                            kind: ast::StmtKind::Item(a.expect_item()),
-                            span,
-                        })));
-                    });
+                    (self.0)(
+                        ecx,
+                        span,
+                        meta_item,
+                        &Annotatable::Item(item),
+                        &mut |a| {
+                            // Cannot use 'ecx.stmt_item' here, because we need to pass 'ecx'
+                            // to the function
+                            items.push(Annotatable::Stmt(P(ast::Stmt {
+                                id: ast::DUMMY_NODE_ID,
+                                kind: ast::StmtKind::Item(a.expect_item()),
+                                span,
+                            })));
+                        },
+                        is_derive_const,
+                    );
                 } else {
                     unreachable!("should have already errored on non-item statement")
                 }
             }
             _ => {
-                (self.0)(ecx, span, meta_item, &item, &mut |a| items.push(a));
+                (self.0)(ecx, span, meta_item, &item, &mut |a| items.push(a), is_derive_const);
             }
         }
         ExpandResult::Ready(items)
index bde0102186a478165cdadbc0ab5f5904ec2543b9..1cbbfb432647cebca15bfa72ac207eac463fb1da 100644 (file)
@@ -99,7 +99,8 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
         bench: test::expand_bench,
         cfg_accessible: cfg_accessible::Expander,
         cfg_eval: cfg_eval::expand,
-        derive: derive::Expander,
+        derive: derive::Expander(false),
+        derive_const: derive::Expander(true),
         global_allocator: global_allocator::expand,
         test: test::expand_test,
         test_case: test::expand_test_case,
index d78bbc3c932269c401400588536325cf2084c95a..3411bd40c9de553ec6e192aafb8350f0d55f6282 100644 (file)
@@ -216,7 +216,10 @@ pub fn expand_include_bytes(
         }
     };
     match cx.source_map().load_binary_file(&file) {
-        Ok(bytes) => base::MacEager::expr(cx.expr_byte_str(sp, bytes)),
+        Ok(bytes) => {
+            let expr = cx.expr(sp, ast::ExprKind::IncludedBytes(bytes.into()));
+            base::MacEager::expr(expr)
+        }
         Err(e) => {
             cx.span_err(sp, &format!("couldn't read {}: {}", file.display(), e));
             DummyResult::any(sp)
index fee5d04cdae857c7972a343afb6ff7920803c000..b62840d4bc8221d72d4a45d5d5e3144a3a050d01 100644 (file)
@@ -112,7 +112,7 @@ pub fn expand_test_or_bench(
     };
 
     // Note: non-associated fn items are already handled by `expand_test_or_bench`
-    if !matches!(item.kind, ast::ItemKind::Fn(_)) {
+    let ast::ItemKind::Fn(fn_) = &item.kind else {
         let diag = &cx.sess.parse_sess.span_diagnostic;
         let msg = "the `#[test]` attribute may only be used on a non-associated function";
         let mut err = match item.kind {
@@ -130,7 +130,7 @@ pub fn expand_test_or_bench(
             .emit();
 
         return vec![Annotatable::Item(item)];
-    }
+    };
 
     // has_*_signature will report any errors in the type so compilation
     // will fail. We shouldn't try to expand in this case because the errors
@@ -141,12 +141,14 @@ pub fn expand_test_or_bench(
         return vec![Annotatable::Item(item)];
     }
 
-    let (sp, attr_sp) = (cx.with_def_site_ctxt(item.span), cx.with_def_site_ctxt(attr_sp));
+    let sp = cx.with_def_site_ctxt(item.span);
+    let ret_ty_sp = cx.with_def_site_ctxt(fn_.sig.decl.output.span());
+    let attr_sp = cx.with_def_site_ctxt(attr_sp);
 
     let test_id = Ident::new(sym::test, attr_sp);
 
     // creates test::$name
-    let test_path = |name| cx.path(sp, vec![test_id, Ident::from_str_and_span(name, sp)]);
+    let test_path = |name| cx.path(ret_ty_sp, vec![test_id, Ident::from_str_and_span(name, sp)]);
 
     // creates test::ShouldPanic::$name
     let should_panic_path = |name| {
@@ -192,7 +194,7 @@ pub fn expand_test_or_bench(
                         vec![
                             // super::$test_fn(b)
                             cx.expr_call(
-                                sp,
+                                ret_ty_sp,
                                 cx.expr_path(cx.path(sp, vec![item.ident])),
                                 vec![cx.expr_ident(sp, b)],
                             ),
@@ -216,7 +218,11 @@ pub fn expand_test_or_bench(
                         cx.expr_path(test_path("assert_test_result")),
                         vec![
                             // $test_fn()
-                            cx.expr_call(sp, cx.expr_path(cx.path(sp, vec![item.ident])), vec![]), // )
+                            cx.expr_call(
+                                ret_ty_sp,
+                                cx.expr_path(cx.path(sp, vec![item.ident])),
+                                vec![],
+                            ), // )
                         ],
                     ), // }
                 ), // )
index 148b66d959e8a74126c5fdde83eb48f3a3de1290..df1150ec0b8ce266e610de2a0a52052ebd9dc992 100644 (file)
@@ -128,7 +128,7 @@ pub(crate) fn codegen_const_value<'tcx>(
     ty: Ty<'tcx>,
 ) -> CValue<'tcx> {
     let layout = fx.layout_of(ty);
-    assert!(!layout.is_unsized(), "sized const value");
+    assert!(layout.is_sized(), "unsized const value");
 
     if layout.is_zst() {
         return CValue::by_ref(crate::Pointer::dangling(layout.align.pref), layout);
index c55db2017ee68c31c53b0a59e12c82b6b72c6c7e..2ba012a77b0a908788f0272705f82f7c875cb1a7 100644 (file)
@@ -59,7 +59,7 @@ pub(crate) fn new(tcx: TyCtxt<'_>, isa: &dyn TargetIsa) -> Self {
 
         let producer = format!(
             "cg_clif (rustc {}, cranelift {})",
-            rustc_interface::util::version_str().unwrap_or("unknown version"),
+            rustc_interface::util::rustc_version_str().unwrap_or("unknown version"),
             cranelift_codegen::VERSION,
         );
         let comp_dir = tcx
index c3dfbd37279f9eca6b984156b9d1500a3017ccd4..c5bd574623df68d2644ce5908d136d696b12e979 100644 (file)
@@ -19,7 +19,7 @@ fn codegen_field<'tcx>(
     };
 
     if let Some(extra) = extra {
-        if !field_layout.is_unsized() {
+        if field_layout.is_sized() {
             return simple(fx);
         }
         match field_layout.ty.kind() {
@@ -364,7 +364,7 @@ pub(crate) fn new_stack_slot(
         fx: &mut FunctionCx<'_, '_, 'tcx>,
         layout: TyAndLayout<'tcx>,
     ) -> CPlace<'tcx> {
-        assert!(!layout.is_unsized());
+        assert!(layout.is_sized());
         if layout.size.bytes() == 0 {
             return CPlace {
                 inner: CPlaceInner::Addr(Pointer::dangling(layout.align.pref), None),
@@ -825,7 +825,7 @@ pub(crate) fn downcast_variant(
         fx: &FunctionCx<'_, '_, 'tcx>,
         variant: VariantIdx,
     ) -> Self {
-        assert!(!self.layout().is_unsized());
+        assert!(self.layout().is_sized());
         let layout = self.layout().for_variant(fx, variant);
         CPlace { inner: self.inner, layout }
     }
index 862ed62c68b2ab9124e9ef04252819839e34a78c..bdf7318ce48c9505887b2287c0201bf66742bc54 100644 (file)
@@ -277,7 +277,7 @@ pub fn struct_fields<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout
         offset = target_offset + field.size;
         prev_effective_align = effective_field_align;
     }
-    if !layout.is_unsized() && field_count > 0 {
+    if layout.is_sized() && field_count > 0 {
         if offset > layout.size {
             bug!("layout: {:#?} stride: {:?} offset: {:?}", layout, layout.size, offset);
         }
index d96da5cc11d1f72fba53e7116afb7810ca11d39c..a8b47633519aabc39689ab19a7138c269b11440c 100644 (file)
@@ -12,6 +12,7 @@
 use smallvec::SmallVec;
 
 use crate::attributes;
+use crate::errors::{MissingFeatures, SanitizerMemtagRequiresMte, TargetFeatureDisableOrEnable};
 use crate::llvm::AttributePlace::Function;
 use crate::llvm::{self, AllocKindFlags, Attribute, AttributeKind, AttributePlace, MemoryEffects};
 use crate::llvm_util;
@@ -82,7 +83,7 @@ pub fn sanitize_attrs<'ll>(
         let mte_feature =
             features.iter().map(|s| &s[..]).rfind(|n| ["+mte", "-mte"].contains(&&n[..]));
         if let None | Some("-mte") = mte_feature {
-            cx.tcx.sess.err("`-Zsanitizer=memtag` requires `-Ctarget-feature=+mte`");
+            cx.tcx.sess.emit_err(SanitizerMemtagRequiresMte);
         }
 
         attrs.push(llvm::AttributeKind::SanitizeMemTag.create_attr(cx.llcx));
@@ -393,13 +394,14 @@ pub fn from_fn_attrs<'ll, 'tcx>(
             .get_attrs(instance.def_id(), sym::target_feature)
             .next()
             .map_or_else(|| cx.tcx.def_span(instance.def_id()), |a| a.span);
-        let msg = format!(
-            "the target features {} must all be either enabled or disabled together",
-            f.join(", ")
-        );
-        let mut err = cx.tcx.sess.struct_span_err(span, &msg);
-        err.help("add the missing features in a `target_feature` attribute");
-        err.emit();
+        cx.tcx
+            .sess
+            .create_err(TargetFeatureDisableOrEnable {
+                features: f,
+                span: Some(span),
+                missing_features: Some(MissingFeatures),
+            })
+            .emit();
         return;
     }
 
index 082665bba3802cc33f56d1ebbc1885964ee2af43..5c68abeb08baf288532e48c162926b39f92fce26 100644 (file)
 use object::read::macho::FatArch;
 
 use crate::common;
+use crate::errors::{
+    ArchiveBuildFailure, DlltoolFailImportLibrary, ErrorCallingDllTool, ErrorCreatingImportLibrary,
+    ErrorWritingDEFFile, UnknownArchiveKind,
+};
 use crate::llvm::archive_ro::{ArchiveRO, Child};
 use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport};
 use rustc_codegen_ssa::back::archive::{ArchiveBuilder, ArchiveBuilderBuilder};
@@ -147,7 +151,7 @@ fn add_file(&mut self, file: &Path) {
     fn build(mut self: Box<Self>, output: &Path) -> bool {
         match self.build_with_llvm(output) {
             Ok(any_members) => any_members,
-            Err(e) => self.sess.fatal(&format!("failed to build archive: {}", e)),
+            Err(e) => self.sess.emit_fatal(ArchiveBuildFailure { error: e }),
         }
     }
 }
@@ -217,7 +221,7 @@ fn create_dll_import_lib(
             match std::fs::write(&def_file_path, def_file_content) {
                 Ok(_) => {}
                 Err(e) => {
-                    sess.fatal(&format!("Error writing .DEF file: {}", e));
+                    sess.emit_fatal(ErrorWritingDEFFile { error: e });
                 }
             };
 
@@ -239,13 +243,14 @@ fn create_dll_import_lib(
 
             match result {
                 Err(e) => {
-                    sess.fatal(&format!("Error calling dlltool: {}", e));
+                    sess.emit_fatal(ErrorCallingDllTool { error: e });
+                }
+                Ok(output) if !output.status.success() => {
+                    sess.emit_fatal(DlltoolFailImportLibrary {
+                        stdout: String::from_utf8_lossy(&output.stdout),
+                        stderr: String::from_utf8_lossy(&output.stderr),
+                    })
                 }
-                Ok(output) if !output.status.success() => sess.fatal(&format!(
-                    "Dlltool could not create import library: {}\n{}",
-                    String::from_utf8_lossy(&output.stdout),
-                    String::from_utf8_lossy(&output.stderr)
-                )),
                 _ => {}
             }
         } else {
@@ -293,11 +298,10 @@ fn create_dll_import_lib(
             };
 
             if result == crate::llvm::LLVMRustResult::Failure {
-                sess.fatal(&format!(
-                    "Error creating import library for {}: {}",
+                sess.emit_fatal(ErrorCreatingImportLibrary {
                     lib_name,
-                    llvm::last_error().unwrap_or("unknown LLVM error".to_string())
-                ));
+                    error: llvm::last_error().unwrap_or("unknown LLVM error".to_string()),
+                });
             }
         };
 
@@ -308,9 +312,10 @@ fn create_dll_import_lib(
 impl<'a> LlvmArchiveBuilder<'a> {
     fn build_with_llvm(&mut self, output: &Path) -> io::Result<bool> {
         let kind = &*self.sess.target.archive_format;
-        let kind = kind.parse::<ArchiveKind>().map_err(|_| kind).unwrap_or_else(|kind| {
-            self.sess.fatal(&format!("Don't know how to build archive of type: {}", kind))
-        });
+        let kind = kind
+            .parse::<ArchiveKind>()
+            .map_err(|_| kind)
+            .unwrap_or_else(|kind| self.sess.emit_fatal(UnknownArchiveKind { kind }));
 
         let mut additions = mem::take(&mut self.additions);
         let mut strings = Vec::new();
index a49cc7f8d662ddd427334895ca2a13e2eb582e78..3fa21355b7f4c9b46349591904aac80717541976 100644 (file)
@@ -1,4 +1,5 @@
 use crate::back::write::{self, save_temp_bitcode, DiagnosticHandlers};
+use crate::errors::DynamicLinkingWithLTO;
 use crate::llvm::{self, build_string};
 use crate::{LlvmCodegenBackend, ModuleLlvm};
 use object::read::archive::ArchiveFile;
@@ -90,13 +91,7 @@ fn prepare_lto(
         }
 
         if cgcx.opts.cg.prefer_dynamic && !cgcx.opts.unstable_opts.dylib_lto {
-            diag_handler
-                .struct_err("cannot prefer dynamic linking when performing LTO")
-                .note(
-                    "only 'staticlib', 'bin', and 'cdylib' outputs are \
-                               supported with LTO",
-                )
-                .emit();
+            diag_handler.emit_err(DynamicLinkingWithLTO);
             return Err(FatalError);
         }
 
index 11053a8f6c45293a1b306c1c573ceed88a370efe..97d0de47b3a6e7fbff4484c5e74c393bea3891a2 100644 (file)
@@ -765,11 +765,21 @@ extern "C" fn demangle_callback(
         drop(handlers);
     }
 
+    // `.dwo` files are only emitted if:
+    //
+    // - Object files are being emitted (i.e. bitcode only or metadata only compilations will not
+    //   produce dwarf objects, even if otherwise enabled)
+    // - Target supports Split DWARF
+    // - Split debuginfo is enabled
+    // - Split DWARF kind is `split` (i.e. debuginfo is split into `.dwo` files, not different
+    //   sections in the `.o` files).
+    let dwarf_object_emitted = matches!(config.emit_obj, EmitObj::ObjectCode(_))
+        && cgcx.target_can_use_split_dwarf
+        && cgcx.split_debuginfo != SplitDebuginfo::Off
+        && cgcx.split_dwarf_kind == SplitDwarfKind::Split;
     Ok(module.into_compiled_module(
         config.emit_obj != EmitObj::None,
-        cgcx.target_can_use_split_dwarf
-            && cgcx.split_debuginfo != SplitDebuginfo::Off
-            && cgcx.split_dwarf_kind == SplitDwarfKind::Split,
+        dwarf_object_emitted,
         config.emit_bc,
         &cgcx.output_filenames,
     ))
index dd3c43ba5ca7ccb4cf7aef75058b629630757246..3b504d3a7df7589fc7f13a0027584d4cb51d6638 100644 (file)
@@ -1,6 +1,7 @@
 use crate::base;
 use crate::common::{self, CodegenCx};
 use crate::debuginfo;
+use crate::errors::{InvalidMinimumAlignment, LinkageConstOrMutType, SymbolAlreadyDefined};
 use crate::llvm::{self, True};
 use crate::llvm_util;
 use crate::type_::Type;
@@ -19,6 +20,7 @@
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::{self, Instance, Ty};
 use rustc_middle::{bug, span_bug};
+use rustc_session::config::Lto;
 use rustc_target::abi::{
     AddressSpace, Align, HasDataLayout, Primitive, Scalar, Size, WrappingRange,
 };
@@ -145,7 +147,7 @@ fn set_global_alignment<'ll>(cx: &CodegenCx<'ll, '_>, gv: &'ll Value, mut align:
         match Align::from_bits(min) {
             Ok(min) => align = align.max(min),
             Err(err) => {
-                cx.sess().err(&format!("invalid minimum global alignment: {}", err));
+                cx.sess().emit_err(InvalidMinimumAlignment { err });
             }
         }
     }
@@ -173,10 +175,7 @@ fn check_and_apply_linkage<'ll, 'tcx>(
         let llty2 = if let ty::RawPtr(ref mt) = ty.kind() {
             cx.layout_of(mt.ty).llvm_type(cx)
         } else {
-            cx.sess().span_fatal(
-                cx.tcx.def_span(def_id),
-                "must have type `*const T` or `*mut T` due to `#[linkage]` attribute",
-            )
+            cx.sess().emit_fatal(LinkageConstOrMutType { span: cx.tcx.def_span(def_id) })
         };
         unsafe {
             // Declare a symbol `foo` with the desired linkage.
@@ -192,10 +191,10 @@ fn check_and_apply_linkage<'ll, 'tcx>(
             let mut real_name = "_rust_extern_with_linkage_".to_string();
             real_name.push_str(sym);
             let g2 = cx.define_global(&real_name, llty).unwrap_or_else(|| {
-                cx.sess().span_fatal(
-                    cx.tcx.def_span(def_id),
-                    &format!("symbol `{}` is already defined", &sym),
-                )
+                cx.sess().emit_fatal(SymbolAlreadyDefined {
+                    span: cx.tcx.def_span(def_id),
+                    symbol_name: sym,
+                })
             });
             llvm::LLVMRustSetLinkage(g2, llvm::Linkage::InternalLinkage);
             llvm::LLVMSetInitializer(g2, g1);
@@ -303,7 +302,8 @@ pub(crate) fn get_static(&self, def_id: DefId) -> &'ll Value {
                 // ThinLTO can't handle this workaround in all cases, so we don't
                 // emit the attrs. Instead we make them unnecessary by disallowing
                 // dynamic linking when linker plugin based LTO is enabled.
-                !self.tcx.sess.opts.cg.linker_plugin_lto.enabled();
+                !self.tcx.sess.opts.cg.linker_plugin_lto.enabled() &&
+                self.tcx.sess.lto() != Lto::Thin;
 
             // If this assertion triggers, there's something wrong with commandline
             // argument validation.
index c22ec128dacb0cddc7b57f337668448729ed0dcb..eaa2ccfc835c5f2564a58d53ff9522d87e3320e7 100644 (file)
@@ -3,6 +3,7 @@
 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;
@@ -26,6 +27,7 @@
 use rustc_session::config::{CrateType, DebugInfo, PAuthKey, PacRet};
 use rustc_session::Session;
 use rustc_span::source_map::Span;
+use rustc_span::source_map::Spanned;
 use rustc_target::abi::{
     call::FnAbi, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx,
 };
@@ -275,7 +277,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.err("-Zbranch-protection is only supported on aarch64");
+            sess.emit_err(BranchProtectionRequiresAArch64);
         } else {
             llvm::LLVMRustAddModuleFlag(
                 llmod,
@@ -951,7 +953,7 @@ impl<'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'_, 'tcx> {
     #[inline]
     fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
         if let LayoutError::SizeOverflow(_) = err {
-            self.sess().span_fatal(span, &err.to_string())
+            self.sess().emit_fatal(Spanned { span, node: err })
         } else {
             span_bug!(span, "failed to get layout for `{}`: {}", ty, err)
         }
@@ -969,7 +971,7 @@ fn handle_fn_abi_err(
         fn_abi_request: FnAbiRequest<'tcx>,
     ) -> ! {
         if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err {
-            self.sess().span_fatal(span, &err.to_string())
+            self.sess().emit_fatal(Spanned { span, node: err })
         } else {
             match fn_abi_request {
                 FnAbiRequest::OfFnPtr { sig, extra_args } => {
index 433f043209e5314a08e3b7bb2cbc81b0bc0642db..8a8d889a29865960e9c1337873d5ab54879b783e 100644 (file)
@@ -1,5 +1,6 @@
 use crate::common::CodegenCx;
 use crate::coverageinfo;
+use crate::errors::InstrumentCoverageRequiresLLVM12;
 use crate::llvm;
 
 use llvm::coverageinfo::CounterMappingRegion;
@@ -37,7 +38,7 @@ pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) {
     // LLVM 12.
     let version = coverageinfo::mapping_version();
     if version < 4 {
-        tcx.sess.fatal("rustc option `-C instrument-coverage` requires LLVM 12 or higher.");
+        tcx.sess.emit_fatal(InstrumentCoverageRequiresLLVM12);
     }
 
     debug!("Generating coverage map for CodegenUnit: `{}`", cx.codegen_unit.name());
index a40cfc8b23fb32217f5b6b0897bea0e4f9e27373..5cd0e1cb63ae1b6b2c602272ba506cbf45dc1c45 100644 (file)
@@ -72,7 +72,7 @@ pub(crate) fn fat_pointer_kind<'ll, 'tcx>(
         layout.is_unsized()
     );
 
-    if !layout.is_unsized() {
+    if layout.is_sized() {
         return None;
     }
 
diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs
new file mode 100644 (file)
index 0000000..0fafc21
--- /dev/null
@@ -0,0 +1,139 @@
+use std::borrow::Cow;
+
+use rustc_errors::fluent;
+use rustc_errors::DiagnosticBuilder;
+use rustc_errors::ErrorGuaranteed;
+use rustc_errors::Handler;
+use rustc_errors::IntoDiagnostic;
+use rustc_macros::{Diagnostic, Subdiagnostic};
+use rustc_span::Span;
+
+#[derive(Diagnostic)]
+#[diag(codegen_llvm_unknown_ctarget_feature_prefix)]
+#[note]
+pub(crate) struct UnknownCTargetFeaturePrefix<'a> {
+    pub feature: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_llvm_unknown_ctarget_feature)]
+#[note]
+pub(crate) struct UnknownCTargetFeature<'a> {
+    pub feature: &'a str,
+    #[subdiagnostic]
+    pub rust_feature: PossibleFeature<'a>,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum PossibleFeature<'a> {
+    #[help(possible_feature)]
+    Some { rust_feature: &'a str },
+    #[help(consider_filing_feature_request)]
+    None,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_llvm_error_creating_import_library)]
+pub(crate) struct ErrorCreatingImportLibrary<'a> {
+    pub lib_name: &'a str,
+    pub error: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_llvm_instrument_coverage_requires_llvm_12)]
+pub(crate) struct InstrumentCoverageRequiresLLVM12;
+
+#[derive(Diagnostic)]
+#[diag(codegen_llvm_symbol_already_defined)]
+pub(crate) struct SymbolAlreadyDefined<'a> {
+    #[primary_span]
+    pub span: Span,
+    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 {
+    pub err: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_llvm_linkage_const_or_mut_type)]
+pub(crate) struct LinkageConstOrMutType {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_llvm_sanitizer_memtag_requires_mte)]
+pub(crate) struct SanitizerMemtagRequiresMte;
+
+#[derive(Diagnostic)]
+#[diag(codegen_llvm_archive_build_failure)]
+pub(crate) struct ArchiveBuildFailure {
+    pub error: std::io::Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_llvm_error_writing_def_file)]
+pub(crate) struct ErrorWritingDEFFile {
+    pub error: std::io::Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_llvm_error_calling_dlltool)]
+pub(crate) struct ErrorCallingDllTool {
+    pub error: std::io::Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_llvm_dlltool_fail_import_library)]
+pub(crate) struct DlltoolFailImportLibrary<'a> {
+    pub stdout: Cow<'a, str>,
+    pub stderr: Cow<'a, str>,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_llvm_unknown_archive_kind)]
+pub(crate) struct UnknownArchiveKind<'a> {
+    pub kind: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_llvm_dynamic_linking_with_lto)]
+#[note]
+pub(crate) struct DynamicLinkingWithLTO;
+
+#[derive(Diagnostic)]
+#[diag(codegen_llvm_fail_parsing_target_machine_config_to_target_machine)]
+pub(crate) struct FailParsingTargetMachineConfigToTargetMachine {
+    pub error: String,
+}
+
+pub(crate) struct TargetFeatureDisableOrEnable<'a> {
+    pub features: &'a [&'a str],
+    pub span: Option<Span>,
+    pub missing_features: Option<MissingFeatures>,
+}
+
+#[derive(Subdiagnostic)]
+#[help(codegen_llvm_missing_features)]
+pub(crate) struct MissingFeatures;
+
+impl IntoDiagnostic<'_, ErrorGuaranteed> for TargetFeatureDisableOrEnable<'_> {
+    fn into_diagnostic(self, sess: &'_ Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
+        let mut diag = sess.struct_err(fluent::codegen_llvm_target_feature_disable_or_enable);
+        if let Some(span) = self.span {
+            diag.set_span(span);
+        };
+        if let Some(missing_features) = self.missing_features {
+            diag.subdiagnostic(missing_features);
+        }
+        diag.set_arg("features", self.features.join(", "));
+        diag
+    }
+}
index 825011941a24117a00f65638cc53e5efc2100d27..cf590a43826e53407aab00b691ad66fe0744a3cd 100644 (file)
@@ -340,17 +340,26 @@ fn codegen_intrinsic_call(
 
             sym::black_box => {
                 args[0].val.store(self, result);
-
+                let result_val_span = [result.llval];
                 // We need to "use" the argument in some way LLVM can't introspect, and on
                 // targets that support it we can typically leverage inline assembly to do
                 // this. LLVM's interpretation of inline assembly is that it's, well, a black
                 // box. This isn't the greatest implementation since it probably deoptimizes
                 // more than we want, but it's so far good enough.
+                //
+                // For zero-sized types, the location pointed to by the result may be
+                // uninitialized. Do not "use" the result in this case; instead just clobber
+                // the memory.
+                let (constraint, inputs): (&str, &[_]) = if result.layout.is_zst() {
+                    ("~{memory}", &[])
+                } else {
+                    ("r,~{memory}", &result_val_span)
+                };
                 crate::asm::inline_asm_call(
                     self,
                     "",
-                    "r,~{memory}",
-                    &[result.llval],
+                    constraint,
+                    inputs,
                     self.type_void(),
                     true,
                     false,
index d51aced85df43141c779d0902244f651bdcb7358..246e82545c874811fa6552bc2286da98bc113476 100644 (file)
@@ -12,6 +12,8 @@
 #![feature(iter_intersperse)]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
 
 #[macro_use]
 extern crate rustc_macros;
@@ -20,6 +22,7 @@
 
 use back::write::{create_informational_target_machine, create_target_machine};
 
+use errors::FailParsingTargetMachineConfigToTargetMachine;
 pub use llvm_util::target_features;
 use rustc_ast::expand::allocator::AllocatorKind;
 use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule};
@@ -62,6 +65,7 @@ mod back {
 mod coverageinfo;
 mod debuginfo;
 mod declare;
+mod errors;
 mod intrinsic;
 
 // The following is a work around that replaces `pub mod llvm;` and that fixes issue 53912.
@@ -412,7 +416,7 @@ fn parse(
             let tm = match (cgcx.tm_factory)(tm_factory_config) {
                 Ok(m) => m,
                 Err(e) => {
-                    handler.struct_err(&e).emit();
+                    handler.emit_err(FailParsingTargetMachineConfigToTargetMachine { error: e });
                     return Err(FatalError);
                 }
             };
index 2fd58567c487406d6864849027ddd03ca44ccf07..e1f54356228d3ea60163ec928322caf5d82fbc88 100644 (file)
@@ -1,4 +1,8 @@
 use crate::back::write::create_informational_target_machine;
+use crate::errors::{
+    PossibleFeature, TargetFeatureDisableOrEnable, UnknownCTargetFeature,
+    UnknownCTargetFeaturePrefix,
+};
 use crate::llvm;
 use libc::c_int;
 use rustc_codegen_ssa::target_features::{
@@ -434,12 +438,7 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
                 Some(c @ '+' | c @ '-') => c,
                 Some(_) => {
                     if diagnostics {
-                        let mut diag = sess.struct_warn(&format!(
-                            "unknown feature specified for `-Ctarget-feature`: `{}`",
-                            s
-                        ));
-                        diag.note("features must begin with a `+` to enable or `-` to disable it");
-                        diag.emit();
+                        sess.emit_warning(UnknownCTargetFeaturePrefix { feature: s });
                     }
                     return None;
                 }
@@ -456,17 +455,15 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
                         None
                     }
                 });
-                let mut diag = sess.struct_warn(&format!(
-                    "unknown feature specified for `-Ctarget-feature`: `{}`",
-                    feature
-                ));
-                diag.note("it is still passed through to the codegen backend");
-                if let Some(rust_feature) = rust_feature {
-                    diag.help(&format!("you might have meant: `{}`", rust_feature));
+                let unknown_feature = if let Some(rust_feature) = rust_feature {
+                    UnknownCTargetFeature {
+                        feature,
+                        rust_feature: PossibleFeature::Some { rust_feature },
+                    }
                 } else {
-                    diag.note("consider filing a feature request");
-                }
-                diag.emit();
+                    UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None }
+                };
+                sess.emit_warning(unknown_feature);
             }
 
             if diagnostics {
@@ -492,10 +489,11 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
     features.extend(feats);
 
     if diagnostics && let Some(f) = check_tied_features(sess, &featsmap) {
-        sess.err(&format!(
-            "target features {} must all be enabled or disabled together",
-            f.join(", ")
-        ));
+        sess.emit_err(TargetFeatureDisableOrEnable {
+            features: f,
+            span: None,
+            missing_features: None,
+        });
     }
 
     features
index 1eceb7f5c87beb362760851e5ce31ae40a66c75f..76f692b2016fd5ff64d4824206b856fc12811969 100644 (file)
@@ -1,6 +1,7 @@
 use crate::attributes;
 use crate::base;
 use crate::context::CodegenCx;
+use crate::errors::SymbolAlreadyDefined;
 use crate::llvm;
 use crate::type_of::LayoutLlvmExt;
 use rustc_codegen_ssa::traits::*;
@@ -25,10 +26,8 @@ fn predefine_static(
         let llty = self.layout_of(ty).llvm_type(self);
 
         let g = self.define_global(symbol_name, llty).unwrap_or_else(|| {
-            self.sess().span_fatal(
-                self.tcx.def_span(def_id),
-                &format!("symbol `{}` is already defined", symbol_name),
-            )
+            self.sess()
+                .emit_fatal(SymbolAlreadyDefined { span: self.tcx.def_span(def_id), symbol_name })
         });
 
         unsafe {
index dc1165835e7ca271b38986619f20801fb8c5a71e..182adf81785716fe5abea7b91e0571dc6bda7a8b 100644 (file)
@@ -140,7 +140,7 @@ fn struct_llfields<'a, 'tcx>(
         prev_effective_align = effective_field_align;
     }
     let padding_used = result.len() > field_count;
-    if !layout.is_unsized() && field_count > 0 {
+    if layout.is_sized() && field_count > 0 {
         if offset > layout.size {
             bug!("layout: {:#?} stride: {:?} offset: {:?}", layout, layout.size, offset);
         }
index 8fbcbe45d6ee9c1f8be65c1d9a004c85a8d2205a..4445e5f6c3a64e3d24c0d9379f15cfd74337eda1 100644 (file)
@@ -6,7 +6,7 @@
 use rustc_data_structures::temp_dir::MaybeTempDir;
 use rustc_errors::{ErrorGuaranteed, Handler};
 use rustc_fs_util::fix_windows_verbatim_for_gcc;
-use rustc_hir::def_id::CrateNum;
+use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
 use rustc_metadata::find_native_static_library;
 use rustc_metadata::fs::{emit_wrapper_file, METADATA_FILENAME};
 use rustc_middle::middle::dependency_format::Linkage;
@@ -24,7 +24,7 @@
 use rustc_span::DebuggerVisualizerFile;
 use rustc_target::spec::crt_objects::{CrtObjects, LinkSelfContainedDefault};
 use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, LinkerFlavorCli, Lld, PanicStrategy};
-use rustc_target::spec::{RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, Target};
+use rustc_target::spec::{RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo};
 
 use super::archive::{ArchiveBuilder, ArchiveBuilderBuilder};
 use super::command::Command;
@@ -2013,15 +2013,9 @@ fn linker_with_args<'a>(
     cmd.add_as_needed();
 
     // Local native libraries of all kinds.
-    //
-    // If `-Zlink-native-libraries=false` is set, then the assumption is that an
-    // external build system already has the native dependencies defined, and it
-    // will provide them to the linker itself.
-    if sess.opts.unstable_opts.link_native_libraries {
-        add_local_native_libraries(cmd, sess, codegen_results);
-    }
+    add_local_native_libraries(cmd, sess, archive_builder_builder, codegen_results, tmpdir);
 
-    // Upstream rust libraries and their (possibly bundled) static native libraries.
+    // Upstream rust crates and their non-dynamic native libraries.
     add_upstream_rust_crates(
         cmd,
         sess,
@@ -2032,13 +2026,7 @@ fn linker_with_args<'a>(
     );
 
     // Dynamic native libraries from upstream crates.
-    //
-    // FIXME: Merge this to `add_upstream_rust_crates` so that all native libraries are linked
-    // together with their respective upstream crates, and in their originally specified order.
-    // This may be slightly breaking due to our use of `--as-needed` and needs a crater run.
-    if sess.opts.unstable_opts.link_native_libraries {
-        add_upstream_native_libraries(cmd, sess, codegen_results);
-    }
+    add_upstream_native_libraries(cmd, sess, archive_builder_builder, codegen_results, tmpdir);
 
     // Link with the import library generated for any raw-dylib functions.
     for (raw_dylib_name, raw_dylib_imports) in
@@ -2282,42 +2270,46 @@ fn collect_natvis_visualizers(
     visualizer_paths
 }
 
-/// # Native library linking
-///
-/// User-supplied library search paths (-L on the command line). These are the same paths used to
-/// find Rust crates, so some of them may have been added already by the previous crate linking
-/// code. This only allows them to be found at compile time so it is still entirely up to outside
-/// forces to make sure that library can be found at runtime.
-///
-/// Also note that the native libraries linked here are only the ones located in the current crate.
-/// Upstream crates with native library dependencies may have their native library pulled in above.
-fn add_local_native_libraries(
+fn add_native_libs_from_crate(
     cmd: &mut dyn Linker,
     sess: &Session,
+    archive_builder_builder: &dyn ArchiveBuilderBuilder,
     codegen_results: &CodegenResults,
+    tmpdir: &Path,
+    search_paths: &OnceCell<Vec<PathBuf>>,
+    bundled_libs: &FxHashSet<Symbol>,
+    cnum: CrateNum,
+    link_static: bool,
+    link_dynamic: bool,
 ) {
-    let filesearch = sess.target_filesearch(PathKind::All);
-    for search_path in filesearch.search_paths() {
-        match search_path.kind {
-            PathKind::Framework => {
-                cmd.framework_path(&search_path.dir);
-            }
-            _ => {
-                cmd.include_path(&fix_windows_verbatim_for_gcc(&search_path.dir));
-            }
-        }
+    if !sess.opts.unstable_opts.link_native_libraries {
+        // If `-Zlink-native-libraries=false` is set, then the assumption is that an
+        // external build system already has the native dependencies defined, and it
+        // will provide them to the linker itself.
+        return;
     }
 
-    let relevant_libs =
-        codegen_results.crate_info.used_libraries.iter().filter(|l| relevant_lib(sess, l));
+    if link_static && cnum != LOCAL_CRATE && !bundled_libs.is_empty() {
+        // If rlib contains native libs as archives, unpack them to tmpdir.
+        let rlib = &codegen_results.crate_info.used_crate_source[&cnum].rlib.as_ref().unwrap().0;
+        archive_builder_builder
+            .extract_bundled_libs(rlib, tmpdir, &bundled_libs)
+            .unwrap_or_else(|e| sess.emit_fatal(e));
+    }
+
+    let native_libs = match cnum {
+        LOCAL_CRATE => &codegen_results.crate_info.used_libraries,
+        _ => &codegen_results.crate_info.native_libraries[&cnum],
+    };
 
-    let search_path = OnceCell::new();
     let mut last = (None, NativeLibKind::Unspecified, None);
-    for lib in relevant_libs {
+    for lib in native_libs {
         let Some(name) = lib.name else {
             continue;
         };
-        let name = name.as_str();
+        if !relevant_lib(sess, lib) {
+            continue;
+        }
 
         // Skip if this library is the same as the last.
         last = if (lib.name, lib.kind, lib.verbatim) == last {
@@ -2326,46 +2318,119 @@ fn add_local_native_libraries(
             (lib.name, lib.kind, lib.verbatim)
         };
 
+        let name = name.as_str();
         let verbatim = lib.verbatim.unwrap_or(false);
         match lib.kind {
+            NativeLibKind::Static { bundle, whole_archive } => {
+                if link_static {
+                    let bundle = bundle.unwrap_or(true);
+                    let whole_archive = whole_archive == Some(true)
+                        // Backward compatibility case: this can be a rlib (so `+whole-archive`
+                        // cannot be added explicitly if necessary, see the error in `fn link_rlib`)
+                        // compiled as an executable due to `--test`. Use whole-archive implicitly,
+                        // like before the introduction of native lib modifiers.
+                        || (whole_archive == None
+                            && bundle
+                            && cnum == LOCAL_CRATE
+                            && sess.opts.test);
+
+                    if bundle && cnum != LOCAL_CRATE {
+                        if let Some(filename) = lib.filename {
+                            // If rlib contains native libs as archives, they are unpacked to tmpdir.
+                            let path = tmpdir.join(filename.as_str());
+                            if whole_archive {
+                                cmd.link_whole_rlib(&path);
+                            } else {
+                                cmd.link_rlib(&path);
+                            }
+                        }
+                    } else {
+                        if whole_archive {
+                            cmd.link_whole_staticlib(
+                                name,
+                                verbatim,
+                                &search_paths.get_or_init(|| archive_search_paths(sess)),
+                            );
+                        } else {
+                            // HACK/FIXME: Fixup a circular dependency between libgcc and libc
+                            // with glibc. This logic should be moved to the libc crate.
+                            if cnum != LOCAL_CRATE
+                                && sess.target.os == "linux"
+                                && sess.target.env == "gnu"
+                                && name == "c"
+                            {
+                                cmd.link_staticlib("gcc", false);
+                            }
+                            cmd.link_staticlib(name, verbatim)
+                        }
+                    }
+                }
+            }
             NativeLibKind::Dylib { as_needed } => {
-                cmd.link_dylib(name, verbatim, as_needed.unwrap_or(true))
+                if link_dynamic {
+                    cmd.link_dylib(name, verbatim, as_needed.unwrap_or(true))
+                }
             }
-            NativeLibKind::Unspecified => cmd.link_dylib(name, verbatim, true),
-            NativeLibKind::Framework { as_needed } => {
-                cmd.link_framework(name, as_needed.unwrap_or(true))
+            NativeLibKind::Unspecified => {
+                if link_dynamic {
+                    cmd.link_dylib(name, verbatim, true);
+                }
             }
-            NativeLibKind::Static { whole_archive, bundle, .. } => {
-                if whole_archive == Some(true)
-                    // Backward compatibility case: this can be a rlib (so `+whole-archive` cannot
-                    // be added explicitly if necessary, see the error in `fn link_rlib`) compiled
-                    // as an executable due to `--test`. Use whole-archive implicitly, like before
-                    // the introduction of native lib modifiers.
-                    || (whole_archive == None && bundle != Some(false) && sess.opts.test)
-                {
-                    cmd.link_whole_staticlib(
-                        name,
-                        verbatim,
-                        &search_path.get_or_init(|| archive_search_paths(sess)),
-                    );
-                } else {
-                    cmd.link_staticlib(name, verbatim)
+            NativeLibKind::Framework { as_needed } => {
+                if link_dynamic {
+                    cmd.link_framework(name, as_needed.unwrap_or(true))
                 }
             }
             NativeLibKind::RawDylib => {
-                // Ignore RawDylib here, they are handled separately in linker_with_args().
+                // Handled separately in `linker_with_args`.
             }
             NativeLibKind::LinkArg => {
-                cmd.arg(name);
+                if link_static {
+                    cmd.arg(name);
+                }
             }
         }
     }
 }
 
-/// # Linking Rust crates and their non-bundled static libraries
-///
-/// Rust crates are not considered at all when creating an rlib output. All dependencies will be
-/// linked when producing the final output (instead of the intermediate rlib version).
+fn add_local_native_libraries(
+    cmd: &mut dyn Linker,
+    sess: &Session,
+    archive_builder_builder: &dyn ArchiveBuilderBuilder,
+    codegen_results: &CodegenResults,
+    tmpdir: &Path,
+) {
+    if sess.opts.unstable_opts.link_native_libraries {
+        // User-supplied library search paths (-L on the command line). These are the same paths
+        // used to find Rust crates, so some of them may have been added already by the previous
+        // crate linking code. This only allows them to be found at compile time so it is still
+        // entirely up to outside forces to make sure that library can be found at runtime.
+        for search_path in sess.target_filesearch(PathKind::All).search_paths() {
+            match search_path.kind {
+                PathKind::Framework => cmd.framework_path(&search_path.dir),
+                _ => cmd.include_path(&fix_windows_verbatim_for_gcc(&search_path.dir)),
+            }
+        }
+    }
+
+    let search_paths = OnceCell::new();
+    // All static and dynamic native library dependencies are linked to the local crate.
+    let link_static = true;
+    let link_dynamic = true;
+    add_native_libs_from_crate(
+        cmd,
+        sess,
+        archive_builder_builder,
+        codegen_results,
+        tmpdir,
+        &search_paths,
+        &Default::default(),
+        LOCAL_CRATE,
+        link_static,
+        link_dynamic,
+    );
+}
+
 fn add_upstream_rust_crates<'a>(
     cmd: &mut dyn Linker,
     sess: &'a Session,
@@ -2381,7 +2446,6 @@ fn add_upstream_rust_crates<'a>(
     // Linking to a rlib involves just passing it to the linker (the linker
     // will slurp up the object files inside), and linking to a dynamic library
     // involves just passing the right -l flag.
-
     let (_, data) = codegen_results
         .crate_info
         .dependency_formats
@@ -2389,346 +2453,234 @@ fn add_upstream_rust_crates<'a>(
         .find(|(ty, _)| *ty == crate_type)
         .expect("failed to find crate type in dependency format list");
 
-    // Invoke get_used_crates to ensure that we get a topological sorting of
-    // crates.
-    let deps = &codegen_results.crate_info.used_crates;
-
-    let mut compiler_builtins = None;
-    let search_path = OnceCell::new();
-
-    for &cnum in deps.iter() {
-        // We may not pass all crates through to the linker. Some crates may
-        // appear statically in an existing dylib, meaning we'll pick up all the
-        // symbols from the dylib.
-        let src = &codegen_results.crate_info.used_crate_source[&cnum];
-        match data[cnum.as_usize() - 1] {
-            _ if codegen_results.crate_info.profiler_runtime == Some(cnum) => {
-                add_static_crate(
-                    cmd,
-                    sess,
-                    archive_builder_builder,
-                    codegen_results,
-                    tmpdir,
-                    cnum,
-                    &Default::default(),
-                );
-            }
-            // compiler-builtins are always placed last to ensure that they're
-            // linked correctly.
-            _ if codegen_results.crate_info.compiler_builtins == Some(cnum) => {
-                assert!(compiler_builtins.is_none());
-                compiler_builtins = Some(cnum);
-            }
-            Linkage::NotLinked | Linkage::IncludedFromDylib => {}
-            Linkage::Static => {
-                let bundled_libs = if sess.opts.unstable_opts.packed_bundled_libs {
-                    codegen_results.crate_info.native_libraries[&cnum]
+    let search_paths = OnceCell::new();
+    for &cnum in &codegen_results.crate_info.used_crates {
+        // We may not pass all crates through to the linker. Some crates may appear statically in
+        // an existing dylib, meaning we'll pick up all the symbols from the dylib.
+        // We must always link crates `compiler_builtins` and `profiler_builtins` statically.
+        // Even if they were already included into a dylib
+        // (e.g. `libstd` when `-C prefer-dynamic` is used).
+        // FIXME: `dependency_formats` can report `profiler_builtins` as `NotLinked` for some
+        // reason, it shouldn't do that because `profiler_builtins` should indeed be linked.
+        let linkage = data[cnum.as_usize() - 1];
+        let link_static_crate = linkage == Linkage::Static
+            || (linkage == Linkage::IncludedFromDylib || linkage == Linkage::NotLinked)
+                && (codegen_results.crate_info.compiler_builtins == Some(cnum)
+                    || codegen_results.crate_info.profiler_runtime == Some(cnum));
+
+        let mut bundled_libs = Default::default();
+        match linkage {
+            Linkage::Static | Linkage::IncludedFromDylib | Linkage::NotLinked => {
+                if link_static_crate {
+                    bundled_libs = codegen_results.crate_info.native_libraries[&cnum]
                         .iter()
                         .filter_map(|lib| lib.filename)
-                        .collect::<FxHashSet<_>>()
-                } else {
-                    Default::default()
-                };
-                add_static_crate(
-                    cmd,
-                    sess,
-                    archive_builder_builder,
-                    codegen_results,
-                    tmpdir,
-                    cnum,
-                    &bundled_libs,
-                );
-
-                // Link static native libs with "-bundle" modifier only if the crate they originate from
-                // is being linked statically to the current crate.  If it's linked dynamically
-                // or is an rlib already included via some other dylib crate, the symbols from
-                // native libs will have already been included in that dylib.
-                //
-                // If `-Zlink-native-libraries=false` is set, then the assumption is that an
-                // external build system already has the native dependencies defined, and it
-                // will provide them to the linker itself.
-                if sess.opts.unstable_opts.link_native_libraries {
-                    if sess.opts.unstable_opts.packed_bundled_libs {
-                        // If rlib contains native libs as archives, unpack them to tmpdir.
-                        let rlib = &src.rlib.as_ref().unwrap().0;
-                        archive_builder_builder
-                            .extract_bundled_libs(rlib, tmpdir, &bundled_libs)
-                            .unwrap_or_else(|e| sess.emit_fatal(e));
-                    }
-
-                    let mut last = (None, NativeLibKind::Unspecified, None);
-                    for lib in &codegen_results.crate_info.native_libraries[&cnum] {
-                        let Some(name) = lib.name else {
-                            continue;
-                        };
-                        let name = name.as_str();
-                        if !relevant_lib(sess, lib) {
-                            continue;
-                        }
-
-                        // Skip if this library is the same as the last.
-                        last = if (lib.name, lib.kind, lib.verbatim) == last {
-                            continue;
-                        } else {
-                            (lib.name, lib.kind, lib.verbatim)
-                        };
-
-                        match lib.kind {
-                            NativeLibKind::Static {
-                                bundle: Some(false),
-                                whole_archive: Some(true),
-                            } => {
-                                cmd.link_whole_staticlib(
-                                    name,
-                                    lib.verbatim.unwrap_or(false),
-                                    search_path.get_or_init(|| archive_search_paths(sess)),
-                                );
-                            }
-                            NativeLibKind::Static {
-                                bundle: Some(false),
-                                whole_archive: Some(false) | None,
-                            } => {
-                                // HACK/FIXME: Fixup a circular dependency between libgcc and libc
-                                // with glibc. This logic should be moved to the libc crate.
-                                if sess.target.os == "linux"
-                                    && sess.target.env == "gnu"
-                                    && name == "c"
-                                {
-                                    cmd.link_staticlib("gcc", false);
-                                }
-                                cmd.link_staticlib(name, lib.verbatim.unwrap_or(false));
-                            }
-                            NativeLibKind::LinkArg => {
-                                cmd.arg(name);
-                            }
-                            NativeLibKind::Dylib { .. }
-                            | NativeLibKind::Framework { .. }
-                            | NativeLibKind::Unspecified
-                            | NativeLibKind::RawDylib => {}
-                            NativeLibKind::Static { bundle: Some(true) | None, whole_archive } => {
-                                if sess.opts.unstable_opts.packed_bundled_libs {
-                                    // If rlib contains native libs as archives, they are unpacked to tmpdir.
-                                    let path = tmpdir.join(lib.filename.unwrap().as_str());
-                                    if whole_archive == Some(true) {
-                                        cmd.link_whole_rlib(&path);
-                                    } else {
-                                        cmd.link_rlib(&path);
-                                    }
-                                }
-                            }
-                        }
-                    }
+                        .collect();
+                    add_static_crate(
+                        cmd,
+                        sess,
+                        archive_builder_builder,
+                        codegen_results,
+                        tmpdir,
+                        cnum,
+                        &bundled_libs,
+                    );
                 }
             }
-            Linkage::Dynamic => add_dynamic_crate(cmd, sess, &src.dylib.as_ref().unwrap().0),
+            Linkage::Dynamic => {
+                let src = &codegen_results.crate_info.used_crate_source[&cnum];
+                add_dynamic_crate(cmd, sess, &src.dylib.as_ref().unwrap().0);
+            }
         }
-    }
 
-    // compiler-builtins are always placed last to ensure that they're
-    // linked correctly.
-    // We must always link the `compiler_builtins` crate statically. Even if it
-    // was already "included" in a dylib (e.g., `libstd` when `-C prefer-dynamic`
-    // is used)
-    if let Some(cnum) = compiler_builtins {
-        add_static_crate(
+        // Static libraries are linked for a subset of linked upstream crates.
+        // 1. If the upstream crate is a directly linked rlib then we must link the native library
+        // because the rlib is just an archive.
+        // 2. If the upstream crate is a dylib or a rlib linked through dylib, then we do not link
+        // the native library because it is already linked into the dylib, and even if
+        // inline/const/generic functions from the dylib can refer to symbols from the native
+        // library, those symbols should be exported and available from the dylib anyway.
+        // 3. Libraries bundled into `(compiler,profiler)_builtins` are special, see above.
+        let link_static = link_static_crate;
+        // Dynamic libraries are not linked here, see the FIXME in `add_upstream_native_libraries`.
+        let link_dynamic = false;
+        add_native_libs_from_crate(
             cmd,
             sess,
             archive_builder_builder,
             codegen_results,
             tmpdir,
+            &search_paths,
+            &bundled_libs,
             cnum,
-            &Default::default(),
+            link_static,
+            link_dynamic,
         );
     }
+}
 
-    // Converts a library file-stem into a cc -l argument
-    fn unlib<'a>(target: &Target, stem: &'a str) -> &'a str {
-        if stem.starts_with("lib") && !target.is_like_windows { &stem[3..] } else { stem }
+fn add_upstream_native_libraries(
+    cmd: &mut dyn Linker,
+    sess: &Session,
+    archive_builder_builder: &dyn ArchiveBuilderBuilder,
+    codegen_results: &CodegenResults,
+    tmpdir: &Path,
+) {
+    let search_path = OnceCell::new();
+    for &cnum in &codegen_results.crate_info.used_crates {
+        // Static libraries are not linked here, they are linked in `add_upstream_rust_crates`.
+        // FIXME: Merge this function to `add_upstream_rust_crates` so that all native libraries
+        // are linked together with their respective upstream crates, and in their originally
+        // specified order. This is slightly breaking due to our use of `--as-needed` (see crater
+        // results in https://github.com/rust-lang/rust/pull/102832#issuecomment-1279772306).
+        let link_static = false;
+        // Dynamic libraries are linked for all linked upstream crates.
+        // 1. If the upstream crate is a directly linked rlib then we must link the native library
+        // because the rlib is just an archive.
+        // 2. If the upstream crate is a dylib or a rlib linked through dylib, then we have to link
+        // the native library too because inline/const/generic functions from the dylib can refer
+        // to symbols from the native library, so the native library providing those symbols should
+        // be available when linking our final binary.
+        let link_dynamic = true;
+        add_native_libs_from_crate(
+            cmd,
+            sess,
+            archive_builder_builder,
+            codegen_results,
+            tmpdir,
+            &search_path,
+            &Default::default(),
+            cnum,
+            link_static,
+            link_dynamic,
+        );
     }
+}
 
-    // Adds the static "rlib" versions of all crates to the command line.
-    // There's a bit of magic which happens here specifically related to LTO,
-    // namely that we remove upstream object files.
-    //
-    // When performing LTO, almost(*) all of the bytecode from the upstream
-    // libraries has already been included in our object file output. As a
-    // result we need to remove the object files in the upstream libraries so
-    // the linker doesn't try to include them twice (or whine about duplicate
-    // symbols). We must continue to include the rest of the rlib, however, as
-    // it may contain static native libraries which must be linked in.
-    //
-    // (*) Crates marked with `#![no_builtins]` don't participate in LTO and
-    // their bytecode wasn't included. The object files in those libraries must
-    // still be passed to the linker.
-    //
-    // Note, however, that if we're not doing LTO we can just pass the rlib
-    // blindly to the linker (fast) because it's fine if it's not actually
-    // included as we're at the end of the dependency chain.
-    fn add_static_crate<'a>(
-        cmd: &mut dyn Linker,
-        sess: &'a Session,
-        archive_builder_builder: &dyn ArchiveBuilderBuilder,
-        codegen_results: &CodegenResults,
-        tmpdir: &Path,
-        cnum: CrateNum,
-        bundled_lib_file_names: &FxHashSet<Symbol>,
-    ) {
-        let src = &codegen_results.crate_info.used_crate_source[&cnum];
-        let cratepath = &src.rlib.as_ref().unwrap().0;
-
-        let mut link_upstream = |path: &Path| {
-            cmd.link_rlib(&fix_windows_verbatim_for_gcc(path));
-        };
-
-        // See the comment above in `link_staticlib` and `link_rlib` for why if
-        // there's a static library that's not relevant we skip all object
-        // files.
-        let native_libs = &codegen_results.crate_info.native_libraries[&cnum];
-        let skip_native = native_libs.iter().any(|lib| {
-            matches!(lib.kind, NativeLibKind::Static { bundle: None | Some(true), .. })
-                && !relevant_lib(sess, lib)
-        });
-
-        if (!are_upstream_rust_objects_already_included(sess)
-            || ignored_for_lto(sess, &codegen_results.crate_info, cnum))
-            && !skip_native
-        {
-            link_upstream(cratepath);
-            return;
-        }
-
-        let dst = tmpdir.join(cratepath.file_name().unwrap());
-        let name = cratepath.file_name().unwrap().to_str().unwrap();
-        let name = &name[3..name.len() - 5]; // chop off lib/.rlib
-        let bundled_lib_file_names = bundled_lib_file_names.clone();
-
-        sess.prof.generic_activity_with_arg("link_altering_rlib", name).run(|| {
-            let canonical_name = name.replace('-', "_");
-            let upstream_rust_objects_already_included =
-                are_upstream_rust_objects_already_included(sess);
-            let is_builtins = sess.target.no_builtins
-                || !codegen_results.crate_info.is_no_builtins.contains(&cnum);
-
-            let mut archive = archive_builder_builder.new_archive_builder(sess);
-            if let Err(error) = archive.add_archive(
-                cratepath,
-                Box::new(move |f| {
-                    if f == METADATA_FILENAME {
-                        return true;
-                    }
+// Adds the static "rlib" versions of all crates to the command line.
+// There's a bit of magic which happens here specifically related to LTO,
+// namely that we remove upstream object files.
+//
+// When performing LTO, almost(*) all of the bytecode from the upstream
+// libraries has already been included in our object file output. As a
+// result we need to remove the object files in the upstream libraries so
+// the linker doesn't try to include them twice (or whine about duplicate
+// symbols). We must continue to include the rest of the rlib, however, as
+// it may contain static native libraries which must be linked in.
+//
+// (*) Crates marked with `#![no_builtins]` don't participate in LTO and
+// their bytecode wasn't included. The object files in those libraries must
+// still be passed to the linker.
+//
+// Note, however, that if we're not doing LTO we can just pass the rlib
+// blindly to the linker (fast) because it's fine if it's not actually
+// included as we're at the end of the dependency chain.
+fn add_static_crate<'a>(
+    cmd: &mut dyn Linker,
+    sess: &'a Session,
+    archive_builder_builder: &dyn ArchiveBuilderBuilder,
+    codegen_results: &CodegenResults,
+    tmpdir: &Path,
+    cnum: CrateNum,
+    bundled_lib_file_names: &FxHashSet<Symbol>,
+) {
+    let src = &codegen_results.crate_info.used_crate_source[&cnum];
+    let cratepath = &src.rlib.as_ref().unwrap().0;
 
-                    let canonical = f.replace('-', "_");
-
-                    let is_rust_object =
-                        canonical.starts_with(&canonical_name) && looks_like_rust_object_file(&f);
-
-                    // If we've been requested to skip all native object files
-                    // (those not generated by the rust compiler) then we can skip
-                    // this file. See above for why we may want to do this.
-                    let skip_because_cfg_say_so = skip_native && !is_rust_object;
-
-                    // If we're performing LTO and this is a rust-generated object
-                    // file, then we don't need the object file as it's part of the
-                    // LTO module. Note that `#![no_builtins]` is excluded from LTO,
-                    // though, so we let that object file slide.
-                    let skip_because_lto =
-                        upstream_rust_objects_already_included && is_rust_object && is_builtins;
-
-                    // We skip native libraries because:
-                    // 1. This native libraries won't be used from the generated rlib,
-                    //    so we can throw them away to avoid the copying work.
-                    // 2. We can't allow it to be a single remaining entry in archive
-                    //    as some linkers may complain on that.
-                    if bundled_lib_file_names.contains(&Symbol::intern(f)) {
-                        return true;
-                    }
+    let mut link_upstream = |path: &Path| {
+        cmd.link_rlib(&fix_windows_verbatim_for_gcc(path));
+    };
 
-                    if skip_because_cfg_say_so || skip_because_lto {
-                        return true;
-                    }
+    // See the comment above in `link_staticlib` and `link_rlib` for why if
+    // there's a static library that's not relevant we skip all object
+    // files.
+    let native_libs = &codegen_results.crate_info.native_libraries[&cnum];
+    let skip_native = native_libs.iter().any(|lib| {
+        matches!(lib.kind, NativeLibKind::Static { bundle: None | Some(true), .. })
+            && !relevant_lib(sess, lib)
+    });
 
-                    false
-                }),
-            ) {
-                sess.emit_fatal(errors::RlibArchiveBuildFailure { error });
-            }
-            if archive.build(&dst) {
-                link_upstream(&dst);
-            }
-        });
+    if (!are_upstream_rust_objects_already_included(sess)
+        || ignored_for_lto(sess, &codegen_results.crate_info, cnum))
+        && !skip_native
+    {
+        link_upstream(cratepath);
+        return;
     }
 
-    // Same thing as above, but for dynamic crates instead of static crates.
-    fn add_dynamic_crate(cmd: &mut dyn Linker, sess: &Session, cratepath: &Path) {
-        // Just need to tell the linker about where the library lives and
-        // what its name is
-        let parent = cratepath.parent();
-        if let Some(dir) = parent {
-            cmd.include_path(&fix_windows_verbatim_for_gcc(dir));
-        }
-        let filestem = cratepath.file_stem().unwrap().to_str().unwrap();
-        cmd.link_rust_dylib(
-            &unlib(&sess.target, filestem),
-            parent.unwrap_or_else(|| Path::new("")),
-        );
-    }
-}
+    let dst = tmpdir.join(cratepath.file_name().unwrap());
+    let name = cratepath.file_name().unwrap().to_str().unwrap();
+    let name = &name[3..name.len() - 5]; // chop off lib/.rlib
+    let bundled_lib_file_names = bundled_lib_file_names.clone();
 
-/// Link in all of our upstream crates' native dependencies. Remember that all of these upstream
-/// native dependencies are all non-static dependencies. We've got two cases then:
-///
-/// 1. The upstream crate is an rlib. In this case we *must* link in the native dependency because
-/// the rlib is just an archive.
-///
-/// 2. The upstream crate is a dylib. In order to use the dylib, we have to have the dependency
-/// present on the system somewhere. Thus, we don't gain a whole lot from not linking in the
-/// dynamic dependency to this crate as well.
-///
-/// The use case for this is a little subtle. In theory the native dependencies of a crate are
-/// purely an implementation detail of the crate itself, but the problem arises with generic and
-/// inlined functions. If a generic function calls a native function, then the generic function
-/// must be instantiated in the target crate, meaning that the native symbol must also be resolved
-/// in the target crate.
-fn add_upstream_native_libraries(
-    cmd: &mut dyn Linker,
-    sess: &Session,
-    codegen_results: &CodegenResults,
-) {
-    let mut last = (None, NativeLibKind::Unspecified, None);
-    for &cnum in &codegen_results.crate_info.used_crates {
-        for lib in codegen_results.crate_info.native_libraries[&cnum].iter() {
-            let Some(name) = lib.name else {
-                continue;
-            };
-            let name = name.as_str();
-            if !relevant_lib(sess, &lib) {
-                continue;
-            }
+    sess.prof.generic_activity_with_arg("link_altering_rlib", name).run(|| {
+        let canonical_name = name.replace('-', "_");
+        let upstream_rust_objects_already_included =
+            are_upstream_rust_objects_already_included(sess);
+        let is_builtins =
+            sess.target.no_builtins || !codegen_results.crate_info.is_no_builtins.contains(&cnum);
 
-            // Skip if this library is the same as the last.
-            last = if (lib.name, lib.kind, lib.verbatim) == last {
-                continue;
-            } else {
-                (lib.name, lib.kind, lib.verbatim)
-            };
+        let mut archive = archive_builder_builder.new_archive_builder(sess);
+        if let Err(e) = archive.add_archive(
+            cratepath,
+            Box::new(move |f| {
+                if f == METADATA_FILENAME {
+                    return true;
+                }
 
-            let verbatim = lib.verbatim.unwrap_or(false);
-            match lib.kind {
-                NativeLibKind::Dylib { as_needed } => {
-                    cmd.link_dylib(name, verbatim, as_needed.unwrap_or(true))
+                let canonical = f.replace('-', "_");
+
+                let is_rust_object =
+                    canonical.starts_with(&canonical_name) && looks_like_rust_object_file(&f);
+
+                // If we've been requested to skip all native object files
+                // (those not generated by the rust compiler) then we can skip
+                // this file. See above for why we may want to do this.
+                let skip_because_cfg_say_so = skip_native && !is_rust_object;
+
+                // If we're performing LTO and this is a rust-generated object
+                // file, then we don't need the object file as it's part of the
+                // LTO module. Note that `#![no_builtins]` is excluded from LTO,
+                // though, so we let that object file slide.
+                let skip_because_lto =
+                    upstream_rust_objects_already_included && is_rust_object && is_builtins;
+
+                // We skip native libraries because:
+                // 1. This native libraries won't be used from the generated rlib,
+                //    so we can throw them away to avoid the copying work.
+                // 2. We can't allow it to be a single remaining entry in archive
+                //    as some linkers may complain on that.
+                if bundled_lib_file_names.contains(&Symbol::intern(f)) {
+                    return true;
                 }
-                NativeLibKind::Unspecified => cmd.link_dylib(name, verbatim, true),
-                NativeLibKind::Framework { as_needed } => {
-                    cmd.link_framework(name, as_needed.unwrap_or(true))
+
+                if skip_because_cfg_say_so || skip_because_lto {
+                    return true;
                 }
-                // ignore static native libraries here as we've
-                // already included them in add_local_native_libraries and
-                // add_upstream_rust_crates
-                NativeLibKind::Static { .. } => {}
-                NativeLibKind::RawDylib | NativeLibKind::LinkArg => {}
-            }
+
+                false
+            }),
+        ) {
+            sess.fatal(&format!("failed to build archive from rlib: {}", e));
         }
-    }
+        if archive.build(&dst) {
+            link_upstream(&dst);
+        }
+    });
+}
+
+// Same thing as above, but for dynamic crates instead of static crates.
+fn add_dynamic_crate(cmd: &mut dyn Linker, sess: &Session, cratepath: &Path) {
+    // Just need to tell the linker about where the library lives and
+    // what its name is
+    let parent = cratepath.parent();
+    if let Some(dir) = parent {
+        cmd.include_path(&fix_windows_verbatim_for_gcc(dir));
+    }
+    let stem = cratepath.file_stem().unwrap().to_str().unwrap();
+    // Convert library file-stem into a cc -l argument.
+    let prefix = if stem.starts_with("lib") && !sess.target.is_like_windows { 3 } else { 0 };
+    cmd.link_rust_dylib(&stem[prefix..], parent.unwrap_or_else(|| Path::new("")));
 }
 
 fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool {
index c49b19bdf0094b9b39663c59b35d96007a7e2d6b..7f0c2861f7e29014de16da9d8817dc50a7c8c6c6 100644 (file)
@@ -1260,11 +1260,11 @@ fn link_framework(&mut self, _framework: &str, _as_needed: bool) {
     }
 
     fn link_whole_staticlib(&mut self, lib: &str, _verbatim: bool, _search_path: &[PathBuf]) {
-        self.cmd.arg("-l").arg(lib);
+        self.cmd.arg("--whole-archive").arg("-l").arg(lib).arg("--no-whole-archive");
     }
 
     fn link_whole_rlib(&mut self, lib: &Path) {
-        self.cmd.arg(lib);
+        self.cmd.arg("--whole-archive").arg(lib).arg("--no-whole-archive");
     }
 
     fn gc_sections(&mut self, _keep_metadata: bool) {
index d0ac016b02e151863d263c9223c7c26dba6f2889..e3d28a1aca20eacfc1dc08ad628a58bb06b0d1a8 100644 (file)
 use rustc_data_structures::profiling::VerboseTimingGuard;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::emitter::Emitter;
-use rustc_errors::{
-    translation::{to_fluent_args, Translate},
-    DiagnosticId, FatalError, Handler, Level,
-};
+use rustc_errors::{translation::Translate, DiagnosticId, FatalError, Handler, Level};
+use rustc_errors::{DiagnosticMessage, Style};
 use rustc_fs_util::link_or_copy;
 use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
 use rustc_incremental::{
@@ -38,6 +36,7 @@
 use rustc_target::spec::{MergeFunctions, SanitizerSet};
 
 use std::any::Any;
+use std::borrow::Cow;
 use std::fs;
 use std::io;
 use std::marker::PhantomData;
@@ -969,8 +968,11 @@ pub enum Message<B: WriteBackendMethods> {
     CodegenAborted,
 }
 
+type DiagnosticArgName<'source> = Cow<'source, str>;
+
 struct Diagnostic {
-    msg: String,
+    msg: Vec<(DiagnosticMessage, Style)>,
+    args: FxHashMap<DiagnosticArgName<'static>, rustc_errors::DiagnosticArgValue<'static>>,
     code: Option<DiagnosticId>,
     lvl: Level,
 }
@@ -1743,15 +1745,18 @@ fn fallback_fluent_bundle(&self) -> &rustc_errors::FluentBundle {
 
 impl Emitter for SharedEmitter {
     fn emit_diagnostic(&mut self, diag: &rustc_errors::Diagnostic) {
-        let fluent_args = to_fluent_args(diag.args());
+        let args: FxHashMap<Cow<'_, str>, rustc_errors::DiagnosticArgValue<'_>> =
+            diag.args().map(|(name, arg)| (name.clone(), arg.clone())).collect();
         drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic {
-            msg: self.translate_messages(&diag.message, &fluent_args).to_string(),
+            msg: diag.message.clone(),
+            args: args.clone(),
             code: diag.code.clone(),
             lvl: diag.level(),
         })));
         for child in &diag.children {
             drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic {
-                msg: self.translate_messages(&child.message, &fluent_args).to_string(),
+                msg: child.message.clone(),
+                args: args.clone(),
                 code: None,
                 lvl: child.level,
             })));
@@ -1782,10 +1787,11 @@ pub fn check(&self, sess: &Session, blocking: bool) {
             match message {
                 Ok(SharedEmitterMessage::Diagnostic(diag)) => {
                     let handler = sess.diagnostic();
-                    let mut d = rustc_errors::Diagnostic::new(diag.lvl, &diag.msg);
+                    let mut d = rustc_errors::Diagnostic::new_with_messages(diag.lvl, diag.msg);
                     if let Some(code) = diag.code {
                         d.code(code);
                     }
+                    d.replace_args(diag.args);
                     handler.emit_diagnostic(&mut d);
                 }
                 Ok(SharedEmitterMessage::InlineAsmError(cookie, msg, level, source)) => {
index c1411690f8289883f8cc391bffd19018b797fad0..4f396e970ad70969228cae3756eec5273af4a483 100644 (file)
@@ -833,20 +833,30 @@ pub fn new(tcx: TyCtxt<'_>, target_cpu: String) -> CrateInfo {
         //
         // In order to get this left-to-right dependency ordering, we use the reverse
         // postorder of all crates putting the leaves at the right-most positions.
-        let used_crates = tcx
+        let mut compiler_builtins = None;
+        let mut used_crates: Vec<_> = tcx
             .postorder_cnums(())
             .iter()
             .rev()
             .copied()
-            .filter(|&cnum| !tcx.dep_kind(cnum).macros_only())
+            .filter(|&cnum| {
+                let link = !tcx.dep_kind(cnum).macros_only();
+                if link && tcx.is_compiler_builtins(cnum) {
+                    compiler_builtins = Some(cnum);
+                    return false;
+                }
+                link
+            })
             .collect();
+        // `compiler_builtins` are always placed last to ensure that they're linked correctly.
+        used_crates.extend(compiler_builtins);
 
         let mut info = CrateInfo {
             target_cpu,
             exported_symbols,
             linked_symbols,
             local_crate_name,
-            compiler_builtins: None,
+            compiler_builtins,
             profiler_runtime: None,
             is_no_builtins: Default::default(),
             native_libraries: Default::default(),
@@ -872,9 +882,6 @@ pub fn new(tcx: TyCtxt<'_>, target_cpu: String) -> CrateInfo {
 
             let used_crate_source = tcx.used_crate_source(cnum);
             info.used_crate_source.insert(cnum, used_crate_source.clone());
-            if tcx.is_compiler_builtins(cnum) {
-                info.compiler_builtins = Some(cnum);
-            }
             if tcx.is_profiler_runtime(cnum) {
                 info.profiler_runtime = Some(cnum);
             }
index e6f402ef19d870b69516a5bf5cefc0adb4fcfb82..6015d48decae930ac7cfc764663680d25d830c8b 100644 (file)
@@ -15,7 +15,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
 ) -> (Bx::Value, Bx::Value) {
     let layout = bx.layout_of(t);
     debug!("size_and_align_of_dst(ty={}, info={:?}): layout: {:?}", t, info, layout);
-    if !layout.is_unsized() {
+    if layout.is_sized() {
         let size = bx.const_usize(layout.size.bytes());
         let align = bx.const_usize(layout.align.abi.bytes());
         return (size, align);
index 9c18df5643f1c51dc1889a5cec2a2b18b13e968c..908555385891d85417e4710ad4b860b790e43676 100644 (file)
@@ -29,7 +29,7 @@ pub struct PlaceRef<'tcx, V> {
 
 impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
     pub fn new_sized(llval: V, layout: TyAndLayout<'tcx>) -> PlaceRef<'tcx, V> {
-        assert!(!layout.is_unsized());
+        assert!(layout.is_sized());
         PlaceRef { llval, llextra: None, layout, align: layout.align.abi }
     }
 
@@ -38,7 +38,7 @@ pub fn new_sized_aligned(
         layout: TyAndLayout<'tcx>,
         align: Align,
     ) -> PlaceRef<'tcx, V> {
-        assert!(!layout.is_unsized());
+        assert!(layout.is_sized());
         PlaceRef { llval, llextra: None, layout, align }
     }
 
@@ -48,7 +48,7 @@ pub fn alloca<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
         bx: &mut Bx,
         layout: TyAndLayout<'tcx>,
     ) -> Self {
-        assert!(!layout.is_unsized(), "tried to statically allocate unsized place");
+        assert!(layout.is_sized(), "tried to statically allocate unsized place");
         let tmp = bx.alloca(bx.cx().backend_type(layout), layout.align.abi);
         Self::new_sized(tmp, layout)
     }
@@ -145,7 +145,7 @@ pub fn project_field<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
                 );
                 return simple();
             }
-            _ if !field.is_unsized() => return simple(),
+            _ if field.is_sized() => return simple(),
             ty::Slice(..) | ty::Str | ty::Foreign(..) => return simple(),
             ty::Adt(def, _) => {
                 if def.repr().packed() {
@@ -209,7 +209,9 @@ pub fn codegen_get_discr<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
         bx: &mut Bx,
         cast_to: Ty<'tcx>,
     ) -> V {
-        let cast_to = bx.cx().immediate_backend_type(bx.cx().layout_of(cast_to));
+        let cast_to_layout = bx.cx().layout_of(cast_to);
+        let cast_to_size = cast_to_layout.layout.size();
+        let cast_to = bx.cx().immediate_backend_type(cast_to_layout);
         if self.layout.abi.is_uninhabited() {
             return bx.cx().const_undef(cast_to);
         }
@@ -229,7 +231,8 @@ pub fn codegen_get_discr<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
 
         // Read the tag/niche-encoded discriminant from memory.
         let tag = self.project_field(bx, tag_field);
-        let tag = bx.load_operand(tag);
+        let tag_op = bx.load_operand(tag);
+        let tag_imm = tag_op.immediate();
 
         // Decode the discriminant (specifically if it's niche-encoded).
         match *tag_encoding {
@@ -242,68 +245,161 @@ pub fn codegen_get_discr<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
                     Int(_, signed) => !tag_scalar.is_bool() && signed,
                     _ => false,
                 };
-                bx.intcast(tag.immediate(), cast_to, signed)
+                bx.intcast(tag_imm, cast_to, signed)
             }
             TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start } => {
-                // Rebase from niche values to discriminants, and check
-                // whether the result is in range for the niche variants.
-                let niche_llty = bx.cx().immediate_backend_type(tag.layout);
-                let tag = tag.immediate();
-
-                // We first compute the "relative discriminant" (wrt `niche_variants`),
-                // that is, if `n = niche_variants.end() - niche_variants.start()`,
-                // we remap `niche_start..=niche_start + n` (which may wrap around)
-                // to (non-wrap-around) `0..=n`, to be able to check whether the
-                // discriminant corresponds to a niche variant with one comparison.
-                // We also can't go directly to the (variant index) discriminant
-                // and check that it is in the range `niche_variants`, because
-                // that might not fit in the same type, on top of needing an extra
-                // comparison (see also the comment on `let niche_discr`).
-                let relative_discr = if niche_start == 0 {
-                    // Avoid subtracting `0`, which wouldn't work for pointers.
-                    // FIXME(eddyb) check the actual primitive type here.
-                    tag
+                // Cast to an integer so we don't have to treat a pointer as a
+                // special case.
+                let (tag, tag_llty) = if tag_scalar.primitive().is_ptr() {
+                    let t = bx.type_isize();
+                    let tag = bx.ptrtoint(tag_imm, t);
+                    (tag, t)
                 } else {
-                    bx.sub(tag, bx.cx().const_uint_big(niche_llty, niche_start))
+                    (tag_imm, bx.cx().immediate_backend_type(tag_op.layout))
                 };
+
+                let tag_size = tag_scalar.size(bx.cx());
+                let max_unsigned = tag_size.unsigned_int_max();
+                let max_signed = tag_size.signed_int_max() as u128;
+                let min_signed = max_signed + 1;
                 let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32();
-                let is_niche = if relative_max == 0 {
-                    // Avoid calling `const_uint`, which wouldn't work for pointers.
-                    // Also use canonical == 0 instead of non-canonical u<= 0.
-                    // FIXME(eddyb) check the actual primitive type here.
-                    bx.icmp(IntPredicate::IntEQ, relative_discr, bx.cx().const_null(niche_llty))
+                let niche_end = niche_start.wrapping_add(relative_max as u128) & max_unsigned;
+                let range = tag_scalar.valid_range(bx.cx());
+
+                let sle = |lhs: u128, rhs: u128| -> bool {
+                    // Signed and unsigned comparisons give the same results,
+                    // except that in signed comparisons an integer with the
+                    // sign bit set is less than one with the sign bit clear.
+                    // Toggle the sign bit to do a signed comparison.
+                    (lhs ^ min_signed) <= (rhs ^ min_signed)
+                };
+
+                // We have a subrange `niche_start..=niche_end` inside `range`.
+                // If the value of the tag is inside this subrange, it's a
+                // "niche value", an increment of the discriminant. Otherwise it
+                // indicates the untagged variant.
+                // A general algorithm to extract the discriminant from the tag
+                // is:
+                // relative_tag = tag - niche_start
+                // is_niche = relative_tag <= (ule) relative_max
+                // discr = if is_niche {
+                //     cast(relative_tag) + niche_variants.start()
+                // } else {
+                //     untagged_variant
+                // }
+                // However, we will likely be able to emit simpler code.
+
+                // Find the least and greatest values in `range`, considered
+                // both as signed and unsigned.
+                let (low_unsigned, high_unsigned) = if range.start <= range.end {
+                    (range.start, range.end)
+                } else {
+                    (0, max_unsigned)
+                };
+                let (low_signed, high_signed) = if sle(range.start, range.end) {
+                    (range.start, range.end)
                 } else {
-                    let relative_max = bx.cx().const_uint(niche_llty, relative_max as u64);
-                    bx.icmp(IntPredicate::IntULE, relative_discr, relative_max)
+                    (min_signed, max_signed)
+                };
+
+                let niches_ule = niche_start <= niche_end;
+                let niches_sle = sle(niche_start, niche_end);
+                let cast_smaller = cast_to_size <= tag_size;
+
+                // In the algorithm above, we can change
+                // cast(relative_tag) + niche_variants.start()
+                // into
+                // cast(tag) + (niche_variants.start() - niche_start)
+                // if either the casted type is no larger than the original
+                // type, or if the niche values are contiguous (in either the
+                // signed or unsigned sense).
+                let can_incr_after_cast = cast_smaller || niches_ule || niches_sle;
+
+                let data_for_boundary_niche = || -> Option<(IntPredicate, u128)> {
+                    if !can_incr_after_cast {
+                        None
+                    } else if niche_start == low_unsigned {
+                        Some((IntPredicate::IntULE, niche_end))
+                    } else if niche_end == high_unsigned {
+                        Some((IntPredicate::IntUGE, niche_start))
+                    } else if niche_start == low_signed {
+                        Some((IntPredicate::IntSLE, niche_end))
+                    } else if niche_end == high_signed {
+                        Some((IntPredicate::IntSGE, niche_start))
+                    } else {
+                        None
+                    }
                 };
 
-                // NOTE(eddyb) this addition needs to be performed on the final
-                // type, in case the niche itself can't represent all variant
-                // indices (e.g. `u8` niche with more than `256` variants,
-                // but enough uninhabited variants so that the remaining variants
-                // fit in the niche).
-                // In other words, `niche_variants.end - niche_variants.start`
-                // is representable in the niche, but `niche_variants.end`
-                // might not be, in extreme cases.
-                let niche_discr = {
-                    let relative_discr = if relative_max == 0 {
-                        // HACK(eddyb) since we have only one niche, we know which
-                        // one it is, and we can avoid having a dynamic value here.
-                        bx.cx().const_uint(cast_to, 0)
+                let (is_niche, tagged_discr, delta) = if relative_max == 0 {
+                    // Best case scenario: only one tagged variant. This will
+                    // likely become just a comparison and a jump.
+                    // The algorithm is:
+                    // is_niche = tag == niche_start
+                    // discr = if is_niche {
+                    //     niche_start
+                    // } else {
+                    //     untagged_variant
+                    // }
+                    let niche_start = bx.cx().const_uint_big(tag_llty, niche_start);
+                    let is_niche = bx.icmp(IntPredicate::IntEQ, tag, niche_start);
+                    let tagged_discr =
+                        bx.cx().const_uint(cast_to, niche_variants.start().as_u32() as u64);
+                    (is_niche, tagged_discr, 0)
+                } else if let Some((predicate, constant)) = data_for_boundary_niche() {
+                    // The niche values are either the lowest or the highest in
+                    // `range`. We can avoid the first subtraction in the
+                    // algorithm.
+                    // The algorithm is now this:
+                    // is_niche = tag <= niche_end
+                    // discr = if is_niche {
+                    //     cast(tag) + (niche_variants.start() - niche_start)
+                    // } else {
+                    //     untagged_variant
+                    // }
+                    // (the first line may instead be tag >= niche_start,
+                    // and may be a signed or unsigned comparison)
+                    let is_niche =
+                        bx.icmp(predicate, tag, bx.cx().const_uint_big(tag_llty, constant));
+                    let cast_tag = if cast_smaller {
+                        bx.intcast(tag, cast_to, false)
+                    } else if niches_ule {
+                        bx.zext(tag, cast_to)
                     } else {
-                        bx.intcast(relative_discr, cast_to, false)
+                        bx.sext(tag, cast_to)
                     };
-                    bx.add(
+
+                    let delta = (niche_variants.start().as_u32() as u128).wrapping_sub(niche_start);
+                    (is_niche, cast_tag, delta)
+                } else {
+                    // The special cases don't apply, so we'll have to go with
+                    // the general algorithm.
+                    let relative_discr = bx.sub(tag, bx.cx().const_uint_big(tag_llty, niche_start));
+                    let cast_tag = bx.intcast(relative_discr, cast_to, false);
+                    let is_niche = bx.icmp(
+                        IntPredicate::IntULE,
                         relative_discr,
-                        bx.cx().const_uint(cast_to, niche_variants.start().as_u32() as u64),
-                    )
+                        bx.cx().const_uint(tag_llty, relative_max as u64),
+                    );
+                    (is_niche, cast_tag, niche_variants.start().as_u32() as u128)
                 };
 
-                bx.select(
+                let tagged_discr = if delta == 0 {
+                    tagged_discr
+                } else {
+                    bx.add(tagged_discr, bx.cx().const_uint_big(cast_to, delta))
+                };
+
+                let discr = bx.select(
                     is_niche,
-                    niche_discr,
+                    tagged_discr,
                     bx.cx().const_uint(cast_to, untagged_variant.as_u32() as u64),
-                )
+                );
+
+                // In principle we could insert assumes on the possible range of `discr`, but
+                // currently in LLVM this seems to be a pessimization.
+
+                discr
             }
         }
     }
index 1b1052fdf47a751692f1001624d191dc30c815d0..8f5e503d659dad30b1d16c7199bfcb7dc7276bfd 100644 (file)
@@ -46,7 +46,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
         ecx.tcx.def_kind(cid.instance.def_id())
     );
     let layout = ecx.layout_of(body.bound_return_ty().subst(tcx, cid.instance.substs))?;
-    assert!(!layout.is_unsized());
+    assert!(layout.is_sized());
     let ret = ecx.allocate(layout, MemoryKind::Stack)?;
 
     trace!(
index f7d64f6d4f48ae2be6f6d29a69b1fa73222f1fe6..ab82268dde3ab5898bce8cb11ccda94b43ec7bf9 100644 (file)
@@ -572,7 +572,7 @@ pub(super) fn size_and_align_of(
         metadata: &MemPlaceMeta<M::Provenance>,
         layout: &TyAndLayout<'tcx>,
     ) -> InterpResult<'tcx, Option<(Size, Align)>> {
-        if !layout.is_unsized() {
+        if layout.is_sized() {
             return Ok(Some((layout.size, layout.align.abi)));
         }
         match layout.ty.kind() {
index b92a68788475fcd60c2907b4d36f5cfef02b3e92..e68456a1d731a2989ceace8449d42c7bdc406982 100644 (file)
@@ -713,7 +713,7 @@ pub(crate) fn raw_eq_intrinsic(
         rhs: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>,
     ) -> InterpResult<'tcx, Scalar<M::Provenance>> {
         let layout = self.layout_of(lhs.layout.ty.builtin_deref(true).unwrap().ty)?;
-        assert!(!layout.is_unsized());
+        assert!(layout.is_sized());
 
         let get_bytes = |this: &InterpCx<'mir, 'tcx, M>,
                          op: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>,
index e5e015c1e1802408293c16fae02a20bfd357b491..a529972db9d6fec739332ae5b9ad2ee8f1dc5dda 100644 (file)
@@ -683,7 +683,7 @@ pub fn get_alloc_info(&self, id: AllocId) -> (Size, Align, AllocKind) {
                 // Use size and align of the type.
                 let ty = self.tcx.type_of(def_id);
                 let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap();
-                assert!(!layout.is_unsized());
+                assert!(layout.is_sized());
                 (layout.size, layout.align.abi, AllocKind::LiveData)
             }
             Some(GlobalAlloc::Memory(alloc)) => {
index dd00678aa0ceaf0dac275d7fa7f1a48147aa9a16..274917f09fe3648e88dc5fd7cf97e85a59d859b7 100644 (file)
@@ -280,7 +280,7 @@ pub fn offset(
         layout: TyAndLayout<'tcx>,
         cx: &impl HasDataLayout,
     ) -> InterpResult<'tcx, Self> {
-        assert!(!layout.is_unsized());
+        assert!(layout.is_sized());
         self.offset_with_meta(offset, MemPlaceMeta::None, layout, cx)
     }
 }
index b0625b5f412e03ad900f57d5ef7c77130e6dca9c..4d0125bf395d69174206a67d238edb94694d4e54 100644 (file)
@@ -201,7 +201,7 @@ pub fn offset(
         layout: TyAndLayout<'tcx>,
         cx: &impl HasDataLayout,
     ) -> InterpResult<'tcx, Self> {
-        assert!(!layout.is_unsized());
+        assert!(layout.is_sized());
         self.offset_with_meta(offset, MemPlaceMeta::None, layout, cx)
     }
 
@@ -340,7 +340,7 @@ pub(super) fn get_place_alloc(
         &self,
         place: &MPlaceTy<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx, Option<AllocRef<'_, 'tcx, M::Provenance, M::AllocExtra>>> {
-        assert!(!place.layout.is_unsized());
+        assert!(place.layout.is_sized());
         assert!(!place.meta.has_meta());
         let size = place.layout.size;
         self.get_ptr_alloc(place.ptr, size, place.align)
@@ -351,7 +351,7 @@ pub(super) fn get_place_alloc_mut(
         &mut self,
         place: &MPlaceTy<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx, Option<AllocRefMut<'_, 'tcx, M::Provenance, M::AllocExtra>>> {
-        assert!(!place.layout.is_unsized());
+        assert!(place.layout.is_sized());
         assert!(!place.meta.has_meta());
         let size = place.layout.size;
         self.get_ptr_alloc_mut(place.ptr, size, place.align)
@@ -485,7 +485,7 @@ fn write_immediate_no_validate(
         src: Immediate<M::Provenance>,
         dest: &PlaceTy<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx> {
-        assert!(!dest.layout.is_unsized(), "Cannot write unsized data");
+        assert!(dest.layout.is_sized(), "Cannot write unsized data");
         trace!("write_immediate: {:?} <- {:?}: {}", *dest, src, dest.layout.ty);
 
         // See if we can avoid an allocation. This is the counterpart to `read_immediate_raw`,
@@ -746,7 +746,7 @@ pub fn allocate(
         layout: TyAndLayout<'tcx>,
         kind: MemoryKind<M::MemoryKind>,
     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
-        assert!(!layout.is_unsized());
+        assert!(layout.is_sized());
         let ptr = self.allocate_ptr(layout.size, layout.align.abi, kind)?;
         Ok(MPlaceTy::from_aligned_ptr(ptr.into(), layout))
     }
index c6e04cbfb6bf344200dcc916378ad8df4adcd454..3c286fa61bec5c9cb1a9501924ceded45ab5d13b 100644 (file)
@@ -209,7 +209,7 @@ pub fn eval_rvalue_into_place(
 
             Repeat(ref operand, _) => {
                 let src = self.eval_operand(operand, None)?;
-                assert!(!src.layout.is_unsized());
+                assert!(src.layout.is_sized());
                 let dest = self.force_allocation(&dest)?;
                 let length = dest.len(self)?;
 
index cab23b7241ffc2ea2649103b83552c091d00119a..fa15d466ac125cf910f3e2cbd13e27c362ee6154 100644 (file)
@@ -53,7 +53,7 @@ pub fn get_vtable_size_and_align(
     ) -> InterpResult<'tcx, (Size, Align)> {
         let (ty, _trait_ref) = self.get_ptr_vtable(vtable)?;
         let layout = self.layout_of(ty)?;
-        assert!(!layout.is_unsized(), "there are no vtables for unsized types");
+        assert!(layout.is_sized(), "there are no vtables for unsized types");
         Ok((layout.size, layout.align.abi))
     }
 }
index b1ad22b899e30215f339ed97c5c0d2496bb8ff00..5a8b3e30b9fc0cdaab6bc89e90bfbb3624ee2668 100644 (file)
@@ -765,7 +765,7 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
 
                         let errors = ocx.select_all_or_error();
                         if !errors.is_empty() {
-                            infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+                            infcx.err_ctxt().report_fulfillment_errors(&errors, None);
                         }
                     }
 
@@ -831,7 +831,6 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                                         obligation.clone(),
                                         &obligation,
                                         &e,
-                                        false,
                                     );
                                 }
 
index 5152d5ab0465c126f50dda00f3513f80ea10d80d..5afce15e26bfcc55e3fa8c7454c010dc0aca2296 100644 (file)
@@ -23,7 +23,7 @@ rustc_macros = { path = "../rustc_macros" }
 rustc_serialize = { path = "../rustc_serialize" }
 smallvec = { version = "1.8.1", features = ["const_generics", "union", "may_dangle"] }
 stable_deref_trait = "1.0.0"
-stacker = "0.1.14"
+stacker = "0.1.15"
 tempfile = "3.2"
 thin-vec = "0.2.9"
 tracing = "0.1"
index 009b5d5340afe3c724950d881014d6e716b75c62..11cbff8ea6a84ef7d27adf4a266866a3409848ec 100644 (file)
@@ -110,11 +110,6 @@ fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
     }
 }
 
-/// A helper trait so that `Interned` things can cache stable hashes reproducibly.
-pub trait InternedHashingContext {
-    fn with_def_path_and_no_spans(&mut self, f: impl FnOnce(&mut Self));
-}
-
 /// A helper type that you can wrap round your own type in order to automatically
 /// cache the stable hash on creation and not recompute it whenever the stable hash
 /// of the type is computed.
@@ -161,11 +156,15 @@ fn deref(&self) -> &T {
 impl<T: Hash> Hash for WithStableHash<T> {
     #[inline]
     fn hash<H: Hasher>(&self, s: &mut H) {
-        self.internee.hash(s)
+        if self.stable_hash != Fingerprint::ZERO {
+            self.stable_hash.hash(s)
+        } else {
+            self.internee.hash(s)
+        }
     }
 }
 
-impl<T: HashStable<CTX>, CTX: InternedHashingContext> HashStable<CTX> for WithStableHash<T> {
+impl<T: HashStable<CTX>, CTX> HashStable<CTX> for WithStableHash<T> {
     fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
         if self.stable_hash == Fingerprint::ZERO || cfg!(debug_assertions) {
             // No cached hash available. This can only mean that incremental is disabled.
@@ -176,7 +175,7 @@ fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
             // otherwise the hashes will differ between cached and non-cached mode.
             let stable_hash: Fingerprint = {
                 let mut hasher = StableHasher::new();
-                hcx.with_def_path_and_no_spans(|hcx| self.internee.hash_stable(hcx, &mut hasher));
+                self.internee.hash_stable(hcx, &mut hasher);
                 hasher.finish()
             };
             if cfg!(debug_assertions) && self.stable_hash != Fingerprint::ZERO {
index cf4bcc7c158fcb83cbaa34fe6435046d826118d3..e043368fdfe0210ae475bd7b151310538ba099cc 100644 (file)
@@ -6,6 +6,7 @@
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(once_cell)]
+#![feature(decl_macro)]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
 #![deny(rustc::untranslatable_diagnostic)]
@@ -736,26 +737,58 @@ fn print_crate_info(
             // Any output here interferes with Cargo's parsing of other printed output
             NativeStaticLibs => {}
             LinkArgs => {}
+            SplitDebuginfo => {
+                use rustc_target::spec::SplitDebuginfo::{Off, Packed, Unpacked};
+
+                for split in &[Off, Packed, Unpacked] {
+                    let stable = sess.target.options.supported_split_debuginfo.contains(split);
+                    let unstable_ok = sess.unstable_options();
+                    if stable || unstable_ok {
+                        println!("{}", split);
+                    }
+                }
+            }
         }
     }
     Compilation::Stop
 }
 
 /// Prints version information
-pub fn version(binary: &str, matches: &getopts::Matches) {
+///
+/// NOTE: this is a macro to support drivers built at a different time than the main `rustc_driver` crate.
+pub macro version($binary: literal, $matches: expr) {
+    fn unw(x: Option<&str>) -> &str {
+        x.unwrap_or("unknown")
+    }
+    $crate::version_at_macro_invocation(
+        $binary,
+        $matches,
+        unw(option_env!("CFG_VERSION")),
+        unw(option_env!("CFG_VER_HASH")),
+        unw(option_env!("CFG_VER_DATE")),
+        unw(option_env!("CFG_RELEASE")),
+    )
+}
+
+#[doc(hidden)] // use the macro instead
+pub fn version_at_macro_invocation(
+    binary: &str,
+    matches: &getopts::Matches,
+    version: &str,
+    commit_hash: &str,
+    commit_date: &str,
+    release: &str,
+) {
     let verbose = matches.opt_present("verbose");
 
-    println!("{} {}", binary, util::version_str().unwrap_or("unknown version"));
+    println!("{} {}", binary, version);
 
     if verbose {
-        fn unw(x: Option<&str>) -> &str {
-            x.unwrap_or("unknown")
-        }
         println!("binary: {}", binary);
-        println!("commit-hash: {}", unw(util::commit_hash_str()));
-        println!("commit-date: {}", unw(util::commit_date_str()));
+        println!("commit-hash: {}", commit_hash);
+        println!("commit-date: {}", commit_date);
         println!("host: {}", config::host_triple());
-        println!("release: {}", unw(util::release_str()));
+        println!("release: {}", release);
 
         let debug_flags = matches.opt_strs("Z");
         let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend="));
@@ -1071,7 +1104,7 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
     }
 
     if matches.opt_present("version") {
-        version("rustc", &matches);
+        version!("rustc", &matches);
         return None;
     }
 
@@ -1216,7 +1249,7 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
         format!("we would appreciate a bug report: {}", bug_report_url).into(),
         format!(
             "rustc {} running on {}",
-            util::version_str().unwrap_or("unknown_version"),
+            util::version_str!().unwrap_or("unknown_version"),
             config::host_triple()
         )
         .into(),
index 8a7923ac93f981b4963fcb0b79eb58e25b140dfc..95e7c9fc76ce2bf00c081a386e488c4dfcf05b6e 100644 (file)
@@ -1,4 +1,5 @@
-A type parameter that is specified for `impl` is not constrained.
+A type, const or lifetime parameter that is specified for `impl` is not
+constrained.
 
 Erroneous code example:
 
@@ -14,8 +15,8 @@ impl<T: Default> Foo {
 }
 ```
 
-Any type parameter of an `impl` must meet at least one of
-the following criteria:
+Any type or const parameter of an `impl` must meet at least one of the
+following criteria:
 
  - it appears in the _implementing type_ of the impl, e.g. `impl<T> Foo<T>`
  - for a trait impl, it appears in the _implemented trait_, e.g.
@@ -23,6 +24,9 @@ the following criteria:
  - it is bound as an associated type, e.g. `impl<T, U> SomeTrait for T
    where T: AnotherTrait<AssocType=U>`
 
+Any unconstrained lifetime parameter of an `impl` is not supported if the
+lifetime parameter is used by an associated type.
+
 ### Error example 1
 
 Suppose we have a struct `Foo` and we would like to define some methods for it.
@@ -32,7 +36,6 @@ The problem is that the parameter `T` does not appear in the implementing type
 (`Foo`) of the impl. In this case, we can fix the error by moving the type
 parameter from the `impl` to the method `get`:
 
-
 ```
 struct Foo;
 
@@ -128,6 +131,70 @@ impl<T: Default> Maker<Foo<T>> for FooMaker {
 }
 ```
 
+### Error example 3
+
+Suppose we have a struct `Foo` and we would like to define some methods for it.
+The following code example has a definition which leads to a compiler error:
+
+```compile_fail,E0207
+struct Foo;
+
+impl<const T: i32> Foo {
+    // error: the const parameter `T` is not constrained by the impl trait, self
+    // type, or predicates [E0207]
+    fn get(&self) -> i32 {
+        i32::default()
+    }
+}
+```
+
+The problem is that the const parameter `T` does not appear in the implementing
+type (`Foo`) of the impl. In this case, we can fix the error by moving the type
+parameter from the `impl` to the method `get`:
+
+
+```
+struct Foo;
+
+// Move the const parameter from the impl to the method
+impl Foo {
+    fn get<const T: i32>(&self) -> i32 {
+        i32::default()
+    }
+}
+```
+
+### Error example 4
+
+Suppose we have a struct `Foo` and a struct `Bar` that uses lifetime `'a`. We
+would like to implement trait `Contains` for `Foo`. The trait `Contains` have
+the associated type `B`. The following code example has a definition which
+leads to a compiler error:
+
+```compile_fail,E0207
+struct Foo;
+struct Bar<'a>;
+
+trait Contains {
+    type B;
+
+    fn get(&self) -> i32;
+}
+
+impl<'a> Contains for Foo {
+    type B = Bar<'a>;
+
+    // error: the lifetime parameter `'a` is not constrained by the impl trait,
+    // self type, or predicates [E0207]
+    fn get(&self) -> i32 {
+        i32::default()
+    }
+}
+```
+
+Please note that unconstrained lifetime parameters are not supported if they are
+being used by an associated type.
+
 ### Additional information
 
 For more information, please see [RFC 447].
index d379b8a2384c675ece632d056a724438c3a5dc47..fabd855a222f0f3e1aa97d96e580c9107737ec97 100644 (file)
@@ -56,4 +56,4 @@ You might be interested in visiting the [async book] for further information.
 [`async-trait` crate]: https://crates.io/crates/async-trait
 [async-is-hard]: https://smallcultfollowing.com/babysteps/blog/2019/10/26/async-fn-in-traits-are-hard/
 [Generic Associated Types]: https://github.com/rust-lang/rust/issues/44265
-[async book]: https://rust-lang.github.io/async-book/07_workarounds/06_async_in_traits.html
+[async book]: https://rust-lang.github.io/async-book/07_workarounds/05_async_in_traits.html
index 67f2156f32e509eb78fb18267f48330d5fae2356..de47ada826444e00644e0edfc357973969a21f20 100644 (file)
@@ -58,3 +58,68 @@ borrowck_returned_lifetime_short =
 
 borrowck_used_impl_require_static =
     the used `impl` has a `'static` requirement
+
+borrowck_capture_kind_label =
+    capture is {$kind_desc} because of use here
+
+borrowck_var_borrow_by_use_place_in_generator =
+    borrow occurs due to use of {$place} in closure in generator
+
+borrowck_var_borrow_by_use_place_in_closure =
+    borrow occurs due to use of {$place} in closure
+
+borrowck_var_borrow_by_use_place =
+    borrow occurs due to use of {$place}
+
+borrowck_borrow_due_to_use_generator =
+    borrow occurs due to use in generator
+
+borrowck_use_due_to_use_generator =
+    use occurs due to use in generator
+
+borrowck_assign_due_to_use_generator =
+    assign occurs due to use in generator
+
+borrowck_assign_part_due_to_use_generator =
+    assign to part occurs due to use in generator
+
+borrowck_borrow_due_to_use_closure =
+    borrow occurs due to use in closure
+
+borrowck_use_due_to_use_closure =
+    use occurs due to use in closure
+
+borrowck_assign_due_to_use_closure =
+    assign occurs due to use in closure
+
+borrowck_assign_part_due_to_use_closure =
+    assign to part occurs due to use in closure
+
+borrowck_capture_immute =
+    capture is immutable because of use here
+
+borrowck_capture_mut =
+    capture is mutable because of use here
+
+borrowck_capture_move =
+    capture is moved because of use here
+
+borrowck_var_move_by_use_place_in_generator =
+    move occurs due to use of {$place} in generator
+
+borrowck_var_move_by_use_place_in_closure =
+    move occurs due to use of {$place} in closure
+
+borrowck_cannot_move_when_borrowed =
+    cannot move out of {$place ->
+        [value] value
+        *[other] {$place}
+    } because it is borrowed
+    .label = borrow of {$borrow_place ->
+        [value] value
+        *[other] {$borrow_place}
+    } occurs here
+    .move_label = move out of {$value_place ->
+        [value] value
+        *[other] {$value_place}
+    } occurs here
diff --git a/compiler/rustc_error_messages/locales/en-US/codegen_llvm.ftl b/compiler/rustc_error_messages/locales/en-US/codegen_llvm.ftl
new file mode 100644 (file)
index 0000000..68a205d
--- /dev/null
@@ -0,0 +1,58 @@
+codegen_llvm_unknown_ctarget_feature =
+    unknown feature specified for `-Ctarget-feature`: `{$feature}`
+    .note = it is still passed through to the codegen backend
+    .possible_feature = you might have meant: `{$rust_feature}`
+    .consider_filing_feature_request = consider filing a feature request
+
+codegen_llvm_unknown_ctarget_feature_prefix =
+    unknown feature specified for `-Ctarget-feature`: `{$feature}`
+    .note = features must begin with a `+` to enable or `-` to disable it
+
+codegen_llvm_error_creating_import_library =
+    Error creating import library for {$lib_name}: {$error}
+
+codegen_llvm_instrument_coverage_requires_llvm_12 =
+    rustc option `-C instrument-coverage` requires LLVM 12 or higher.
+
+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}
+
+codegen_llvm_linkage_const_or_mut_type =
+    must have type `*const T` or `*mut T` due to `#[linkage]` attribute
+
+codegen_llvm_sanitizer_memtag_requires_mte =
+    `-Zsanitizer=memtag` requires `-Ctarget-feature=+mte`
+
+codegen_llvm_archive_build_failure =
+    failed to build archive: {$error}
+
+codegen_llvm_error_writing_def_file =
+    Error writing .DEF file: {$error}
+
+codegen_llvm_error_calling_dlltool =
+    Error calling dlltool: {$error}
+
+codegen_llvm_dlltool_fail_import_library =
+    Dlltool could not create import library: {$stdout}\n{$stderr}
+
+codegen_llvm_unknown_archive_kind =
+    Don't know how to build archive of type: {$kind}
+
+codegen_llvm_target_feature_disable_or_enable =
+    the target features {$features} must all be either enabled or disabled together
+
+codegen_llvm_missing_features =
+    add the missing features in a `target_feature` attribute
+
+codegen_llvm_dynamic_linking_with_lto =
+    cannot prefer dynamic linking when performing LTO
+    .note = only 'staticlib', 'bin', and 'cdylib' outputs are supported with LTO
+
+codegen_llvm_fail_parsing_target_machine_config_to_target_machine =
+    failed to parse target machine config to target machine: {$error}
index 74088f4dfbe70d46b03b4a96a554a0c216e32d62..d27edd47470e83a60c74dd527f9317c1bbad4b7b 100644 (file)
@@ -150,3 +150,6 @@ hir_analysis_const_bound_for_non_const_trait =
 hir_analysis_self_in_impl_self =
     `Self` is not valid in the self type of an impl block
     .note = replace `Self` with a different type
+
+hir_analysis_op_trait_generic_params =
+    `{$method_name}` must not have any generic parameters
index 18b3408b06ab435a75ccead96437e58f08c62378..c9d83746d5454debb5f9e21fb847cc1a3cd863bb 100644 (file)
@@ -126,10 +126,10 @@ infer_data_lifetime_flow = ...but data with one lifetime flows into the other he
 infer_declared_multiple = this type is declared with multiple lifetimes...
 infer_types_declared_different = these two types are declared with different lifetimes...
 infer_data_flows = ...but data{$label_var1_exists ->
-    [true] -> {" "}from `{$label_var1}`
+    [true] {" "}from `{$label_var1}`
     *[false] -> {""}
 } flows{$label_var2_exists ->
-    [true] -> {" "}into `{$label_var2}`
+    [true] {" "}into `{$label_var2}`
     *[false] -> {""}
 } here
 
@@ -171,3 +171,4 @@ infer_msl_introduces_static = introduces a `'static` lifetime requirement
 infer_msl_unmet_req = because this has an unmet lifetime requirement
 infer_msl_trait_note = this has an implicit `'static` lifetime requirement
 infer_msl_trait_sugg = consider relaxing the implicit `'static` requirement
+infer_suggest_add_let_for_letchains = consider adding `let`
index 455ff34f7247f3a8d632ac6e57c50c46094b91df..6d42b23fb3a213b6db8495663dc23b0e4fb4898e 100644 (file)
@@ -125,6 +125,9 @@ parser_if_expression_missing_condition = missing condition for `if` expression
 
 parser_expected_expression_found_let = expected expression, found `let` statement
 
+parser_expect_eq_instead_of_eqeq = expected `=`, found `==`
+    .suggestion = consider using `=` here
+
 parser_expected_else_block = expected `{"{"}`, found {$first_tok}
     .label = expected an `if` or a block after this `else`
     .suggestion = add an `if` if this is the condition of a chained `else if` statement
index 5239ff9dc0571d31e0bb58fd6b1e2044deb09b6e..001e53d1d0e4ce52953539a295d5a3cf0ded2475 100644 (file)
@@ -47,7 +47,10 @@ passes_no_coverage_not_coverable =
 
 passes_should_be_applied_to_fn =
     attribute should be applied to a function definition
-    .label = not a function definition
+    .label = {$on_crate ->
+        [true] cannot be applied to crates
+        *[false] not a function definition
+    }
 
 passes_naked_tracked_caller =
     cannot use `#[track_caller]` with `#[naked]`
index 9465051dd103f5ea43b236d880081752d352f13c..0b1b75471a661cefaa5d530e0534cb85ea868ea7 100644 (file)
@@ -30,7 +30,8 @@
 #[cfg(not(parallel_compiler))]
 use intl_memoizer::IntlLangMemoizer;
 
-pub use fluent_bundle::{FluentArgs, FluentError, FluentValue};
+pub use fluent_bundle::{self, FluentArgs, FluentError, FluentValue};
+
 pub use unic_langid::{langid, LanguageIdentifier};
 
 // Generates `DEFAULT_LOCALE_RESOURCES` static and `fluent_generated` module.
@@ -42,6 +43,7 @@
     borrowck => "../locales/en-US/borrowck.ftl",
     builtin_macros => "../locales/en-US/builtin_macros.ftl",
     codegen_gcc => "../locales/en-US/codegen_gcc.ftl",
+    codegen_llvm => "../locales/en-US/codegen_llvm.ftl",
     codegen_ssa => "../locales/en-US/codegen_ssa.ftl",
     compiletest => "../locales/en-US/compiletest.ftl",
     const_eval => "../locales/en-US/const_eval.ftl",
index f14b8ee3254f33608b0bbe0b16c6374ec0c5ad9e..c450c276366e156220e09c14077eb72c23e4727b 100644 (file)
@@ -52,7 +52,6 @@ fn emit_diagnostic(&mut self, diag: &Diagnostic) {
         let (mut primary_span, suggestions) = self.primary_span_formatted(&diag, &fluent_args);
 
         self.fix_multispans_in_extern_macros_and_render_macro_backtrace(
-            &self.source_map,
             &mut primary_span,
             &mut children,
             &diag.level,
index 45c017df918e87060cb771ca8ed83cf4d4de8f80..66c986977eccb78c1ad58e2c9adc9c22a69f93e4 100644 (file)
@@ -44,6 +44,15 @@ pub trait IntoDiagnosticArg {
     fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static>;
 }
 
+impl<'source> IntoDiagnosticArg for DiagnosticArgValue<'source> {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        match self {
+            DiagnosticArgValue::Str(s) => DiagnosticArgValue::Str(Cow::Owned(s.into_owned())),
+            DiagnosticArgValue::Number(n) => DiagnosticArgValue::Number(n),
+        }
+    }
+}
+
 impl<'source> Into<FluentValue<'source>> for DiagnosticArgValue<'source> {
     fn into(self) -> FluentValue<'source> {
         match self {
@@ -55,8 +64,7 @@ fn into(self) -> FluentValue<'source> {
 
 /// Trait implemented by error types. This should not be implemented manually. Instead, use
 /// `#[derive(Subdiagnostic)]` -- see [rustc_macros::Subdiagnostic].
-#[cfg_attr(bootstrap, rustc_diagnostic_item = "AddSubdiagnostic")]
-#[cfg_attr(not(bootstrap), rustc_diagnostic_item = "AddToDiagnostic")]
+#[rustc_diagnostic_item = "AddToDiagnostic"]
 pub trait AddToDiagnostic
 where
     Self: Sized,
@@ -204,6 +212,22 @@ pub fn new<M: Into<DiagnosticMessage>>(level: Level, message: M) -> Self {
         Diagnostic::new_with_code(level, None, message)
     }
 
+    #[track_caller]
+    pub fn new_with_messages(level: Level, messages: Vec<(DiagnosticMessage, Style)>) -> Self {
+        Diagnostic {
+            level,
+            message: messages,
+            code: None,
+            span: MultiSpan::new(),
+            children: vec![],
+            suggestions: Ok(vec![]),
+            args: Default::default(),
+            sort_span: DUMMY_SP,
+            is_lint: false,
+            emitted_at: DiagnosticLocation::caller(),
+        }
+    }
+
     #[track_caller]
     pub fn new_with_code<M: Into<DiagnosticMessage>>(
         level: Level,
@@ -717,7 +741,7 @@ pub fn span_suggestions(
         &mut self,
         sp: Span,
         msg: impl Into<SubdiagnosticMessage>,
-        suggestions: impl Iterator<Item = String>,
+        suggestions: impl IntoIterator<Item = String>,
         applicability: Applicability,
     ) -> &mut Self {
         self.span_suggestions_with_style(
@@ -734,11 +758,11 @@ pub fn span_suggestions_with_style(
         &mut self,
         sp: Span,
         msg: impl Into<SubdiagnosticMessage>,
-        suggestions: impl Iterator<Item = String>,
+        suggestions: impl IntoIterator<Item = String>,
         applicability: Applicability,
         style: SuggestionStyle,
     ) -> &mut Self {
-        let mut suggestions: Vec<_> = suggestions.collect();
+        let mut suggestions: Vec<_> = suggestions.into_iter().collect();
         suggestions.sort();
 
         debug_assert!(
@@ -765,10 +789,10 @@ pub fn span_suggestions_with_style(
     pub fn multipart_suggestions(
         &mut self,
         msg: impl Into<SubdiagnosticMessage>,
-        suggestions: impl Iterator<Item = Vec<(Span, String)>>,
+        suggestions: impl IntoIterator<Item = Vec<(Span, String)>>,
         applicability: Applicability,
     ) -> &mut Self {
-        let suggestions: Vec<_> = suggestions.collect();
+        let suggestions: Vec<_> = suggestions.into_iter().collect();
         debug_assert!(
             !(suggestions
                 .iter()
@@ -931,6 +955,13 @@ pub fn set_arg(
         self
     }
 
+    pub fn replace_args(
+        &mut self,
+        args: FxHashMap<DiagnosticArgName<'static>, DiagnosticArgValue<'static>>,
+    ) {
+        self.args = args;
+    }
+
     pub fn styled_message(&self) -> &[(DiagnosticMessage, Style)] {
         &self.message
     }
index ecf8570e81f7131d25f5df080fce350d0c062175..a2ed988643ff2a4ef2589ba99046d045725e250f 100644 (file)
@@ -16,8 +16,7 @@
 
 /// Trait implemented by error types. This should not be implemented manually. Instead, use
 /// `#[derive(Diagnostic)]` -- see [rustc_macros::Diagnostic].
-#[cfg_attr(bootstrap, rustc_diagnostic_item = "SessionDiagnostic")]
-#[cfg_attr(not(bootstrap), rustc_diagnostic_item = "IntoDiagnostic")]
+#[rustc_diagnostic_item = "IntoDiagnostic"]
 pub trait IntoDiagnostic<'a, T: EmissionGuarantee = ErrorGuaranteed> {
     /// Write out as a diagnostic out of `Handler`.
     #[must_use]
@@ -482,9 +481,9 @@ pub fn buffer(self, buffered_diagnostics: &mut Vec<Diagnostic>) {
     /// In the meantime, though, callsites are required to deal with the "bug"
     /// locally in whichever way makes the most sense.
     #[track_caller]
-    pub fn delay_as_bug(&mut self) {
+    pub fn delay_as_bug(&mut self) -> G {
         self.downgrade_to_delayed_bug();
-        self.emit();
+        self.emit()
     }
 
     forward!(
@@ -599,13 +598,13 @@ pub fn span_labels(
         &mut self,
         sp: Span,
         msg: impl Into<SubdiagnosticMessage>,
-        suggestions: impl Iterator<Item = String>,
+        suggestions: impl IntoIterator<Item = String>,
         applicability: Applicability,
     ) -> &mut Self);
     forward!(pub fn multipart_suggestions(
         &mut self,
         msg: impl Into<SubdiagnosticMessage>,
-        suggestions: impl Iterator<Item = Vec<(Span, String)>>,
+        suggestions: impl IntoIterator<Item = Vec<(Span, String)>>,
         applicability: Applicability,
     ) -> &mut Self);
     forward!(pub fn span_suggestion_short(
index 22f6fc700fad371be7c15ecd14ff14ecb4136aa3..c6035705e39fa70d2022800fee8d488c82fb115b 100644 (file)
@@ -107,6 +107,12 @@ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
     }
 }
 
+impl<'a> IntoDiagnosticArg for Cow<'a, str> {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        DiagnosticArgValue::Str(Cow::Owned(self.into_owned()))
+    }
+}
+
 impl<'a> IntoDiagnosticArg for &'a Path {
     fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
         DiagnosticArgValue::Str(Cow::Owned(self.display().to_string()))
index b7b8fe3f25a04c43de3b24f6b93ca162789cd88b..55c7997a513636bc38d48f8acfc74da9e3c61dd9 100644 (file)
@@ -314,7 +314,6 @@ fn primary_span_formatted<'a>(
 
     fn fix_multispans_in_extern_macros_and_render_macro_backtrace(
         &self,
-        source_map: &Option<Lrc<SourceMap>>,
         span: &mut MultiSpan,
         children: &mut Vec<SubDiagnostic>,
         level: &Level,
@@ -340,7 +339,7 @@ fn fix_multispans_in_extern_macros_and_render_macro_backtrace(
             .collect();
 
         if !backtrace {
-            self.fix_multispans_in_extern_macros(source_map, span, children);
+            self.fix_multispans_in_extern_macros(span, children);
         }
 
         self.render_multispans_macro_backtrace(span, children, backtrace);
@@ -480,15 +479,13 @@ fn render_multispan_macro_backtrace(&self, span: &mut MultiSpan, always_backtrac
     // this will change the span to point at the use site.
     fn fix_multispans_in_extern_macros(
         &self,
-        source_map: &Option<Lrc<SourceMap>>,
         span: &mut MultiSpan,
         children: &mut Vec<SubDiagnostic>,
     ) {
-        let Some(source_map) = source_map else { return };
         debug!("fix_multispans_in_extern_macros: before: span={:?} children={:?}", span, children);
-        self.fix_multispan_in_extern_macros(source_map, span);
+        self.fix_multispan_in_extern_macros(span);
         for child in children.iter_mut() {
-            self.fix_multispan_in_extern_macros(source_map, &mut child.span);
+            self.fix_multispan_in_extern_macros(&mut child.span);
         }
         debug!("fix_multispans_in_extern_macros: after: span={:?} children={:?}", span, children);
     }
@@ -496,7 +493,8 @@ fn fix_multispans_in_extern_macros(
     // This "fixes" MultiSpans that contain `Span`s pointing to locations inside of external macros.
     // Since these locations are often difficult to read,
     // we move these spans from the external macros to their corresponding use site.
-    fn fix_multispan_in_extern_macros(&self, source_map: &Lrc<SourceMap>, span: &mut MultiSpan) {
+    fn fix_multispan_in_extern_macros(&self, span: &mut MultiSpan) {
+        let Some(source_map) = self.source_map() else { return };
         // First, find all the spans in external macros and point instead at their use site.
         let replacements: Vec<(Span, Span)> = span
             .primary_spans()
@@ -544,7 +542,6 @@ fn emit_diagnostic(&mut self, diag: &Diagnostic) {
         debug!("emit_diagnostic: suggestions={:?}", suggestions);
 
         self.fix_multispans_in_extern_macros_and_render_macro_backtrace(
-            &self.sm,
             &mut primary_span,
             &mut children,
             &diag.level,
@@ -2213,22 +2210,45 @@ fn add_annotation_to_file(
 
         if let Some(ref sm) = emitter.source_map() {
             for span_label in msp.span_labels() {
+                let fixup_lo_hi = |span: Span| {
+                    let lo = sm.lookup_char_pos(span.lo());
+                    let mut hi = sm.lookup_char_pos(span.hi());
+
+                    // Watch out for "empty spans". If we get a span like 6..6, we
+                    // want to just display a `^` at 6, so convert that to
+                    // 6..7. This is degenerate input, but it's best to degrade
+                    // gracefully -- and the parser likes to supply a span like
+                    // that for EOF, in particular.
+
+                    if lo.col_display == hi.col_display && lo.line == hi.line {
+                        hi.col_display += 1;
+                    }
+                    (lo, hi)
+                };
+
                 if span_label.span.is_dummy() {
+                    if let Some(span) = msp.primary_span() {
+                        // if we don't know where to render the annotation, emit it as a note
+                        // on the primary span.
+
+                        let (lo, hi) = fixup_lo_hi(span);
+
+                        let ann = Annotation {
+                            start_col: lo.col_display,
+                            end_col: hi.col_display,
+                            is_primary: span_label.is_primary,
+                            label: span_label
+                                .label
+                                .as_ref()
+                                .map(|m| emitter.translate_message(m, args).to_string()),
+                            annotation_type: AnnotationType::Singleline,
+                        };
+                        add_annotation_to_file(&mut output, lo.file, lo.line, ann);
+                    }
                     continue;
                 }
 
-                let lo = sm.lookup_char_pos(span_label.span.lo());
-                let mut hi = sm.lookup_char_pos(span_label.span.hi());
-
-                // Watch out for "empty spans". If we get a span like 6..6, we
-                // want to just display a `^` at 6, so convert that to
-                // 6..7. This is degenerate input, but it's best to degrade
-                // gracefully -- and the parser likes to supply a span like
-                // that for EOF, in particular.
-
-                if lo.col_display == hi.col_display && lo.line == hi.line {
-                    hi.col_display += 1;
-                }
+                let (lo, hi) = fixup_lo_hi(span_label.span);
 
                 if lo.line != hi.line {
                     let ml = MultilineAnnotation {
index a7737b467b75bd89dc266a03a78c941b96cb76eb..a452fac074787348a0bf5666d5b7b55cfa00421f 100644 (file)
@@ -1,7 +1,10 @@
 use crate::snippet::Style;
 use crate::{DiagnosticArg, DiagnosticMessage, FluentBundle};
 use rustc_data_structures::sync::Lrc;
-use rustc_error_messages::FluentArgs;
+use rustc_error_messages::{
+    fluent_bundle::resolver::errors::{ReferenceKind, ResolverError},
+    FluentArgs, FluentError,
+};
 use std::borrow::Cow;
 
 /// Convert diagnostic arguments (a rustc internal type that exists to implement
@@ -102,14 +105,31 @@ fn translate_message<'a>(
             .or_else(|| translate_with_bundle(self.fallback_fluent_bundle()))
             .map(|(translated, errs)| {
                 // Always bail out for errors with the fallback bundle.
-                assert!(
-                    errs.is_empty(),
-                    "identifier: {:?}, attr: {:?}, args: {:?}, errors: {:?}",
-                    identifier,
-                    attr,
-                    args,
-                    errs
-                );
+
+                let mut help_messages = vec![];
+
+                if !errs.is_empty() {
+                    for error in &errs {
+                        match error {
+                            FluentError::ResolverError(ResolverError::Reference(
+                                ReferenceKind::Message { id, .. },
+                            )) if args.iter().any(|(arg_id, _)| arg_id == id) => {
+                                help_messages.push(format!("Argument `{id}` exists but was not referenced correctly. Try using `{{${id}}}` instead"));
+                            }
+                            _ => {}
+                        }
+                    }
+
+                    panic!(
+                        "Encountered errors while formatting message for `{identifier}`\n\
+                        help: {}\n\
+                        attr: `{attr:?}`\n\
+                        args: `{args:?}`\n\
+                        errors: `{errs:?}`",
+                        help_messages.join("\nhelp: ")
+                    );
+                }
+
                 translated
             })
             .expect("failed to find message in primary or fallback fluent bundles")
index c8de60ccb89b9830a5000f8ae0f7f970fac5fa1a..1294f1e17d412a7469cf564760f1df89a2f68583 100644 (file)
@@ -250,6 +250,7 @@ fn expand(
         span: Span,
         meta_item: &ast::MetaItem,
         item: Annotatable,
+        is_derive_const: bool,
     ) -> ExpandResult<Vec<Annotatable>, Annotatable>;
 }
 
@@ -263,6 +264,7 @@ fn expand(
         span: Span,
         meta_item: &ast::MetaItem,
         item: Annotatable,
+        _is_derive_const: bool,
     ) -> ExpandResult<Vec<Annotatable>, Annotatable> {
         ExpandResult::Ready(self(ecx, span, meta_item, item))
     }
@@ -873,7 +875,7 @@ pub fn expn_data(
 /// Error type that denotes indeterminacy.
 pub struct Indeterminate;
 
-pub type DeriveResolutions = Vec<(ast::Path, Annotatable, Option<Lrc<SyntaxExtension>>)>;
+pub type DeriveResolutions = Vec<(ast::Path, Annotatable, Option<Lrc<SyntaxExtension>>, bool)>;
 
 pub trait ResolverExpand {
     fn next_node_id(&mut self) -> NodeId;
index 57713fb3cd61d59c7a2f33fdc46d8938b7eafb17..3d37e2c6568518cf5a5615a350c4a22241e175ac 100644 (file)
@@ -337,6 +337,7 @@ pub enum InvocationKind {
     },
     Derive {
         path: ast::Path,
+        is_const: bool,
         item: Annotatable,
     },
 }
@@ -478,13 +479,13 @@ pub fn fully_expand_fragment(&mut self, input_fragment: AstFragment) -> AstFragm
                             derive_invocations.reserve(derives.len());
                             derives
                                 .into_iter()
-                                .map(|(path, item, _exts)| {
+                                .map(|(path, item, _exts, is_const)| {
                                     // FIXME: Consider using the derive resolutions (`_exts`)
                                     // instead of enqueuing the derives to be resolved again later.
                                     let expn_id = LocalExpnId::fresh_empty();
                                     derive_invocations.push((
                                         Invocation {
-                                            kind: InvocationKind::Derive { path, item },
+                                            kind: InvocationKind::Derive { path, item, is_const },
                                             fragment_kind,
                                             expansion_data: ExpansionData {
                                                 id: expn_id,
@@ -717,7 +718,7 @@ fn expand_invoc(
                 SyntaxExtensionKind::LegacyAttr(expander) => {
                     match validate_attr::parse_meta(&self.cx.sess.parse_sess, &attr) {
                         Ok(meta) => {
-                            let items = match expander.expand(self.cx, span, &meta, item) {
+                            let items = match expander.expand(self.cx, span, &meta, item, false) {
                                 ExpandResult::Ready(items) => items,
                                 ExpandResult::Retry(item) => {
                                     // Reassemble the original invocation for retrying.
@@ -749,19 +750,19 @@ fn expand_invoc(
                 }
                 _ => unreachable!(),
             },
-            InvocationKind::Derive { path, item } => match ext {
+            InvocationKind::Derive { path, item, is_const } => match ext {
                 SyntaxExtensionKind::Derive(expander)
                 | SyntaxExtensionKind::LegacyDerive(expander) => {
                     if let SyntaxExtensionKind::Derive(..) = ext {
                         self.gate_proc_macro_input(&item);
                     }
                     let meta = ast::MetaItem { kind: MetaItemKind::Word, span, path };
-                    let items = match expander.expand(self.cx, span, &meta, item) {
+                    let items = match expander.expand(self.cx, span, &meta, item, is_const) {
                         ExpandResult::Ready(items) => items,
                         ExpandResult::Retry(item) => {
                             // Reassemble the original invocation for retrying.
                             return ExpandResult::Retry(Invocation {
-                                kind: InvocationKind::Derive { path: meta.path, item },
+                                kind: InvocationKind::Derive { path: meta.path, item, is_const },
                                 ..invoc
                             });
                         }
index f42576b16f5204d13f2a2ed69c6d34b8c0eb0e19..63bafd7b046fb173275548d333b098ddfd4ab06a 100644 (file)
@@ -52,7 +52,7 @@ fn new(op: KleeneOp, span: Span) -> KleeneToken {
 /// A Kleene-style [repetition operator](https://en.wikipedia.org/wiki/Kleene_star)
 /// for token sequences.
 #[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy)]
-enum KleeneOp {
+pub(crate) enum KleeneOp {
     /// Kleene star (`*`) for zero or more repetitions
     ZeroOrMore,
     /// Kleene plus (`+`) for one or more repetitions
index c8bdc39311c6550c7c206eb0b24e6bc1fc099b22..95cec8d7ae29992455c0e1ee9638ff941d5c71cc 100644 (file)
 pub(crate) use NamedMatch::*;
 pub(crate) use ParseResult::*;
 
-use crate::mbe::{KleeneOp, TokenTree};
+use crate::mbe::{macro_rules::Tracker, KleeneOp, TokenTree};
 
 use rustc_ast::token::{self, DocComment, Nonterminal, NonterminalKind, Token};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::sync::Lrc;
+use rustc_errors::ErrorGuaranteed;
 use rustc_lint_defs::pluralize;
 use rustc_parse::parser::{NtOrTt, Parser};
+use rustc_span::symbol::Ident;
 use rustc_span::symbol::MacroRulesNormalizedIdent;
 use rustc_span::Span;
-
-use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::sync::Lrc;
-use rustc_span::symbol::Ident;
 use std::borrow::Cow;
 use std::collections::hash_map::Entry::{Occupied, Vacant};
 
@@ -96,7 +96,8 @@
 ///
 /// This means a matcher can be represented by `&[MatcherLoc]`, and traversal mostly involves
 /// simply incrementing the current matcher position index by one.
-pub(super) enum MatcherLoc {
+#[derive(Debug)]
+pub(crate) enum MatcherLoc {
     Token {
         token: Token,
     },
@@ -270,13 +271,17 @@ pub(crate) enum ParseResult<T> {
     Failure(Token, &'static str),
     /// Fatal error (malformed macro?). Abort compilation.
     Error(rustc_span::Span, String),
-    ErrorReported,
+    ErrorReported(ErrorGuaranteed),
 }
 
 /// A `ParseResult` where the `Success` variant contains a mapping of
 /// `MacroRulesNormalizedIdent`s to `NamedMatch`es. This represents the mapping
 /// of metavars to the token trees they bind to.
-pub(crate) type NamedParseResult = ParseResult<FxHashMap<MacroRulesNormalizedIdent, NamedMatch>>;
+pub(crate) type NamedParseResult = ParseResult<NamedMatches>;
+
+/// Contains a mapping of `MacroRulesNormalizedIdent`s to `NamedMatch`es.
+/// This represents the mapping of metavars to the token trees they bind to.
+pub(crate) type NamedMatches = FxHashMap<MacroRulesNormalizedIdent, NamedMatch>;
 
 /// Count how many metavars declarations are in `matcher`.
 pub(super) fn count_metavar_decls(matcher: &[TokenTree]) -> usize {
@@ -400,17 +405,21 @@ pub(super) fn new(macro_name: Ident) -> TtParser {
     ///
     /// `Some(result)` if everything is finished, `None` otherwise. Note that matches are kept
     /// track of through the mps generated.
-    fn parse_tt_inner(
+    fn parse_tt_inner<'matcher, T: Tracker<'matcher>>(
         &mut self,
-        matcher: &[MatcherLoc],
+        matcher: &'matcher [MatcherLoc],
         token: &Token,
+        track: &mut T,
     ) -> Option<NamedParseResult> {
         // Matcher positions that would be valid if the macro invocation was over now. Only
         // modified if `token == Eof`.
         let mut eof_mps = EofMatcherPositions::None;
 
         while let Some(mut mp) = self.cur_mps.pop() {
-            match &matcher[mp.idx] {
+            let matcher_loc = &matcher[mp.idx];
+            track.before_match_loc(self, matcher_loc);
+
+            match matcher_loc {
                 MatcherLoc::Token { token: t } => {
                     // If it's a doc comment, we just ignore it and move on to the next tt in the
                     // matcher. This is a bug, but #95267 showed that existing programs rely on
@@ -450,7 +459,7 @@ fn parse_tt_inner(
                         // Try zero matches of this sequence, by skipping over it.
                         self.cur_mps.push(MatcherPos {
                             idx: idx_first_after,
-                            matches: mp.matches.clone(), // a cheap clone
+                            matches: Lrc::clone(&mp.matches),
                         });
                     }
 
@@ -463,8 +472,8 @@ fn parse_tt_inner(
                     // sequence. If that's not possible, `ending_mp` will fail quietly when it is
                     // processed next time around the loop.
                     let ending_mp = MatcherPos {
-                        idx: mp.idx + 1,             // +1 skips the Kleene op
-                        matches: mp.matches.clone(), // a cheap clone
+                        idx: mp.idx + 1, // +1 skips the Kleene op
+                        matches: Lrc::clone(&mp.matches),
                     };
                     self.cur_mps.push(ending_mp);
 
@@ -479,8 +488,8 @@ fn parse_tt_inner(
                     // separator yet. Try ending the sequence. If that's not possible, `ending_mp`
                     // will fail quietly when it is processed next time around the loop.
                     let ending_mp = MatcherPos {
-                        idx: mp.idx + 2,             // +2 skips the separator and the Kleene op
-                        matches: mp.matches.clone(), // a cheap clone
+                        idx: mp.idx + 2, // +2 skips the separator and the Kleene op
+                        matches: Lrc::clone(&mp.matches),
                     };
                     self.cur_mps.push(ending_mp);
 
@@ -552,10 +561,11 @@ fn parse_tt_inner(
     }
 
     /// Match the token stream from `parser` against `matcher`.
-    pub(super) fn parse_tt(
+    pub(super) fn parse_tt<'matcher, T: Tracker<'matcher>>(
         &mut self,
         parser: &mut Cow<'_, Parser<'_>>,
-        matcher: &[MatcherLoc],
+        matcher: &'matcher [MatcherLoc],
+        track: &mut T,
     ) -> NamedParseResult {
         // A queue of possible matcher positions. We initialize it with the matcher position in
         // which the "dot" is before the first token of the first token tree in `matcher`.
@@ -571,7 +581,8 @@ pub(super) fn parse_tt(
 
             // Process `cur_mps` until either we have finished the input or we need to get some
             // parsing from the black-box parser done.
-            if let Some(res) = self.parse_tt_inner(matcher, &parser.token) {
+            let res = self.parse_tt_inner(matcher, &parser.token, track);
+            if let Some(res) = res {
                 return res;
             }
 
@@ -612,14 +623,14 @@ pub(super) fn parse_tt(
                         // edition-specific matching behavior for non-terminals.
                         let nt = match parser.to_mut().parse_nonterminal(kind) {
                             Err(mut err) => {
-                                err.span_label(
+                                let guarantee = err.span_label(
                                     span,
                                     format!(
                                         "while parsing argument for this `{kind}` macro fragment"
                                     ),
                                 )
                                 .emit();
-                                return ErrorReported;
+                                return ErrorReported(guarantee);
                             }
                             Ok(nt) => nt,
                         };
index f6fe38174f7c5566f380e7a2c587c8e3b98aa272..99af91072882efc99011b95871c34c32e80a6be7 100644 (file)
@@ -14,7 +14,9 @@
 use rustc_ast_pretty::pprust;
 use rustc_attr::{self as attr, TransparencyError};
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
-use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, DiagnosticMessage};
+use rustc_errors::{
+    Applicability, Diagnostic, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed,
+};
 use rustc_feature::Features;
 use rustc_lint_defs::builtin::{
     RUST_2021_INCOMPATIBLE_OR_PATTERNS, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
@@ -33,6 +35,8 @@
 use std::collections::hash_map::Entry;
 use std::{mem, slice};
 
+use super::macro_parser::{NamedMatches, NamedParseResult};
+
 pub(crate) struct ParserAnyMacro<'a> {
     parser: Parser<'a>,
 
@@ -205,8 +209,32 @@ fn trace_macros_note(cx_expansions: &mut FxIndexMap<Span, Vec<String>>, sp: Span
     cx_expansions.entry(sp).or_default().push(message);
 }
 
+pub(super) trait Tracker<'matcher> {
+    /// This is called before trying to match next MatcherLoc on the current token.
+    fn before_match_loc(&mut self, parser: &TtParser, matcher: &'matcher MatcherLoc);
+
+    /// This is called after an arm has been parsed, either successfully or unsuccessfully. When this is called,
+    /// `before_match_loc` was called at least once (with a `MatcherLoc::Eof`).
+    fn after_arm(&mut self, result: &NamedParseResult);
+
+    /// For tracing.
+    fn description() -> &'static str;
+}
+
+/// A noop tracker that is used in the hot path of the expansion, has zero overhead thanks to monomorphization.
+struct NoopTracker;
+
+impl<'matcher> Tracker<'matcher> for NoopTracker {
+    fn before_match_loc(&mut self, _: &TtParser, _: &'matcher MatcherLoc) {}
+    fn after_arm(&mut self, _: &NamedParseResult) {}
+    fn description() -> &'static str {
+        "none"
+    }
+}
+
 /// Expands the rules based macro defined by `lhses` and `rhses` for a given
 /// input `arg`.
+#[instrument(skip(cx, transparency, arg, lhses, rhses))]
 fn expand_macro<'cx>(
     cx: &'cx mut ExtCtxt<'_>,
     sp: Span,
@@ -228,9 +256,188 @@ fn expand_macro<'cx>(
         trace_macros_note(&mut cx.expansions, sp, msg);
     }
 
-    // Which arm's failure should we report? (the one furthest along)
-    let mut best_failure: Option<(Token, &str)> = None;
+    // Track nothing for the best performance.
+    let try_success_result = try_match_macro(sess, name, &arg, lhses, &mut NoopTracker);
+
+    match try_success_result {
+        Ok((i, named_matches)) => {
+            let (rhs, rhs_span): (&mbe::Delimited, DelimSpan) = match &rhses[i] {
+                mbe::TokenTree::Delimited(span, delimited) => (&delimited, *span),
+                _ => cx.span_bug(sp, "malformed macro rhs"),
+            };
+            let arm_span = rhses[i].span();
+
+            let rhs_spans = rhs.tts.iter().map(|t| t.span()).collect::<Vec<_>>();
+            // rhs has holes ( `$id` and `$(...)` that need filled)
+            let mut tts = match transcribe(cx, &named_matches, &rhs, rhs_span, transparency) {
+                Ok(tts) => tts,
+                Err(mut err) => {
+                    err.emit();
+                    return DummyResult::any(arm_span);
+                }
+            };
+
+            // Replace all the tokens for the corresponding positions in the macro, to maintain
+            // proper positions in error reporting, while maintaining the macro_backtrace.
+            if rhs_spans.len() == tts.len() {
+                tts = tts.map_enumerated(|i, tt| {
+                    let mut tt = tt.clone();
+                    let mut sp = rhs_spans[i];
+                    sp = sp.with_ctxt(tt.span().ctxt());
+                    tt.set_span(sp);
+                    tt
+                });
+            }
+
+            if cx.trace_macros() {
+                let msg = format!("to `{}`", pprust::tts_to_string(&tts));
+                trace_macros_note(&mut cx.expansions, sp, msg);
+            }
+
+            let mut p = Parser::new(sess, tts, false, None);
+            p.last_type_ascription = cx.current_expansion.prior_type_ascription;
+
+            if is_local {
+                cx.resolver.record_macro_rule_usage(node_id, i);
+            }
+
+            // Let the context choose how to interpret the result.
+            // Weird, but useful for X-macros.
+            return Box::new(ParserAnyMacro {
+                parser: p,
+
+                // Pass along the original expansion site and the name of the macro
+                // so we can print a useful error message if the parse of the expanded
+                // macro leaves unparsed tokens.
+                site_span: sp,
+                macro_ident: name,
+                lint_node_id: cx.current_expansion.lint_node_id,
+                is_trailing_mac: cx.current_expansion.is_trailing_mac,
+                arm_span,
+                is_local,
+            });
+        }
+        Err(CanRetry::No(_)) => {
+            debug!("Will not retry matching as an error was emitted already");
+            return DummyResult::any(sp);
+        }
+        Err(CanRetry::Yes) => {
+            // Retry and emit a better error below.
+        }
+    }
+
+    // An error occurred, try the expansion again, tracking the expansion closely for better diagnostics.
+    let mut tracker = CollectTrackerAndEmitter::new(cx, sp);
+
+    let try_success_result = try_match_macro(sess, name, &arg, lhses, &mut tracker);
+    assert!(try_success_result.is_err(), "Macro matching returned a success on the second try");
+
+    if let Some(result) = tracker.result {
+        // An irrecoverable error occured and has been emitted.
+        return result;
+    }
+
+    let Some((token, label)) = tracker.best_failure else {
+        return tracker.result.expect("must have encountered Error or ErrorReported");
+    };
+
+    let span = token.span.substitute_dummy(sp);
+
+    let mut err = cx.struct_span_err(span, &parse_failure_msg(&token));
+    err.span_label(span, label);
+    if !def_span.is_dummy() && !cx.source_map().is_imported(def_span) {
+        err.span_label(cx.source_map().guess_head_span(def_span), "when calling this macro");
+    }
+
+    annotate_doc_comment(&mut err, sess.source_map(), span);
+
+    // Check whether there's a missing comma in this macro call, like `println!("{}" a);`
+    if let Some((arg, comma_span)) = arg.add_comma() {
+        for lhs in lhses {
+            let parser = parser_from_cx(sess, arg.clone());
+            let mut tt_parser = TtParser::new(name);
+
+            if let Success(_) =
+                tt_parser.parse_tt(&mut Cow::Borrowed(&parser), lhs, &mut NoopTracker)
+            {
+                if comma_span.is_dummy() {
+                    err.note("you might be missing a comma");
+                } else {
+                    err.span_suggestion_short(
+                        comma_span,
+                        "missing comma here",
+                        ", ",
+                        Applicability::MachineApplicable,
+                    );
+                }
+            }
+        }
+    }
+    err.emit();
+    cx.trace_macros_diag();
+    DummyResult::any(sp)
+}
+
+/// The tracker used for the slow error path that collects useful info for diagnostics.
+struct CollectTrackerAndEmitter<'a, 'cx> {
+    cx: &'a mut ExtCtxt<'cx>,
+    /// Which arm's failure should we report? (the one furthest along)
+    best_failure: Option<(Token, &'static str)>,
+    root_span: Span,
+    result: Option<Box<dyn MacResult + 'cx>>,
+}
+
+impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx> {
+    fn before_match_loc(&mut self, _parser: &TtParser, _matcher: &'matcher MatcherLoc) {
+        // Empty for now.
+    }
+
+    fn after_arm(&mut self, result: &NamedParseResult) {
+        match result {
+            Success(_) => {
+                unreachable!("should not collect detailed info for successful macro match");
+            }
+            Failure(token, msg) => match self.best_failure {
+                Some((ref best_token, _)) if best_token.span.lo() >= token.span.lo() => {}
+                _ => self.best_failure = Some((token.clone(), msg)),
+            },
+            Error(err_sp, msg) => {
+                let span = err_sp.substitute_dummy(self.root_span);
+                self.cx.struct_span_err(span, msg).emit();
+                self.result = Some(DummyResult::any(span));
+            }
+            ErrorReported(_) => self.result = Some(DummyResult::any(self.root_span)),
+        }
+    }
+
+    fn description() -> &'static str {
+        "detailed"
+    }
+}
+
+impl<'a, 'cx> CollectTrackerAndEmitter<'a, 'cx> {
+    fn new(cx: &'a mut ExtCtxt<'cx>, root_span: Span) -> Self {
+        Self { cx, best_failure: None, root_span, result: None }
+    }
+}
+
+enum CanRetry {
+    Yes,
+    /// We are not allowed to retry macro expansion as a fatal error has been emitted already.
+    No(ErrorGuaranteed),
+}
 
+/// Try expanding the macro. Returns the index of the successful arm and its named_matches if it was successful,
+/// and nothing if it failed. On failure, it's the callers job to use `track` accordingly to record all errors
+/// correctly.
+#[instrument(level = "debug", skip(sess, arg, lhses, track), fields(tracking = %T::description()))]
+fn try_match_macro<'matcher, T: Tracker<'matcher>>(
+    sess: &ParseSess,
+    name: Ident,
+    arg: &TokenStream,
+    lhses: &'matcher [Vec<MatcherLoc>],
+    track: &mut T,
+) -> Result<(usize, NamedMatches), CanRetry> {
     // We create a base parser that can be used for the "black box" parts.
     // Every iteration needs a fresh copy of that parser. However, the parser
     // is not mutated on many of the iterations, particularly when dealing with
@@ -252,125 +459,52 @@ fn expand_macro<'cx>(
     // this situation.)
     // FIXME(Nilstrieb): Stop recovery from happening on this parser and retry later with recovery if the macro failed to match.
     let parser = parser_from_cx(sess, arg.clone());
-
     // Try each arm's matchers.
     let mut tt_parser = TtParser::new(name);
     for (i, lhs) in lhses.iter().enumerate() {
+        let _tracing_span = trace_span!("Matching arm", %i);
+
         // Take a snapshot of the state of pre-expansion gating at this point.
         // This is used so that if a matcher is not `Success(..)`ful,
         // then the spans which became gated when parsing the unsuccessful matcher
         // are not recorded. On the first `Success(..)`ful matcher, the spans are merged.
         let mut gated_spans_snapshot = mem::take(&mut *sess.gated_spans.spans.borrow_mut());
 
-        match tt_parser.parse_tt(&mut Cow::Borrowed(&parser), lhs) {
+        let result = tt_parser.parse_tt(&mut Cow::Borrowed(&parser), lhs, track);
+
+        track.after_arm(&result);
+
+        match result {
             Success(named_matches) => {
+                debug!("Parsed arm successfully");
                 // The matcher was `Success(..)`ful.
                 // Merge the gated spans from parsing the matcher with the pre-existing ones.
                 sess.gated_spans.merge(gated_spans_snapshot);
 
-                let (rhs, rhs_span): (&mbe::Delimited, DelimSpan) = match &rhses[i] {
-                    mbe::TokenTree::Delimited(span, delimited) => (&delimited, *span),
-                    _ => cx.span_bug(sp, "malformed macro rhs"),
-                };
-                let arm_span = rhses[i].span();
-
-                let rhs_spans = rhs.tts.iter().map(|t| t.span()).collect::<Vec<_>>();
-                // rhs has holes ( `$id` and `$(...)` that need filled)
-                let mut tts = match transcribe(cx, &named_matches, &rhs, rhs_span, transparency) {
-                    Ok(tts) => tts,
-                    Err(mut err) => {
-                        err.emit();
-                        return DummyResult::any(arm_span);
-                    }
-                };
-
-                // Replace all the tokens for the corresponding positions in the macro, to maintain
-                // proper positions in error reporting, while maintaining the macro_backtrace.
-                if rhs_spans.len() == tts.len() {
-                    tts = tts.map_enumerated(|i, tt| {
-                        let mut tt = tt.clone();
-                        let mut sp = rhs_spans[i];
-                        sp = sp.with_ctxt(tt.span().ctxt());
-                        tt.set_span(sp);
-                        tt
-                    });
-                }
-
-                if cx.trace_macros() {
-                    let msg = format!("to `{}`", pprust::tts_to_string(&tts));
-                    trace_macros_note(&mut cx.expansions, sp, msg);
-                }
-
-                let mut p = Parser::new(sess, tts, false, None);
-                p.last_type_ascription = cx.current_expansion.prior_type_ascription;
-
-                if is_local {
-                    cx.resolver.record_macro_rule_usage(node_id, i);
-                }
-
-                // Let the context choose how to interpret the result.
-                // Weird, but useful for X-macros.
-                return Box::new(ParserAnyMacro {
-                    parser: p,
-
-                    // Pass along the original expansion site and the name of the macro
-                    // so we can print a useful error message if the parse of the expanded
-                    // macro leaves unparsed tokens.
-                    site_span: sp,
-                    macro_ident: name,
-                    lint_node_id: cx.current_expansion.lint_node_id,
-                    is_trailing_mac: cx.current_expansion.is_trailing_mac,
-                    arm_span,
-                    is_local,
-                });
+                return Ok((i, named_matches));
             }
-            Failure(token, msg) => match best_failure {
-                Some((ref best_token, _)) if best_token.span.lo() >= token.span.lo() => {}
-                _ => best_failure = Some((token, msg)),
-            },
-            Error(err_sp, ref msg) => {
-                let span = err_sp.substitute_dummy(sp);
-                cx.struct_span_err(span, &msg).emit();
-                return DummyResult::any(span);
+            Failure(_, _) => {
+                trace!("Failed to match arm, trying the next one");
+                // Try the next arm.
+            }
+            Error(_, _) => {
+                debug!("Fatal error occurred during matching");
+                // We haven't emitted an error yet, so we can retry.
+                return Err(CanRetry::Yes);
+            }
+            ErrorReported(guarantee) => {
+                debug!("Fatal error occurred and was reported during matching");
+                // An error has been reported already, we cannot retry as that would cause duplicate errors.
+                return Err(CanRetry::No(guarantee));
             }
-            ErrorReported => return DummyResult::any(sp),
         }
 
         // The matcher was not `Success(..)`ful.
         // Restore to the state before snapshotting and maybe try again.
         mem::swap(&mut gated_spans_snapshot, &mut sess.gated_spans.spans.borrow_mut());
     }
-    drop(parser);
 
-    let (token, label) = best_failure.expect("ran no matchers");
-    let span = token.span.substitute_dummy(sp);
-    let mut err = cx.struct_span_err(span, &parse_failure_msg(&token));
-    err.span_label(span, label);
-    if !def_span.is_dummy() && !cx.source_map().is_imported(def_span) {
-        err.span_label(cx.source_map().guess_head_span(def_span), "when calling this macro");
-    }
-    annotate_doc_comment(&mut err, sess.source_map(), span);
-    // Check whether there's a missing comma in this macro call, like `println!("{}" a);`
-    if let Some((arg, comma_span)) = arg.add_comma() {
-        for lhs in lhses {
-            let parser = parser_from_cx(sess, arg.clone());
-            if let Success(_) = tt_parser.parse_tt(&mut Cow::Borrowed(&parser), lhs) {
-                if comma_span.is_dummy() {
-                    err.note("you might be missing a comma");
-                } else {
-                    err.span_suggestion_short(
-                        comma_span,
-                        "missing comma here",
-                        ", ",
-                        Applicability::MachineApplicable,
-                    );
-                }
-            }
-        }
-    }
-    err.emit();
-    cx.trace_macros_diag();
-    DummyResult::any(sp)
+    Err(CanRetry::Yes)
 }
 
 // Note that macro-by-example's input is also matched against a token tree:
@@ -452,28 +586,29 @@ pub fn compile_declarative_macro(
     let parser = Parser::new(&sess.parse_sess, body, true, rustc_parse::MACRO_ARGUMENTS);
     let mut tt_parser =
         TtParser::new(Ident::with_dummy_span(if macro_rules { kw::MacroRules } else { kw::Macro }));
-    let argument_map = match tt_parser.parse_tt(&mut Cow::Borrowed(&parser), &argument_gram) {
-        Success(m) => m,
-        Failure(token, msg) => {
-            let s = parse_failure_msg(&token);
-            let sp = token.span.substitute_dummy(def.span);
-            let mut err = sess.parse_sess.span_diagnostic.struct_span_err(sp, &s);
-            err.span_label(sp, msg);
-            annotate_doc_comment(&mut err, sess.source_map(), sp);
-            err.emit();
-            return dummy_syn_ext();
-        }
-        Error(sp, msg) => {
-            sess.parse_sess
-                .span_diagnostic
-                .struct_span_err(sp.substitute_dummy(def.span), &msg)
-                .emit();
-            return dummy_syn_ext();
-        }
-        ErrorReported => {
-            return dummy_syn_ext();
-        }
-    };
+    let argument_map =
+        match tt_parser.parse_tt(&mut Cow::Owned(parser), &argument_gram, &mut NoopTracker) {
+            Success(m) => m,
+            Failure(token, msg) => {
+                let s = parse_failure_msg(&token);
+                let sp = token.span.substitute_dummy(def.span);
+                let mut err = sess.parse_sess.span_diagnostic.struct_span_err(sp, &s);
+                err.span_label(sp, msg);
+                annotate_doc_comment(&mut err, sess.source_map(), sp);
+                err.emit();
+                return dummy_syn_ext();
+            }
+            Error(sp, msg) => {
+                sess.parse_sess
+                    .span_diagnostic
+                    .struct_span_err(sp.substitute_dummy(def.span), &msg)
+                    .emit();
+                return dummy_syn_ext();
+            }
+            ErrorReported(_) => {
+                return dummy_syn_ext();
+            }
+        };
 
     let mut valid = true;
 
index 1a2ab9d190ebdcd8c141a3abacf222506f936bbc..e9a69192068941167386c97429d4ec96bbd217b1 100644 (file)
@@ -112,6 +112,7 @@ fn expand(
         span: Span,
         _meta_item: &ast::MetaItem,
         item: Annotatable,
+        _is_derive_const: bool,
     ) -> ExpandResult<Vec<Annotatable>, Annotatable> {
         // We need special handling for statement items
         // (e.g. `fn foo() { #[derive(Debug)] struct Bar; }`)
index cc2858d3f73a17d80a95147a4353501ca82cc5b4..a929f6cb0a5df6d6db89b433c8f133412711e260 100644 (file)
@@ -525,6 +525,13 @@ fn expand_expr(&mut self, stream: &Self::TokenStream) -> Result<Self::TokenStrea
             ast::ExprKind::Lit(l) => {
                 Ok(tokenstream::TokenStream::token_alone(token::Literal(l.token_lit), l.span))
             }
+            ast::ExprKind::IncludedBytes(bytes) => {
+                let lit = ast::Lit::from_included_bytes(bytes, expr.span);
+                Ok(tokenstream::TokenStream::token_alone(
+                    token::TokenKind::Literal(lit.token_lit),
+                    expr.span,
+                ))
+            }
             ast::ExprKind::Unary(ast::UnOp::Neg, e) => match &e.kind {
                 ast::ExprKind::Lit(l) => match l.token_lit {
                     token::Lit { kind: token::Integer | token::Float, .. } => {
index c2aa096a993154a399c38820345c03d4a9ae51e1..1646727a1c85f9b72f14f01596b72d8a42929184 100644 (file)
@@ -54,9 +54,9 @@ macro_rules! declare_features {
     /// Allows using ADX intrinsics from `core::arch::{x86, x86_64}`.
     (accepted, adx_target_feature, "1.61.0", Some(44839), None),
     /// Allows explicit discriminants on non-unit enum variants.
-    (accepted, arbitrary_enum_discriminant, "CURRENT_RUSTC_VERSION", Some(60553), None),
+    (accepted, arbitrary_enum_discriminant, "1.66.0", Some(60553), None),
     /// Allows using `sym` operands in inline assembly.
-    (accepted, asm_sym, "CURRENT_RUSTC_VERSION", Some(93333), None),
+    (accepted, asm_sym, "1.66.0", Some(93333), None),
     /// Allows the definition of associated constants in `trait` or `impl` blocks.
     (accepted, associated_consts, "1.20.0", Some(29646), None),
     /// Allows using associated `type`s in `trait`s.
@@ -174,7 +174,7 @@ macro_rules! declare_features {
     // FIXME: explain `globs`.
     (accepted, globs, "1.0.0", None, None),
     /// Allows using `..=X` as a pattern.
-    (accepted, half_open_range_patterns, "CURRENT_RUSTC_VERSION", Some(67264), None),
+    (accepted, half_open_range_patterns, "1.66.0", Some(67264), None),
     /// Allows using the `u128` and `i128` types.
     (accepted, i128_type, "1.26.0", Some(35118), None),
     /// Allows the use of `if let` expressions.
index 09a747662e2669e8a9d995e6a555ca9984af2bab..5cf2fdde392547979af15534f35bf10917cd814f 100644 (file)
@@ -152,6 +152,8 @@ pub fn set(&self, features: &mut Features, span: Span) {
     (active, anonymous_lifetime_in_impl_trait, "1.63.0", None, None),
     /// Allows identifying the `compiler_builtins` crate.
     (active, compiler_builtins, "1.13.0", None, None),
+    /// Allows writing custom MIR
+    (active, custom_mir, "1.65.0", None, None),
     /// Outputs useful `assert!` messages
     (active, generic_assert, "1.63.0", None, None),
     /// Allows using the `rust-intrinsic`'s "ABI".
@@ -309,7 +311,7 @@ pub fn set(&self, features: &mut Features, span: Span) {
     /// Allows `async || body` closures.
     (active, async_closure, "1.37.0", Some(62290), None),
     /// Alows async functions to be declared, implemented, and used in traits.
-    (incomplete, async_fn_in_trait, "CURRENT_RUSTC_VERSION", Some(91611), None),
+    (incomplete, async_fn_in_trait, "1.66.0", Some(91611), None),
     /// Allows `extern "C-unwind" fn` to enable unwinding across ABI boundaries.
     (active, c_unwind, "1.52.0", Some(74990), None),
     /// Allows using C-variadics.
@@ -412,7 +414,7 @@ pub fn set(&self, features: &mut Features, span: Span) {
     /// Allows non-trivial generic constants which have to have wfness manually propagated to callers
     (incomplete, generic_const_exprs, "1.56.0", Some(76560), None),
     /// Allows using `..=X` as a patterns in slices.
-    (active, half_open_range_patterns_in_slices, "CURRENT_RUSTC_VERSION", Some(67264), None),
+    (active, half_open_range_patterns_in_slices, "1.66.0", Some(67264), None),
     /// Allows `if let` guard in match arms.
     (active, if_let_guard, "1.47.0", Some(51114), None),
     /// Allows `impl Trait` as output type in `Fn` traits in return position of functions.
@@ -510,9 +512,9 @@ pub fn set(&self, features: &mut Features, span: Span) {
     (active, thread_local, "1.0.0", Some(29594), None),
     /// Allows defining `trait X = A + B;` alias items.
     (active, trait_alias, "1.24.0", Some(41517), None),
-    /// Allows upcasting trait objects via supertraits.
-    /// Trait upcasting is casting, e.g., `dyn Foo -> dyn Bar` where `Foo: Bar`.
-    (incomplete, trait_upcasting, "1.56.0", Some(65991), None),
+    /// Allows dyn upcasting trait objects via supertraits.
+    /// Dyn upcasting is casting, e.g., `dyn Foo -> dyn Bar` where `Foo: Bar`.
+    (active, trait_upcasting, "1.56.0", Some(65991), None),
     /// Allows #[repr(transparent)] on unions (RFC 2645).
     (active, transparent_unions, "1.37.0", Some(60405), None),
     /// Allows inconsistent bounds in where clauses.
index 4ff3b3f2a38b35860985486a174bdccdd898a154..dc3a74956843eb86c36f5b7e3dff6d0d33027ade 100644 (file)
@@ -810,6 +810,10 @@ pub struct BuiltinAttribute {
     rustc_attr!(TEST, rustc_polymorphize_error, Normal, template!(Word), WarnFollowing),
     rustc_attr!(TEST, rustc_def_path, Normal, template!(Word), WarnFollowing),
     rustc_attr!(TEST, rustc_mir, Normal, template!(List: "arg1, arg2, ..."), DuplicatesOk),
+    gated!(
+        custom_mir, Normal, template!(List: r#"dialect = "...", phase = "...""#),
+        ErrorFollowing, "the `#[custom_mir]` attribute is just used for the Rust test suite",
+    ),
     rustc_attr!(TEST, rustc_dump_program_clauses, Normal, template!(Word), WarnFollowing),
     rustc_attr!(TEST, rustc_dump_env_program_clauses, Normal, template!(Word), WarnFollowing),
     rustc_attr!(TEST, rustc_object_lifetime_default, Normal, template!(Word), WarnFollowing),
index 8b1cc50a3a1f9e6655dbb9d37078c8ad144fe9a9..4518cf30acdd5fda428c2fa7d3ef6e9f26bacb84 100644 (file)
@@ -1201,7 +1201,8 @@ fn add_predicates_for_ast_type_binding(
                     (_, _) => {
                         let got = if let Some(_) = term.ty() { "type" } else { "constant" };
                         let expected = def_kind.descr(assoc_item_def_id);
-                        tcx.sess
+                        let reported = tcx
+                            .sess
                             .struct_span_err(
                                 binding.span,
                                 &format!("expected {expected} bound, found {got}"),
@@ -1212,11 +1213,14 @@ fn add_predicates_for_ast_type_binding(
                             )
                             .emit();
                         term = match def_kind {
-                            hir::def::DefKind::AssocTy => tcx.ty_error().into(),
+                            hir::def::DefKind::AssocTy => {
+                                tcx.ty_error_with_guaranteed(reported).into()
+                            }
                             hir::def::DefKind::AssocConst => tcx
-                                .const_error(
+                                .const_error_with_guaranteed(
                                     tcx.bound_type_of(assoc_item_def_id)
                                         .subst(tcx, projection_ty.skip_binder().substs),
+                                    reported,
                                 )
                                 .into(),
                             _ => unreachable!(),
@@ -1334,8 +1338,9 @@ trait here instead: `trait NewTrait: {} {{}}`",
                 .map(|&(trait_ref, _, _)| trait_ref.def_id())
                 .find(|&trait_ref| tcx.is_trait_alias(trait_ref))
                 .map(|trait_ref| tcx.def_span(trait_ref));
-            tcx.sess.emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span });
-            return tcx.ty_error();
+            let reported =
+                tcx.sess.emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span });
+            return tcx.ty_error_with_guaranteed(reported);
         }
 
         // Check that there are no gross object safety violations;
@@ -1345,14 +1350,14 @@ trait here instead: `trait NewTrait: {} {{}}`",
             let object_safety_violations =
                 astconv_object_safety_violations(tcx, item.trait_ref().def_id());
             if !object_safety_violations.is_empty() {
-                report_object_safety_error(
+                let reported = report_object_safety_error(
                     tcx,
                     span,
                     item.trait_ref().def_id(),
                     &object_safety_violations,
                 )
                 .emit();
-                return tcx.ty_error();
+                return tcx.ty_error_with_guaranteed(reported);
             }
         }
 
@@ -2112,13 +2117,13 @@ fn qpath_to_ty(
                 "Type"
             };
 
-            self.report_ambiguous_associated_type(
+            let reported = self.report_ambiguous_associated_type(
                 span,
                 type_name,
                 &path_str,
                 item_segment.ident.name,
             );
-            return tcx.ty_error();
+            return tcx.ty_error_with_guaranteed(reported)
         };
 
         debug!("qpath_to_ty: self_type={:?}", self_ty);
@@ -2560,8 +2565,7 @@ pub fn res_to_ty(
                     {
                         err.span_note(impl_.self_ty.span, "not a concrete type");
                     }
-                    err.emit();
-                    tcx.ty_error()
+                    tcx.ty_error_with_guaranteed(err.emit())
                 } else {
                     self.normalize_ty(span, ty)
                 }
@@ -2976,7 +2980,7 @@ fn validate_late_bound_regions(
     ) {
         for br in referenced_regions.difference(&constrained_regions) {
             let br_name = match *br {
-                ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(_) | ty::BrEnv => {
+                ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(..) | ty::BrEnv => {
                     "an anonymous lifetime".to_string()
                 }
                 ty::BrNamed(_, name) => format!("lifetime `{}`", name),
@@ -2984,7 +2988,7 @@ fn validate_late_bound_regions(
 
             let mut err = generate_err(&br_name);
 
-            if let ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(_) = *br {
+            if let ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(..) = *br {
                 // The only way for an anonymous lifetime to wind up
                 // in the return type but **also** be unconstrained is
                 // if it only appears in "associated types" in the
index 133bbd52b9142c3249d634c057088df2953bfef9..0ba5e61510125d10e187a6269996729c21b46280 100644 (file)
@@ -26,6 +26,7 @@
 use rustc_span::symbol::sym;
 use rustc_span::{self, Span};
 use rustc_target::spec::abi::Abi;
+use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedDirective;
 use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
 use rustc_trait_selection::traits::{self, ObligationCtxt};
 
@@ -471,7 +472,7 @@ fn check_opaque_meets_bounds<'tcx>(
     // version.
     let errors = ocx.select_all_or_error();
     if !errors.is_empty() {
-        infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+        infcx.err_ctxt().report_fulfillment_errors(&errors, None);
     }
     match origin {
         // Checked when type checking the function containing them.
@@ -655,7 +656,7 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
 
 pub(super) fn check_on_unimplemented(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
     // an error would be reported if this fails.
-    let _ = traits::OnUnimplementedDirective::of_item(tcx, item.owner_id.to_def_id());
+    let _ = OnUnimplementedDirective::of_item(tcx, item.owner_id.to_def_id());
 }
 
 pub(super) fn check_specialization_validity<'tcx>(
index c6b497e9b9fc40aad71e61a8d16ef285c4cdea9b..7c99896b4571427d08543e8031e4ab20b99e30b8 100644 (file)
@@ -1,7 +1,7 @@
 use super::potentially_plural_count;
 use crate::errors::LifetimesOrBoundsMismatchOnTrait;
 use hir::def_id::{DefId, LocalDefId};
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
 use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
@@ -9,14 +9,15 @@
 use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind};
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_infer::infer::{self, TyCtxtInferExt};
+use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
 use rustc_infer::traits::util;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::util::ExplicitSelf;
-use rustc_middle::ty::InternalSubsts;
 use rustc_middle::ty::{
-    self, AssocItem, DefIdTree, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable,
+    self, AssocItem, DefIdTree, TraitRef, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable,
+    TypeVisitable,
 };
+use rustc_middle::ty::{FnSig, InternalSubsts};
 use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt};
 use rustc_span::Span;
 use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
@@ -256,7 +257,7 @@ fn compare_predicate_entailment<'tcx>(
     // Compute placeholder form of impl and trait method tys.
     let tcx = infcx.tcx;
 
-    let mut wf_tys = FxHashSet::default();
+    let mut wf_tys = FxIndexSet::default();
 
     let impl_sig = infcx.replace_bound_vars_with_fresh_vars(
         impl_m_span,
@@ -303,109 +304,26 @@ fn compare_predicate_entailment<'tcx>(
     }
 
     if let Err(terr) = result {
-        debug!("sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty);
+        debug!(?terr, "sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty);
 
-        let (impl_err_span, trait_err_span) =
-            extract_spans_for_error_reporting(&infcx, terr, &cause, impl_m, trait_m);
-
-        cause.span = impl_err_span;
-
-        let mut diag = struct_span_err!(
-            tcx.sess,
-            cause.span(),
-            E0053,
-            "method `{}` has an incompatible type for trait",
-            trait_m.name
-        );
-        match &terr {
-            TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0)
-                if trait_m.fn_has_self_parameter =>
-            {
-                let ty = trait_sig.inputs()[0];
-                let sugg = match ExplicitSelf::determine(ty, |_| ty == impl_trait_ref.self_ty()) {
-                    ExplicitSelf::ByValue => "self".to_owned(),
-                    ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(),
-                    ExplicitSelf::ByReference(_, hir::Mutability::Mut) => "&mut self".to_owned(),
-                    _ => format!("self: {ty}"),
-                };
-
-                // When the `impl` receiver is an arbitrary self type, like `self: Box<Self>`, the
-                // span points only at the type `Box<Self`>, but we want to cover the whole
-                // argument pattern and type.
-                let span = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
-                    ImplItemKind::Fn(ref sig, body) => tcx
-                        .hir()
-                        .body_param_names(body)
-                        .zip(sig.decl.inputs.iter())
-                        .map(|(param, ty)| param.span.to(ty.span))
-                        .next()
-                        .unwrap_or(impl_err_span),
-                    _ => bug!("{:?} is not a method", impl_m),
-                };
-
-                diag.span_suggestion(
-                    span,
-                    "change the self-receiver type to match the trait",
-                    sugg,
-                    Applicability::MachineApplicable,
-                );
-            }
-            TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(_, i) => {
-                if trait_sig.inputs().len() == *i {
-                    // Suggestion to change output type. We do not suggest in `async` functions
-                    // to avoid complex logic or incorrect output.
-                    match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
-                        ImplItemKind::Fn(ref sig, _)
-                            if sig.header.asyncness == hir::IsAsync::NotAsync =>
-                        {
-                            let msg = "change the output type to match the trait";
-                            let ap = Applicability::MachineApplicable;
-                            match sig.decl.output {
-                                hir::FnRetTy::DefaultReturn(sp) => {
-                                    let sugg = format!("-> {} ", trait_sig.output());
-                                    diag.span_suggestion_verbose(sp, msg, sugg, ap);
-                                }
-                                hir::FnRetTy::Return(hir_ty) => {
-                                    let sugg = trait_sig.output();
-                                    diag.span_suggestion(hir_ty.span, msg, sugg, ap);
-                                }
-                            };
-                        }
-                        _ => {}
-                    };
-                } else if let Some(trait_ty) = trait_sig.inputs().get(*i) {
-                    diag.span_suggestion(
-                        impl_err_span,
-                        "change the parameter type to match the trait",
-                        trait_ty,
-                        Applicability::MachineApplicable,
-                    );
-                }
-            }
-            _ => {}
-        }
-
-        infcx.err_ctxt().note_type_err(
-            &mut diag,
-            &cause,
-            trait_err_span.map(|sp| (sp, "type in trait".to_owned())),
-            Some(infer::ValuePairs::Terms(ExpectedFound {
-                expected: trait_fty.into(),
-                found: impl_fty.into(),
-            })),
+        let emitted = report_trait_method_mismatch(
+            tcx,
+            &mut cause,
+            &infcx,
             terr,
-            false,
-            false,
+            (trait_m, trait_fty),
+            (impl_m, impl_fty),
+            &trait_sig,
+            &impl_trait_ref,
         );
-
-        return Err(diag.emit());
+        return Err(emitted);
     }
 
     // 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, false);
+        let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
         return Err(reported);
     }
 
@@ -424,6 +342,7 @@ fn compare_predicate_entailment<'tcx>(
     Ok(())
 }
 
+#[instrument(skip(tcx), level = "debug", ret)]
 pub fn collect_trait_impl_trait_tys<'tcx>(
     tcx: TyCtxt<'tcx>,
     def_id: DefId,
@@ -437,7 +356,7 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
 
     let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
     let return_span = tcx.hir().fn_decl_by_hir_id(impl_m_hir_id).unwrap().output.span();
-    let cause = ObligationCause::new(
+    let mut cause = ObligationCause::new(
         return_span,
         impl_m_hir_id,
         ObligationCauseCode::CompareImplItemObligation {
@@ -479,7 +398,7 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
     let trait_sig = ocx.normalize(norm_cause.clone(), param_env, unnormalized_trait_sig);
     let trait_return_ty = trait_sig.output();
 
-    let wf_tys = FxHashSet::from_iter(
+    let wf_tys = FxIndexSet::from_iter(
         unnormalized_trait_sig.inputs_and_output.iter().chain(trait_sig.inputs_and_output.iter()),
     );
 
@@ -514,23 +433,35 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
         }
     }
 
+    debug!(?trait_sig, ?impl_sig, "equating function signatures");
+
+    let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig));
+    let impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(impl_sig));
+
     // Unify the whole function signature. We need to do this to fully infer
     // the lifetimes of the return type, but do this after unifying just the
     // return types, since we want to avoid duplicating errors from
     // `compare_predicate_entailment`.
-    match infcx
-        .at(&cause, param_env)
-        .eq(tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig)), tcx.mk_fn_ptr(ty::Binder::dummy(impl_sig)))
-    {
+    match infcx.at(&cause, param_env).eq(trait_fty, impl_fty) {
         Ok(infer::InferOk { value: (), obligations }) => {
             ocx.register_obligations(obligations);
         }
         Err(terr) => {
-            let guar = tcx.sess.delay_span_bug(
-                return_span,
-                format!("could not unify `{trait_sig}` and `{impl_sig}`: {terr:?}"),
+            // This function gets called during `compare_predicate_entailment` when normalizing a
+            // signature that contains RPITIT. When the method signatures don't match, we have to
+            // emit an error now because `compare_predicate_entailment` will not report the error
+            // when normalization fails.
+            let emitted = report_trait_method_mismatch(
+                tcx,
+                &mut cause,
+                infcx,
+                terr,
+                (trait_m, trait_fty),
+                (impl_m, impl_fty),
+                &trait_sig,
+                &impl_trait_ref,
             );
-            return Err(guar);
+            return Err(emitted);
         }
     }
 
@@ -538,7 +469,7 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
     // RPITs.
     let errors = ocx.select_all_or_error();
     if !errors.is_empty() {
-        let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+        let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
         return Err(reported);
     }
 
@@ -611,11 +542,11 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
                 collected_tys.insert(def_id, ty);
             }
             Err(err) => {
-                tcx.sess.delay_span_bug(
+                let reported = tcx.sess.delay_span_bug(
                     return_span,
                     format!("could not fully resolve: {ty} => {err:?}"),
                 );
-                collected_tys.insert(def_id, tcx.ty_error());
+                collected_tys.insert(def_id, tcx.ty_error_with_guaranteed(reported));
             }
         }
     }
@@ -690,6 +621,112 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
     }
 }
 
+fn report_trait_method_mismatch<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    cause: &mut ObligationCause<'tcx>,
+    infcx: &InferCtxt<'tcx>,
+    terr: TypeError<'tcx>,
+    (trait_m, trait_fty): (&AssocItem, Ty<'tcx>),
+    (impl_m, impl_fty): (&AssocItem, Ty<'tcx>),
+    trait_sig: &FnSig<'tcx>,
+    impl_trait_ref: &TraitRef<'tcx>,
+) -> ErrorGuaranteed {
+    let (impl_err_span, trait_err_span) =
+        extract_spans_for_error_reporting(&infcx, terr, &cause, impl_m, trait_m);
+
+    cause.span = impl_err_span;
+
+    let mut diag = struct_span_err!(
+        tcx.sess,
+        cause.span(),
+        E0053,
+        "method `{}` has an incompatible type for trait",
+        trait_m.name
+    );
+    match &terr {
+        TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0)
+            if trait_m.fn_has_self_parameter =>
+        {
+            let ty = trait_sig.inputs()[0];
+            let sugg = match ExplicitSelf::determine(ty, |_| ty == impl_trait_ref.self_ty()) {
+                ExplicitSelf::ByValue => "self".to_owned(),
+                ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(),
+                ExplicitSelf::ByReference(_, hir::Mutability::Mut) => "&mut self".to_owned(),
+                _ => format!("self: {ty}"),
+            };
+
+            // When the `impl` receiver is an arbitrary self type, like `self: Box<Self>`, the
+            // span points only at the type `Box<Self`>, but we want to cover the whole
+            // argument pattern and type.
+            let span = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
+                ImplItemKind::Fn(ref sig, body) => tcx
+                    .hir()
+                    .body_param_names(body)
+                    .zip(sig.decl.inputs.iter())
+                    .map(|(param, ty)| param.span.to(ty.span))
+                    .next()
+                    .unwrap_or(impl_err_span),
+                _ => bug!("{:?} is not a method", impl_m),
+            };
+
+            diag.span_suggestion(
+                span,
+                "change the self-receiver type to match the trait",
+                sugg,
+                Applicability::MachineApplicable,
+            );
+        }
+        TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(_, i) => {
+            if trait_sig.inputs().len() == *i {
+                // Suggestion to change output type. We do not suggest in `async` functions
+                // to avoid complex logic or incorrect output.
+                match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
+                    ImplItemKind::Fn(ref sig, _)
+                        if sig.header.asyncness == hir::IsAsync::NotAsync =>
+                    {
+                        let msg = "change the output type to match the trait";
+                        let ap = Applicability::MachineApplicable;
+                        match sig.decl.output {
+                            hir::FnRetTy::DefaultReturn(sp) => {
+                                let sugg = format!("-> {} ", trait_sig.output());
+                                diag.span_suggestion_verbose(sp, msg, sugg, ap);
+                            }
+                            hir::FnRetTy::Return(hir_ty) => {
+                                let sugg = trait_sig.output();
+                                diag.span_suggestion(hir_ty.span, msg, sugg, ap);
+                            }
+                        };
+                    }
+                    _ => {}
+                };
+            } else if let Some(trait_ty) = trait_sig.inputs().get(*i) {
+                diag.span_suggestion(
+                    impl_err_span,
+                    "change the parameter type to match the trait",
+                    trait_ty,
+                    Applicability::MachineApplicable,
+                );
+            }
+        }
+        _ => {}
+    }
+
+    infcx.err_ctxt().note_type_err(
+        &mut diag,
+        &cause,
+        trait_err_span.map(|sp| (sp, "type in trait".to_owned())),
+        Some(infer::ValuePairs::Terms(ExpectedFound {
+            expected: trait_fty.into(),
+            found: impl_fty.into(),
+        })),
+        terr,
+        false,
+        false,
+    );
+
+    return diag.emit();
+}
+
 fn check_region_bounds_on_impl_item<'tcx>(
     tcx: TyCtxt<'tcx>,
     impl_m: &ty::AssocItem,
@@ -1431,7 +1468,7 @@ pub(crate) fn raw_compare_const_impl<'tcx>(
     // version.
     let errors = ocx.select_all_or_error();
     if !errors.is_empty() {
-        return Err(infcx.err_ctxt().report_fulfillment_errors(&errors, None, false));
+        return Err(infcx.err_ctxt().report_fulfillment_errors(&errors, None));
     }
 
     // FIXME return `ErrorReported` if region obligations error?
@@ -1549,7 +1586,7 @@ fn compare_type_predicate_entailment<'tcx>(
     // version.
     let errors = ocx.select_all_or_error();
     if !errors.is_empty() {
-        let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+        let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
         return Err(reported);
     }
 
@@ -1769,7 +1806,7 @@ pub fn check_type_bounds<'tcx>(
     // version.
     let errors = ocx.select_all_or_error();
     if !errors.is_empty() {
-        let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+        let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
         return Err(reported);
     }
 
index 609095c9ceaa7511b8c0106a73c6202116116e86..69e54b41d4c04331081c51aaa179e1bf75f00441 100644 (file)
@@ -134,15 +134,18 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
     let name_str = intrinsic_name.as_str();
 
     let bound_vars = tcx.mk_bound_variable_kinds(
-        [ty::BoundVariableKind::Region(ty::BrAnon(0)), ty::BoundVariableKind::Region(ty::BrEnv)]
-            .iter()
-            .copied(),
+        [
+            ty::BoundVariableKind::Region(ty::BrAnon(0, None)),
+            ty::BoundVariableKind::Region(ty::BrEnv),
+        ]
+        .iter()
+        .copied(),
     );
     let mk_va_list_ty = |mutbl| {
         tcx.lang_items().va_list().map(|did| {
             let region = tcx.mk_region(ty::ReLateBound(
                 ty::INNERMOST,
-                ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0) },
+                ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0, None) },
             ));
             let env_region = tcx.mk_region(ty::ReLateBound(
                 ty::INNERMOST,
@@ -364,7 +367,8 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
                 );
                 let discriminant_def_id = assoc_items[0];
 
-                let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0) };
+                let br =
+                    ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0, None) };
                 (
                     1,
                     vec![
@@ -418,7 +422,8 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
             sym::nontemporal_store => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()),
 
             sym::raw_eq => {
-                let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0) };
+                let br =
+                    ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0, None) };
                 let param_ty =
                     tcx.mk_imm_ref(tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)), param(0));
                 (1, vec![param_ty; 2], tcx.types.bool)
index 416b555db5c5e2e9bb4e8b5b8d6d27825f099e2c..837ff0bdf3e35401f38db801d96d286d0b67874a 100644 (file)
@@ -1,7 +1,7 @@
 use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter};
 use hir::def::DefKind;
 use rustc_ast as ast;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
 use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -105,7 +105,7 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>(
     f(&mut wfcx);
     let errors = wfcx.select_all_or_error();
     if !errors.is_empty() {
-        infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+        infcx.err_ctxt().report_fulfillment_errors(&errors, None);
         return;
     }
 
@@ -117,7 +117,7 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>(
 }
 
 fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) {
-    let node = tcx.hir().expect_owner(def_id);
+    let node = tcx.hir().owner(def_id);
     match node {
         hir::OwnerNode::Crate(_) => {}
         hir::OwnerNode::Item(item) => check_item(tcx, item),
@@ -412,7 +412,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
                                 .iter()
                                 .copied()
                                 .collect::<Vec<_>>(),
-                            &FxHashSet::default(),
+                            &FxIndexSet::default(),
                             gat_def_id.def_id,
                             gat_generics,
                         )
@@ -462,10 +462,10 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
             .into_iter()
             .filter(|clause| match clause.kind().skip_binder() {
                 ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => {
-                    !region_known_to_outlive(tcx, gat_hir, param_env, &FxHashSet::default(), a, b)
+                    !region_known_to_outlive(tcx, gat_hir, param_env, &FxIndexSet::default(), a, b)
                 }
                 ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => {
-                    !ty_known_to_outlive(tcx, gat_hir, param_env, &FxHashSet::default(), a, b)
+                    !ty_known_to_outlive(tcx, gat_hir, param_env, &FxIndexSet::default(), a, b)
                 }
                 _ => bug!("Unexpected PredicateKind"),
             })
@@ -547,7 +547,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<'tcx>>(
     param_env: ty::ParamEnv<'tcx>,
     item_hir: hir::HirId,
     to_check: T,
-    wf_tys: &FxHashSet<Ty<'tcx>>,
+    wf_tys: &FxIndexSet<Ty<'tcx>>,
     gat_def_id: LocalDefId,
     gat_generics: &'tcx ty::Generics,
 ) -> Option<FxHashSet<ty::Predicate<'tcx>>> {
@@ -654,7 +654,7 @@ fn ty_known_to_outlive<'tcx>(
     tcx: TyCtxt<'tcx>,
     id: hir::HirId,
     param_env: ty::ParamEnv<'tcx>,
-    wf_tys: &FxHashSet<Ty<'tcx>>,
+    wf_tys: &FxIndexSet<Ty<'tcx>>,
     ty: Ty<'tcx>,
     region: ty::Region<'tcx>,
 ) -> bool {
@@ -671,7 +671,7 @@ fn region_known_to_outlive<'tcx>(
     tcx: TyCtxt<'tcx>,
     id: hir::HirId,
     param_env: ty::ParamEnv<'tcx>,
-    wf_tys: &FxHashSet<Ty<'tcx>>,
+    wf_tys: &FxIndexSet<Ty<'tcx>>,
     region_a: ty::Region<'tcx>,
     region_b: ty::Region<'tcx>,
 ) -> bool {
@@ -695,7 +695,7 @@ fn resolve_regions_with_wf_tys<'tcx>(
     tcx: TyCtxt<'tcx>,
     id: hir::HirId,
     param_env: ty::ParamEnv<'tcx>,
-    wf_tys: &FxHashSet<Ty<'tcx>>,
+    wf_tys: &FxIndexSet<Ty<'tcx>>,
     add_constraints: impl for<'a> FnOnce(&'a InferCtxt<'tcx>, &'a RegionBoundPairs<'tcx>),
 ) -> bool {
     // Unfortunately, we have to use a new `InferCtxt` each call, because
@@ -1708,8 +1708,7 @@ fn receiver_is_valid<'tcx>(
         return true;
     }
 
-    let mut autoderef =
-        Autoderef::new(infcx, wfcx.param_env, wfcx.body_id, span, receiver_ty, span);
+    let mut autoderef = Autoderef::new(infcx, wfcx.param_env, wfcx.body_id, span, receiver_ty);
 
     // The `arbitrary_self_types` feature allows raw pointer receivers like `self: *const Self`.
     if arbitrary_self_types_enabled {
index b6c91d425dff4bfd6ee4b788b5af7413962a10cd..6f74ef3ccad6d75684c5576e5861fb83ac38425f 100644 (file)
@@ -321,7 +321,7 @@ fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did:
                     }),
                 );
                 if !errors.is_empty() {
-                    infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+                    infcx.err_ctxt().report_fulfillment_errors(&errors, None);
                 }
 
                 // Finally, resolve all regions.
@@ -561,7 +561,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
         predicate_for_trait_def(tcx, param_env, cause, trait_def_id, 0, source, &[target.into()]);
     let errors = traits::fully_solve_obligation(&infcx, predicate);
     if !errors.is_empty() {
-        infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+        infcx.err_ctxt().report_fulfillment_errors(&errors, None);
     }
 
     // Finally, resolve all regions.
index 25faacadf3d0c18a8ca572277481c4106561dd40..0e7a5ebf5ab6245e205951a36c1d8765212f3ec3 100644 (file)
@@ -512,8 +512,7 @@ fn projected_ty_from_poly_trait_ref(
                 }
                 _ => {}
             }
-            err.emit();
-            self.tcx().ty_error()
+            self.tcx().ty_error_with_guaranteed(err.emit())
         }
     }
 
@@ -645,12 +644,6 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
             }
         }
 
-        // Desugared from `impl Trait`, so visited by the function's return type.
-        hir::ItemKind::OpaqueTy(hir::OpaqueTy {
-            origin: hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..),
-            ..
-        }) => {}
-
         // Don't call `type_of` on opaque types, since that depends on type
         // checking function bodies. `check_item_type` ensures that it's called
         // instead.
@@ -658,27 +651,32 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
             tcx.ensure().generics_of(def_id);
             tcx.ensure().predicates_of(def_id);
             tcx.ensure().explicit_item_bounds(def_id);
+            tcx.ensure().item_bounds(def_id);
         }
-        hir::ItemKind::TyAlias(..)
-        | hir::ItemKind::Static(..)
-        | hir::ItemKind::Const(..)
-        | hir::ItemKind::Fn(..) => {
+
+        hir::ItemKind::TyAlias(..) => {
             tcx.ensure().generics_of(def_id);
             tcx.ensure().type_of(def_id);
             tcx.ensure().predicates_of(def_id);
-            match it.kind {
-                hir::ItemKind::Fn(..) => tcx.ensure().fn_sig(def_id),
-                hir::ItemKind::OpaqueTy(..) => tcx.ensure().item_bounds(def_id),
-                hir::ItemKind::Const(ty, ..) | hir::ItemKind::Static(ty, ..) => {
-                    if !is_suggestable_infer_ty(ty) {
-                        let mut visitor = HirPlaceholderCollector::default();
-                        visitor.visit_item(it);
-                        placeholder_type_error(tcx, None, visitor.0, false, None, it.kind.descr());
-                    }
-                }
-                _ => (),
+        }
+
+        hir::ItemKind::Static(ty, ..) | hir::ItemKind::Const(ty, ..) => {
+            tcx.ensure().generics_of(def_id);
+            tcx.ensure().type_of(def_id);
+            tcx.ensure().predicates_of(def_id);
+            if !is_suggestable_infer_ty(ty) {
+                let mut visitor = HirPlaceholderCollector::default();
+                visitor.visit_item(it);
+                placeholder_type_error(tcx, None, visitor.0, false, None, it.kind.descr());
             }
         }
+
+        hir::ItemKind::Fn(..) => {
+            tcx.ensure().generics_of(def_id);
+            tcx.ensure().type_of(def_id);
+            tcx.ensure().predicates_of(def_id);
+            tcx.ensure().fn_sig(def_id);
+        }
     }
 }
 
index 3d07f3fbc674dbb3d32ba541a95cf0c5c0309698..6ee7aa9cdac6b8ebc65b56a45732131aedc85768 100644 (file)
@@ -18,7 +18,7 @@
 use rustc_middle::hir::map::Map;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::resolve_lifetime::*;
-use rustc_middle::ty::{self, DefIdTree, TyCtxt};
+use rustc_middle::ty::{self, DefIdTree, TyCtxt, TypeSuperVisitable, TypeVisitor};
 use rustc_span::def_id::DefId;
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
@@ -94,11 +94,6 @@ struct LifetimeContext<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     map: &'a mut NamedRegionMap,
     scope: ScopeRef<'a>,
-
-    /// Indicates that we only care about the definition of a trait. This should
-    /// be false if the `Item` we are resolving lifetimes for is not a trait or
-    /// we eventually need lifetimes resolve for trait items.
-    trait_definition_only: bool,
 }
 
 #[derive(Debug)]
@@ -166,7 +161,9 @@ enum Scope<'a> {
         s: ScopeRef<'a>,
     },
 
-    Root,
+    Root {
+        opt_parent_item: Option<LocalDefId>,
+    },
 }
 
 #[derive(Copy, Clone, Debug)]
@@ -214,95 +211,58 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                 .field("s", &"..")
                 .finish(),
             Scope::TraitRefBoundary { s: _ } => f.debug_struct("TraitRefBoundary").finish(),
-            Scope::Root => f.debug_struct("Root").finish(),
+            Scope::Root { opt_parent_item } => {
+                f.debug_struct("Root").field("opt_parent_item", &opt_parent_item).finish()
+            }
         }
     }
 }
 
 type ScopeRef<'a> = &'a Scope<'a>;
 
-const ROOT_SCOPE: ScopeRef<'static> = &Scope::Root;
-
 pub(crate) fn provide(providers: &mut ty::query::Providers) {
     *providers = ty::query::Providers {
-        resolve_lifetimes_trait_definition,
         resolve_lifetimes,
 
-        named_region_map: |tcx, id| resolve_lifetimes_for(tcx, id).defs.get(&id),
+        named_region_map: |tcx, id| tcx.resolve_lifetimes(id).defs.get(&id),
         is_late_bound_map,
         object_lifetime_default,
-        late_bound_vars_map: |tcx, id| resolve_lifetimes_for(tcx, id).late_bound_vars.get(&id),
+        late_bound_vars_map: |tcx, id| tcx.resolve_lifetimes(id).late_bound_vars.get(&id),
 
         ..*providers
     };
 }
 
-/// Like `resolve_lifetimes`, but does not resolve lifetimes for trait items.
-/// Also does not generate any diagnostics.
-///
-/// This is ultimately a subset of the `resolve_lifetimes` work. It effectively
-/// resolves lifetimes only within the trait "header" -- that is, the trait
-/// and supertrait list. In contrast, `resolve_lifetimes` resolves all the
-/// lifetimes within the trait and its items. There is room to refactor this,
-/// for example to resolve lifetimes for each trait item in separate queries,
-/// but it's convenient to do the entire trait at once because the lifetimes
-/// from the trait definition are in scope within the trait items as well.
-///
-/// The reason for this separate call is to resolve what would otherwise
-/// be a cycle. Consider this example:
-///
-/// ```ignore UNSOLVED (maybe @jackh726 knows what lifetime parameter to give Sub)
-/// trait Base<'a> {
-///     type BaseItem;
-/// }
-/// trait Sub<'b>: for<'a> Base<'a> {
-///    type SubItem: Sub<BaseItem = &'b u32>;
-/// }
-/// ```
-///
-/// When we resolve `Sub` and all its items, we also have to resolve `Sub<BaseItem = &'b u32>`.
-/// To figure out the index of `'b`, we have to know about the supertraits
-/// of `Sub` so that we can determine that the `for<'a>` will be in scope.
-/// (This is because we -- currently at least -- flatten all the late-bound
-/// lifetimes into a single binder.) This requires us to resolve the
-/// *trait definition* of `Sub`; basically just enough lifetime information
-/// to look at the supertraits.
-#[instrument(level = "debug", skip(tcx))]
-fn resolve_lifetimes_trait_definition(
-    tcx: TyCtxt<'_>,
-    local_def_id: LocalDefId,
-) -> ResolveLifetimes {
-    convert_named_region_map(do_resolve(tcx, local_def_id, true))
-}
-
 /// Computes the `ResolveLifetimes` map that contains data for an entire `Item`.
 /// You should not read the result of this query directly, but rather use
 /// `named_region_map`, `is_late_bound_map`, etc.
 #[instrument(level = "debug", skip(tcx))]
-fn resolve_lifetimes(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> ResolveLifetimes {
-    convert_named_region_map(do_resolve(tcx, local_def_id, false))
-}
-
-fn do_resolve(
-    tcx: TyCtxt<'_>,
-    local_def_id: LocalDefId,
-    trait_definition_only: bool,
-) -> NamedRegionMap {
-    let item = tcx.hir().expect_item(local_def_id);
+fn resolve_lifetimes(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveLifetimes {
     let mut named_region_map =
         NamedRegionMap { defs: Default::default(), late_bound_vars: Default::default() };
     let mut visitor = LifetimeContext {
         tcx,
         map: &mut named_region_map,
-        scope: ROOT_SCOPE,
-        trait_definition_only,
+        scope: &Scope::Root { opt_parent_item: None },
     };
-    visitor.visit_item(item);
-
-    named_region_map
-}
+    match tcx.hir().owner(local_def_id) {
+        hir::OwnerNode::Item(item) => visitor.visit_item(item),
+        hir::OwnerNode::ForeignItem(item) => visitor.visit_foreign_item(item),
+        hir::OwnerNode::TraitItem(item) => {
+            let scope =
+                Scope::Root { opt_parent_item: Some(tcx.local_parent(item.owner_id.def_id)) };
+            visitor.scope = &scope;
+            visitor.visit_trait_item(item)
+        }
+        hir::OwnerNode::ImplItem(item) => {
+            let scope =
+                Scope::Root { opt_parent_item: Some(tcx.local_parent(item.owner_id.def_id)) };
+            visitor.scope = &scope;
+            visitor.visit_impl_item(item)
+        }
+        hir::OwnerNode::Crate(_) => {}
+    }
 
-fn convert_named_region_map(named_region_map: NamedRegionMap) -> ResolveLifetimes {
     let mut rl = ResolveLifetimes::default();
 
     for (hir_id, v) in named_region_map.defs {
@@ -319,53 +279,6 @@ fn convert_named_region_map(named_region_map: NamedRegionMap) -> ResolveLifetime
     rl
 }
 
-/// Given `any` owner (structs, traits, trait methods, etc.), does lifetime resolution.
-/// There are two important things this does.
-/// First, we have to resolve lifetimes for
-/// the entire *`Item`* that contains this owner, because that's the largest "scope"
-/// where we can have relevant lifetimes.
-/// Second, if we are asking for lifetimes in a trait *definition*, we use `resolve_lifetimes_trait_definition`
-/// instead of `resolve_lifetimes`, which does not descend into the trait items and does not emit diagnostics.
-/// This allows us to avoid cycles. Importantly, if we ask for lifetimes for lifetimes that have an owner
-/// other than the trait itself (like the trait methods or associated types), then we just use the regular
-/// `resolve_lifetimes`.
-fn resolve_lifetimes_for<'tcx>(tcx: TyCtxt<'tcx>, def_id: hir::OwnerId) -> &'tcx ResolveLifetimes {
-    let item_id = item_for(tcx, def_id.def_id);
-    let local_def_id = item_id.owner_id.def_id;
-    if item_id.owner_id == def_id {
-        let item = tcx.hir().item(item_id);
-        match item.kind {
-            hir::ItemKind::Trait(..) => tcx.resolve_lifetimes_trait_definition(local_def_id),
-            _ => tcx.resolve_lifetimes(local_def_id),
-        }
-    } else {
-        tcx.resolve_lifetimes(local_def_id)
-    }
-}
-
-/// Finds the `Item` that contains the given `LocalDefId`
-fn item_for(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> hir::ItemId {
-    match tcx.hir().find_by_def_id(local_def_id) {
-        Some(Node::Item(item)) => {
-            return item.item_id();
-        }
-        _ => {}
-    }
-    let item = {
-        let hir_id = tcx.hir().local_def_id_to_hir_id(local_def_id);
-        let mut parent_iter = tcx.hir().parent_iter(hir_id);
-        loop {
-            let node = parent_iter.next().map(|n| n.1);
-            match node {
-                Some(hir::Node::Item(item)) => break item.item_id(),
-                Some(hir::Node::Crate(_)) | None => bug!("Called `item_for` on an Item."),
-                _ => {}
-            }
-        }
-    };
-    item
-}
-
 fn late_region_as_bound_region<'tcx>(tcx: TyCtxt<'tcx>, region: &Region) -> ty::BoundVariableKind {
     match region {
         Region::LateBound(_, _, def_id) => {
@@ -383,7 +296,7 @@ fn poly_trait_ref_binder_info(&mut self) -> (Vec<ty::BoundVariableKind>, BinderS
         let mut supertrait_lifetimes = vec![];
         loop {
             match scope {
-                Scope::Body { .. } | Scope::Root => {
+                Scope::Body { .. } | Scope::Root { .. } => {
                     break (vec![], BinderScopeType::Normal);
                 }
 
@@ -414,21 +327,12 @@ fn poly_trait_ref_binder_info(&mut self) -> (Vec<ty::BoundVariableKind>, BinderS
     }
 }
 impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
-    type NestedFilter = nested_filter::All;
+    type NestedFilter = nested_filter::OnlyBodies;
 
     fn nested_visit_map(&mut self) -> Self::Map {
         self.tcx.hir()
     }
 
-    // We want to nest trait/impl items in their parent, but nothing else.
-    fn visit_nested_item(&mut self, _: hir::ItemId) {}
-
-    fn visit_trait_item_ref(&mut self, ii: &'tcx hir::TraitItemRef) {
-        if !self.trait_definition_only {
-            intravisit::walk_trait_item_ref(self, ii)
-        }
-    }
-
     fn visit_nested_body(&mut self, body: hir::BodyId) {
         let body = self.tcx.hir().body(body);
         self.with(Scope::Body { id: body.id(), s: self.scope }, |this| {
@@ -548,7 +452,9 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                     intravisit::walk_item(this, item)
                 });
             }
-            hir::ItemKind::OpaqueTy(hir::OpaqueTy { .. }) => {
+            hir::ItemKind::OpaqueTy(hir::OpaqueTy {
+                origin: hir::OpaqueTyOrigin::TyAlias, ..
+            }) => {
                 // Opaque types are visited when we visit the
                 // `TyKind::OpaqueDef`, so that they have the lifetimes from
                 // their parent opaque_ty in scope.
@@ -557,34 +463,53 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                 // their owner, we can keep going until we find the Item that owns that. We then
                 // conservatively add all resolved lifetimes. Otherwise we run into problems in
                 // cases like `type Foo<'a> = impl Bar<As = impl Baz + 'a>`.
-                for (_hir_id, node) in self.tcx.hir().parent_iter(item.owner_id.into()) {
-                    match node {
-                        hir::Node::Item(parent_item) => {
-                            let resolved_lifetimes: &ResolveLifetimes = self.tcx.resolve_lifetimes(
-                                item_for(self.tcx, parent_item.owner_id.def_id).owner_id.def_id,
-                            );
-                            // We need to add *all* deps, since opaque tys may want them from *us*
-                            for (&owner, defs) in resolved_lifetimes.defs.iter() {
-                                defs.iter().for_each(|(&local_id, region)| {
-                                    self.map.defs.insert(hir::HirId { owner, local_id }, *region);
-                                });
-                            }
-                            for (&owner, late_bound_vars) in
-                                resolved_lifetimes.late_bound_vars.iter()
-                            {
-                                late_bound_vars.iter().for_each(|(&local_id, late_bound_vars)| {
-                                    self.record_late_bound_vars(
-                                        hir::HirId { owner, local_id },
-                                        late_bound_vars.clone(),
-                                    );
-                                });
-                            }
-                            break;
+                let parent_item = self.tcx.hir().get_parent_item(item.hir_id());
+                let resolved_lifetimes: &ResolveLifetimes = self.tcx.resolve_lifetimes(parent_item);
+                // We need to add *all* deps, since opaque tys may want them from *us*
+                for (&owner, defs) in resolved_lifetimes.defs.iter() {
+                    defs.iter().for_each(|(&local_id, region)| {
+                        self.map.defs.insert(hir::HirId { owner, local_id }, *region);
+                    });
+                }
+                for (&owner, late_bound_vars) in resolved_lifetimes.late_bound_vars.iter() {
+                    late_bound_vars.iter().for_each(|(&local_id, late_bound_vars)| {
+                        self.record_late_bound_vars(
+                            hir::HirId { owner, local_id },
+                            late_bound_vars.clone(),
+                        );
+                    });
+                }
+            }
+            hir::ItemKind::OpaqueTy(hir::OpaqueTy {
+                origin: hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_),
+                generics,
+                ..
+            }) => {
+                // We want to start our early-bound indices at the end of the parent scope,
+                // not including any parent `impl Trait`s.
+                let mut lifetimes = FxIndexMap::default();
+                debug!(?generics.params);
+                for param in generics.params {
+                    match param.kind {
+                        GenericParamKind::Lifetime { .. } => {
+                            let (def_id, reg) = Region::early(self.tcx.hir(), &param);
+                            lifetimes.insert(def_id, reg);
                         }
-                        hir::Node::Crate(_) => bug!("No Item about an OpaqueTy"),
-                        _ => {}
+                        GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {}
                     }
                 }
+
+                let scope = Scope::Binder {
+                    hir_id: item.hir_id(),
+                    lifetimes,
+                    s: self.scope,
+                    scope_type: BinderScopeType::Normal,
+                    where_bound_origin: None,
+                };
+                self.with(scope, |this| {
+                    let scope = Scope::TraitRefBoundary { s: this.scope };
+                    this.with(scope, |this| intravisit::walk_item(this, item))
+                });
             }
             hir::ItemKind::TyAlias(_, ref generics)
             | hir::ItemKind::Enum(_, ref generics)
@@ -609,7 +534,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                     hir_id: item.hir_id(),
                     lifetimes,
                     scope_type: BinderScopeType::Normal,
-                    s: ROOT_SCOPE,
+                    s: self.scope,
                     where_bound_origin: None,
                 };
                 self.with(scope, |this| {
@@ -712,7 +637,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
                 //                 ^                  ^ this gets resolved in the scope of
                 //                                      the opaque_ty generics
                 let opaque_ty = self.tcx.hir().item(item_id);
-                let (generics, bounds) = match opaque_ty.kind {
+                match opaque_ty.kind {
                     hir::ItemKind::OpaqueTy(hir::OpaqueTy {
                         origin: hir::OpaqueTyOrigin::TyAlias,
                         ..
@@ -733,10 +658,8 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
                     }
                     hir::ItemKind::OpaqueTy(hir::OpaqueTy {
                         origin: hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..),
-                        ref generics,
-                        bounds,
                         ..
-                    }) => (generics, bounds),
+                    }) => {}
                     ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i),
                 };
 
@@ -766,65 +689,28 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
                     // Ensure that the parent of the def is an item, not HRTB
                     let parent_id = self.tcx.hir().get_parent_node(hir_id);
                     if !parent_id.is_owner() {
-                        if !self.trait_definition_only {
-                            struct_span_err!(
-                                self.tcx.sess,
-                                lifetime.span,
-                                E0657,
-                                "`impl Trait` can only capture lifetimes \
-                                    bound at the fn or impl level"
-                            )
-                            .emit();
-                        }
+                        struct_span_err!(
+                            self.tcx.sess,
+                            lifetime.span,
+                            E0657,
+                            "`impl Trait` can only capture lifetimes bound at the fn or impl level"
+                        )
+                        .emit();
                         self.uninsert_lifetime_on_error(lifetime, def.unwrap());
                     }
                     if let hir::Node::Item(hir::Item {
                         kind: hir::ItemKind::OpaqueTy { .. }, ..
                     }) = self.tcx.hir().get(parent_id)
                     {
-                        if !self.trait_definition_only {
-                            let mut err = self.tcx.sess.struct_span_err(
-                                lifetime.span,
-                                "higher kinded lifetime bounds on nested opaque types are not supported yet",
-                            );
-                            err.span_note(self.tcx.def_span(def_id), "lifetime declared here");
-                            err.emit();
-                        }
+                        let mut err = self.tcx.sess.struct_span_err(
+                            lifetime.span,
+                            "higher kinded lifetime bounds on nested opaque types are not supported yet",
+                        );
+                        err.span_note(self.tcx.def_span(def_id), "lifetime declared here");
+                        err.emit();
                         self.uninsert_lifetime_on_error(lifetime, def.unwrap());
                     }
                 }
-
-                // We want to start our early-bound indices at the end of the parent scope,
-                // not including any parent `impl Trait`s.
-                let mut lifetimes = FxIndexMap::default();
-                debug!(?generics.params);
-                for param in generics.params {
-                    match param.kind {
-                        GenericParamKind::Lifetime { .. } => {
-                            let (def_id, reg) = Region::early(self.tcx.hir(), &param);
-                            lifetimes.insert(def_id, reg);
-                        }
-                        GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {}
-                    }
-                }
-                self.record_late_bound_vars(ty.hir_id, vec![]);
-
-                let scope = Scope::Binder {
-                    hir_id: ty.hir_id,
-                    lifetimes,
-                    s: self.scope,
-                    scope_type: BinderScopeType::Normal,
-                    where_bound_origin: None,
-                };
-                self.with(scope, |this| {
-                    let scope = Scope::TraitRefBoundary { s: this.scope };
-                    this.with(scope, |this| {
-                        this.visit_generics(generics);
-                        for bound in bounds {
-                            this.visit_param_bound(bound);
-                        }
-                    })
-                });
             }
             _ => intravisit::walk_ty(self, ty),
         }
@@ -1193,12 +1079,7 @@ fn with<F>(&mut self, wrap_scope: Scope<'_>, f: F)
         F: for<'b> FnOnce(&mut LifetimeContext<'b, 'tcx>),
     {
         let LifetimeContext { tcx, map, .. } = self;
-        let mut this = LifetimeContext {
-            tcx: *tcx,
-            map,
-            scope: &wrap_scope,
-            trait_definition_only: self.trait_definition_only,
-        };
+        let mut this = LifetimeContext { tcx: *tcx, map, scope: &wrap_scope };
         let span = debug_span!("scope", scope = ?TruncatedScopeDebug(&this.scope));
         {
             let _enter = span.enter();
@@ -1303,7 +1184,13 @@ fn resolve_lifetime_ref(
                     scope = s;
                 }
 
-                Scope::Root => {
+                Scope::Root { opt_parent_item } => {
+                    if let Some(parent_item) = opt_parent_item
+                        && let parent_generics = self.tcx.generics_of(parent_item)
+                        && parent_generics.param_def_id_to_index.contains_key(&region_def_id.to_def_id())
+                    {
+                        break Some(Region::EarlyBound(region_def_id.to_def_id()));
+                    }
                     break None;
                 }
 
@@ -1417,7 +1304,7 @@ fn resolve_lifetime_ref(
                     err.emit();
                     return;
                 }
-                Scope::Root => break,
+                Scope::Root { .. } => break,
                 Scope::Binder { s, .. }
                 | Scope::Body { s, .. }
                 | Scope::Elision { s, .. }
@@ -1495,7 +1382,7 @@ fn visit_segment_args(
                 let mut scope = self.scope;
                 loop {
                     match *scope {
-                        Scope::Root => break false,
+                        Scope::Root { .. } => break false,
 
                         Scope::Body { .. } => break true,
 
@@ -1732,7 +1619,7 @@ fn resolve_object_lifetime_default(&mut self, lifetime_ref: &'tcx hir::Lifetime)
                     scope = s;
                 }
 
-                Scope::Root | Scope::Elision { .. } => break Region::Static,
+                Scope::Root { .. } | Scope::Elision { .. } => break Region::Static,
 
                 Scope::Body { .. } | Scope::ObjectLifetimeDefault { lifetime: None, .. } => return,
 
@@ -1781,7 +1668,7 @@ fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxIndexSet<
 
     let mut late_bound = FxIndexSet::default();
 
-    let mut constrained_by_input = ConstrainedCollector::default();
+    let mut constrained_by_input = ConstrainedCollector { regions: Default::default(), tcx };
     for arg_ty in decl.inputs {
         constrained_by_input.visit_ty(arg_ty);
     }
@@ -1834,12 +1721,65 @@ fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxIndexSet<
     debug!(?late_bound);
     return Some(tcx.arena.alloc(late_bound));
 
-    #[derive(Default)]
-    struct ConstrainedCollector {
+    /// Visits a `ty::Ty` collecting information about what generic parameters are constrained.
+    ///
+    /// The visitor does not operate on `hir::Ty` so that it can be called on the rhs of a `type Alias<...> = ...;`
+    /// which may live in a separate crate so there would not be any hir available. Instead we use the `type_of`
+    /// query to obtain a `ty::Ty` which will be present even in cross crate scenarios. It also naturally
+    /// handles cycle detection as we go through the query system.
+    ///
+    /// This is necessary in the first place for the following case:
+    /// ```
+    /// type Alias<'a, T> = <T as Trait<'a>>::Assoc;
+    /// fn foo<'a>(_: Alias<'a, ()>) -> Alias<'a, ()> { ... }
+    /// ```
+    ///
+    /// If we conservatively considered `'a` unconstrained then we could break users who had written code before
+    /// we started correctly handling aliases. If we considered `'a` constrained then it would become late bound
+    /// causing an error during astconv as the `'a` is not constrained by the input type `<() as Trait<'a>>::Assoc`
+    /// but appears in the output type `<() as Trait<'a>>::Assoc`.
+    ///
+    /// We must therefore "look into" the `Alias` to see whether we should consider `'a` constrained or not.
+    ///
+    /// See #100508 #85533 #47511 for additional context
+    struct ConstrainedCollectorPostAstConv {
+        arg_is_constrained: Box<[bool]>,
+    }
+
+    use std::ops::ControlFlow;
+    use ty::Ty;
+    impl<'tcx> TypeVisitor<'tcx> for ConstrainedCollectorPostAstConv {
+        fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<!> {
+            match t.kind() {
+                ty::Param(param_ty) => {
+                    self.arg_is_constrained[param_ty.index as usize] = true;
+                }
+                ty::Projection(_) => return ControlFlow::Continue(()),
+                _ => (),
+            }
+            t.super_visit_with(self)
+        }
+
+        fn visit_const(&mut self, _: ty::Const<'tcx>) -> ControlFlow<!> {
+            ControlFlow::Continue(())
+        }
+
+        fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<!> {
+            debug!("r={:?}", r.kind());
+            if let ty::RegionKind::ReEarlyBound(region) = r.kind() {
+                self.arg_is_constrained[region.index as usize] = true;
+            }
+
+            ControlFlow::Continue(())
+        }
+    }
+
+    struct ConstrainedCollector<'tcx> {
+        tcx: TyCtxt<'tcx>,
         regions: FxHashSet<LocalDefId>,
     }
 
-    impl<'v> Visitor<'v> for ConstrainedCollector {
+    impl<'v> Visitor<'v> for ConstrainedCollector<'_> {
         fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
             match ty.kind {
                 hir::TyKind::Path(
@@ -1850,6 +1790,47 @@ fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
                     // (defined above)
                 }
 
+                hir::TyKind::Path(hir::QPath::Resolved(
+                    None,
+                    hir::Path { res: Res::Def(DefKind::TyAlias, alias_def), segments, span },
+                )) => {
+                    // See comments on `ConstrainedCollectorPostAstConv` for why this arm does not just consider
+                    // substs to be unconstrained.
+                    let generics = self.tcx.generics_of(alias_def);
+                    let mut walker = ConstrainedCollectorPostAstConv {
+                        arg_is_constrained: vec![false; generics.params.len()].into_boxed_slice(),
+                    };
+                    walker.visit_ty(self.tcx.type_of(alias_def));
+
+                    match segments.last() {
+                        Some(hir::PathSegment { args: Some(args), .. }) => {
+                            let tcx = self.tcx;
+                            for constrained_arg in
+                                args.args.iter().enumerate().flat_map(|(n, arg)| {
+                                    match walker.arg_is_constrained.get(n) {
+                                        Some(true) => Some(arg),
+                                        Some(false) => None,
+                                        None => {
+                                            tcx.sess.delay_span_bug(
+                                                *span,
+                                                format!(
+                                                    "Incorrect generic arg count for alias {:?}",
+                                                    alias_def
+                                                ),
+                                            );
+                                            None
+                                        }
+                                    }
+                                })
+                            {
+                                self.visit_generic_arg(constrained_arg);
+                            }
+                        }
+                        Some(_) => (),
+                        None => bug!("Path with no segments or self type"),
+                    }
+                }
+
                 hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => {
                     // consider only the lifetimes on the final
                     // segment; I am not sure it's even currently
index c29a645eb4a888332f961c500e07d5b7c58d0b11..2402495c2e4a6ffde84ea918a633705408a27c27 100644 (file)
@@ -698,7 +698,7 @@ fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
     }
 
     let Some(hidden) = locator.found else {
-        tcx.sess.emit_err(UnconstrainedOpaqueType {
+        let reported = tcx.sess.emit_err(UnconstrainedOpaqueType {
             span: tcx.def_span(def_id),
             name: tcx.item_name(tcx.local_parent(def_id).to_def_id()),
             what: match tcx.hir().get(scope) {
@@ -708,7 +708,7 @@ fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
                 _ => "item",
             },
         });
-        return tcx.ty_error();
+        return tcx.ty_error_with_guaranteed(reported);
     };
 
     // Only check against typeck if we didn't already error
index e806e94879d932641087b87b842ae3fdab334b98..55cca0cd2d7b540b2a3edad210ada95d39fc6d67 100644 (file)
@@ -69,6 +69,7 @@
 use crate::errors::SubstsOnOverriddenImpl;
 
 use rustc_data_structures::fx::FxHashSet;
+use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::TyCtxtInferExt;
@@ -80,6 +81,7 @@
 use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
 use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
 use rustc_trait_selection::traits::{self, translate_substs, wf, ObligationCtxt};
+use tracing::instrument;
 
 pub(super) fn check_min_specialization(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) {
     if let Some(node) = parent_specialization_node(tcx, impl_def_id) {
@@ -103,13 +105,11 @@ fn parent_specialization_node(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId) -> Opti
 }
 
 /// Check that `impl1` is a sound specialization
+#[instrument(level = "debug", skip(tcx))]
 fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node) {
     if let Some((impl1_substs, impl2_substs)) = get_impl_substs(tcx, impl1_def_id, impl2_node) {
         let impl2_def_id = impl2_node.def_id();
-        debug!(
-            "check_always_applicable(\nimpl1_def_id={:?},\nimpl2_def_id={:?},\nimpl2_substs={:?}\n)",
-            impl1_def_id, impl2_def_id, impl2_substs
-        );
+        debug!(?impl2_def_id, ?impl2_substs);
 
         let parent_substs = if impl2_node.is_from_trait() {
             impl2_substs.to_vec()
@@ -118,12 +118,33 @@ fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node
         };
 
         let span = tcx.def_span(impl1_def_id);
+        check_constness(tcx, impl1_def_id, impl2_node, span);
         check_static_lifetimes(tcx, &parent_substs, span);
         check_duplicate_params(tcx, impl1_substs, &parent_substs, span);
         check_predicates(tcx, impl1_def_id, impl1_substs, impl2_node, impl2_substs, span);
     }
 }
 
+/// Check that the specializing impl `impl1` is at least as const as the base
+/// impl `impl2`
+fn check_constness(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node, span: Span) {
+    if impl2_node.is_from_trait() {
+        // This isn't a specialization
+        return;
+    }
+
+    let impl1_constness = tcx.constness(impl1_def_id.to_def_id());
+    let impl2_constness = tcx.constness(impl2_node.def_id());
+
+    if let hir::Constness::Const = impl2_constness {
+        if let hir::Constness::NotConst = impl1_constness {
+            tcx.sess
+                .struct_span_err(span, "cannot specialize on const impl with non-const impl")
+                .emit();
+        }
+    }
+}
+
 /// Given a specializing impl `impl1`, and the base impl `impl2`, returns two
 /// substitutions `(S1, S2)` that equate their trait references. The returned
 /// types are expressed in terms of the generics of `impl1`.
@@ -155,7 +176,7 @@ fn get_impl_substs<'tcx>(
 
     let errors = ocx.select_all_or_error();
     if !errors.is_empty() {
-        ocx.infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+        ocx.infcx.err_ctxt().report_fulfillment_errors(&errors, None);
         return None;
     }
 
@@ -278,15 +299,15 @@ fn check_static_lifetimes<'tcx>(
 
 /// Check whether predicates on the specializing impl (`impl1`) are allowed.
 ///
-/// Each predicate `P` must be:
+/// Each predicate `P` must be one of:
 ///
-/// * global (not reference any parameters)
-/// * `T: Tr` predicate where `Tr` is an always-applicable trait
-/// * on the base `impl impl2`
-///     * Currently this check is done using syntactic equality, which is
-///       conservative but generally sufficient.
-/// * a well-formed predicate of a type argument of the trait being implemented,
+/// * Global (not reference any parameters).
+/// * A `T: Tr` predicate where `Tr` is an always-applicable trait.
+/// * Present on the base impl `impl2`.
+///     * This check is done using the `trait_predicates_eq` function below.
+/// * A well-formed predicate of a type argument of the trait being implemented,
 ///   including the `Self`-type.
+#[instrument(level = "debug", skip(tcx))]
 fn check_predicates<'tcx>(
     tcx: TyCtxt<'tcx>,
     impl1_def_id: LocalDefId,
@@ -322,10 +343,7 @@ fn check_predicates<'tcx>(
         .map(|obligation| obligation.predicate)
         .collect()
     };
-    debug!(
-        "check_always_applicable(\nimpl1_predicates={:?},\nimpl2_predicates={:?}\n)",
-        impl1_predicates, impl2_predicates,
-    );
+    debug!(?impl1_predicates, ?impl2_predicates);
 
     // Since impls of always applicable traits don't get to assume anything, we
     // can also assume their supertraits apply.
@@ -373,25 +391,83 @@ fn check_predicates<'tcx>(
     );
 
     for (predicate, span) in impl1_predicates {
-        if !impl2_predicates.contains(&predicate) {
+        if !impl2_predicates.iter().any(|pred2| trait_predicates_eq(tcx, predicate, *pred2, span)) {
             check_specialization_on(tcx, predicate, span)
         }
     }
 }
 
+/// Checks if some predicate on the specializing impl (`predicate1`) is the same
+/// as some predicate on the base impl (`predicate2`).
+///
+/// This basically just checks syntactic equivalence, but is a little more
+/// forgiving since we want to equate `T: Tr` with `T: ~const Tr` so this can work:
+///
+/// ```ignore (illustrative)
+/// #[rustc_specialization_trait]
+/// trait Specialize { }
+///
+/// impl<T: Bound> Tr for T { }
+/// impl<T: ~const Bound + Specialize> const Tr for T { }
+/// ```
+///
+/// However, we *don't* want to allow the reverse, i.e., when the bound on the
+/// specializing impl is not as const as the bound on the base impl:
+///
+/// ```ignore (illustrative)
+/// impl<T: ~const Bound> const Tr for T { }
+/// impl<T: Bound + Specialize> const Tr for T { } // should be T: ~const Bound
+/// ```
+///
+/// So we make that check in this function and try to raise a helpful error message.
+fn trait_predicates_eq<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    predicate1: ty::Predicate<'tcx>,
+    predicate2: ty::Predicate<'tcx>,
+    span: Span,
+) -> bool {
+    let pred1_kind = predicate1.kind().skip_binder();
+    let pred2_kind = predicate2.kind().skip_binder();
+    let (trait_pred1, trait_pred2) = match (pred1_kind, pred2_kind) {
+        (ty::PredicateKind::Trait(pred1), ty::PredicateKind::Trait(pred2)) => (pred1, pred2),
+        // Just use plain syntactic equivalence if either of the predicates aren't
+        // trait predicates or have bound vars.
+        _ => return predicate1 == predicate2,
+    };
+
+    let predicates_equal_modulo_constness = {
+        let pred1_unconsted =
+            ty::TraitPredicate { constness: ty::BoundConstness::NotConst, ..trait_pred1 };
+        let pred2_unconsted =
+            ty::TraitPredicate { constness: ty::BoundConstness::NotConst, ..trait_pred2 };
+        pred1_unconsted == pred2_unconsted
+    };
+
+    if !predicates_equal_modulo_constness {
+        return false;
+    }
+
+    // Check that the predicate on the specializing impl is at least as const as
+    // the one on the base.
+    match (trait_pred2.constness, trait_pred1.constness) {
+        (ty::BoundConstness::ConstIfConst, ty::BoundConstness::NotConst) => {
+            tcx.sess.struct_span_err(span, "missing `~const` qualifier for specialization").emit();
+        }
+        _ => {}
+    }
+
+    true
+}
+
+#[instrument(level = "debug", skip(tcx))]
 fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tcx>, span: Span) {
-    debug!("can_specialize_on(predicate = {:?})", predicate);
     match predicate.kind().skip_binder() {
         // Global predicates are either always true or always false, so we
         // are fine to specialize on.
         _ if predicate.is_global() => (),
         // We allow specializing on explicitly marked traits with no associated
         // items.
-        ty::PredicateKind::Trait(ty::TraitPredicate {
-            trait_ref,
-            constness: ty::BoundConstness::NotConst,
-            polarity: _,
-        }) => {
+        ty::PredicateKind::Trait(ty::TraitPredicate { trait_ref, constness: _, polarity: _ }) => {
             if !matches!(
                 trait_predicate_kind(tcx, predicate),
                 Some(TraitSpecializationKind::Marker)
index bd1a461b93522235cb2b6423a48da8f0f11c4dfa..664d3a3a1db84c3d5e8cefd394ee650daaff1613 100644 (file)
@@ -173,7 +173,7 @@ fn require_same_types<'tcx>(
     match &errors[..] {
         [] => true,
         errors => {
-            infcx.err_ctxt().report_fulfillment_errors(errors, None, false);
+            infcx.err_ctxt().report_fulfillment_errors(errors, None);
             false
         }
     }
@@ -336,7 +336,7 @@ fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
         ocx.register_bound(cause, param_env, norm_return_ty, term_did);
         let errors = ocx.select_all_or_error();
         if !errors.is_empty() {
-            infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+            infcx.err_ctxt().report_fulfillment_errors(&errors, None);
             error = true;
         }
         // now we can take the return type of the given main function
index 8d39fa81165ea6bdec7d832b39d3313f31f09b46..6a4a6a5b0a546716721f3bf2d9ec77cbd0a6ed5a 100644 (file)
@@ -1,6 +1,6 @@
 use crate::coercion::{AsCoercionSite, CoerceMany};
 use crate::{Diverges, Expectation, FnCtxt, Needs};
-use rustc_errors::{Applicability, MultiSpan};
+use rustc_errors::{Applicability, Diagnostic, MultiSpan};
 use rustc_hir::{self as hir, ExprKind};
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::traits::Obligation;
@@ -137,55 +137,13 @@ pub fn check_match(
                 Some(&arm.body),
                 arm_ty,
                 Some(&mut |err| {
-                    let Some(ret) = self
-                        .tcx
-                        .hir()
-                        .find_by_def_id(self.body_id.owner.def_id)
-                        .and_then(|owner| owner.fn_decl())
-                        .map(|decl| decl.output.span())
-                    else { return; };
-                    let Expectation::IsLast(stmt) = orig_expected else {
-                        return
-                    };
-                    let can_coerce_to_return_ty = match self.ret_coercion.as_ref() {
-                        Some(ret_coercion) if self.in_tail_expr => {
-                            let ret_ty = ret_coercion.borrow().expected_ty();
-                            let ret_ty = self.inh.infcx.shallow_resolve(ret_ty);
-                            self.can_coerce(arm_ty, ret_ty)
-                                && prior_arm.map_or(true, |(_, t, _)| self.can_coerce(t, ret_ty))
-                                // The match arms need to unify for the case of `impl Trait`.
-                                && !matches!(ret_ty.kind(), ty::Opaque(..))
-                        }
-                        _ => false,
-                    };
-                    if !can_coerce_to_return_ty {
-                        return;
-                    }
-
-                    let semi_span = expr.span.shrink_to_hi().with_hi(stmt.hi());
-                    let mut ret_span: MultiSpan = semi_span.into();
-                    ret_span.push_span_label(
-                        expr.span,
-                        "this could be implicitly returned but it is a statement, not a \
-                            tail expression",
-                    );
-                    ret_span
-                        .push_span_label(ret, "the `match` arms can conform to this return type");
-                    ret_span.push_span_label(
-                        semi_span,
-                        "the `match` is a statement because of this semicolon, consider \
-                            removing it",
-                    );
-                    err.span_note(
-                        ret_span,
-                        "you might have meant to return the `match` expression",
-                    );
-                    err.tool_only_span_suggestion(
-                        semi_span,
-                        "remove this semicolon",
-                        "",
-                        Applicability::MaybeIncorrect,
-                    );
+                    self.suggest_removing_semicolon_for_coerce(
+                        err,
+                        expr,
+                        orig_expected,
+                        arm_ty,
+                        prior_arm,
+                    )
                 }),
                 false,
             );
@@ -219,6 +177,71 @@ pub fn check_match(
         coercion.complete(self)
     }
 
+    fn suggest_removing_semicolon_for_coerce(
+        &self,
+        diag: &mut Diagnostic,
+        expr: &hir::Expr<'tcx>,
+        expectation: Expectation<'tcx>,
+        arm_ty: Ty<'tcx>,
+        prior_arm: Option<(Option<hir::HirId>, Ty<'tcx>, Span)>,
+    ) {
+        let hir = self.tcx.hir();
+
+        // First, check that we're actually in the tail of a function.
+        let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Block(block, _), .. }) =
+            hir.get(self.body_id) else { return; };
+        let Some(hir::Stmt { kind: hir::StmtKind::Semi(last_expr), .. })
+            = block.innermost_block().stmts.last() else {  return; };
+        if last_expr.hir_id != expr.hir_id {
+            return;
+        }
+
+        // Next, make sure that we have no type expectation.
+        let Some(ret) = hir
+            .find_by_def_id(self.body_id.owner.def_id)
+            .and_then(|owner| owner.fn_decl())
+            .map(|decl| decl.output.span()) else { return; };
+        let Expectation::IsLast(stmt) = expectation else {
+            return;
+        };
+
+        let can_coerce_to_return_ty = match self.ret_coercion.as_ref() {
+            Some(ret_coercion) => {
+                let ret_ty = ret_coercion.borrow().expected_ty();
+                let ret_ty = self.inh.infcx.shallow_resolve(ret_ty);
+                self.can_coerce(arm_ty, ret_ty)
+                    && prior_arm.map_or(true, |(_, ty, _)| self.can_coerce(ty, ret_ty))
+                    // The match arms need to unify for the case of `impl Trait`.
+                    && !matches!(ret_ty.kind(), ty::Opaque(..))
+            }
+            _ => false,
+        };
+        if !can_coerce_to_return_ty {
+            return;
+        }
+
+        let semi_span = expr.span.shrink_to_hi().with_hi(stmt.hi());
+        let mut ret_span: MultiSpan = semi_span.into();
+        ret_span.push_span_label(
+            expr.span,
+            "this could be implicitly returned but it is a statement, not a \
+                            tail expression",
+        );
+        ret_span.push_span_label(ret, "the `match` arms can conform to this return type");
+        ret_span.push_span_label(
+            semi_span,
+            "the `match` is a statement because of this semicolon, consider \
+                            removing it",
+        );
+        diag.span_note(ret_span, "you might have meant to return the `match` expression");
+        diag.tool_only_span_suggestion(
+            semi_span,
+            "remove this semicolon",
+            "",
+            Applicability::MaybeIncorrect,
+        );
+    }
+
     /// When the previously checked expression (the scrutinee) diverges,
     /// warn the user about the match arms being unreachable.
     fn warn_arms_when_scrutinee_diverges(&self, arms: &'tcx [hir::Arm<'tcx>]) {
index 59c366ad7d776cb41868bc18140e042f70ccab60..41b52a4c4a9fcb2901c2f26a1562e65faae1a7b3 100644 (file)
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'tcx> {
-        Autoderef::new(self, self.param_env, self.body_id, span, base_ty, span)
-    }
-
-    /// Like `autoderef`, but provides a custom `Span` to use for calls to
-    /// an overloaded `Deref` operator
-    pub fn autoderef_overloaded_span(
-        &'a self,
-        span: Span,
-        base_ty: Ty<'tcx>,
-        overloaded_span: Span,
-    ) -> Autoderef<'a, 'tcx> {
-        Autoderef::new(self, self.param_env, self.body_id, span, base_ty, overloaded_span)
+        Autoderef::new(self, self.param_env, self.body_id, span, base_ty)
     }
 
     pub fn try_overloaded_deref(
@@ -55,11 +44,7 @@ pub fn adjust_steps_as_infer_ok(
                         |InferOk { value: method, obligations: o }| {
                             obligations.extend(o);
                             if let ty::Ref(region, _, mutbl) = *method.sig.output().kind() {
-                                Some(OverloadedDeref {
-                                    region,
-                                    mutbl,
-                                    span: autoderef.overloaded_span(),
-                                })
+                                Some(OverloadedDeref { region, mutbl, span: autoderef.span() })
                             } else {
                                 None
                             }
index 37af6e79c3ef5ef44a3ef78c02db79cb17e66788..3c57e33f6f7fb164e10213569cf5a32cd538343c 100644 (file)
@@ -100,7 +100,6 @@ pub(super) fn check_fn<'a, 'tcx>(
 
     inherited.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig);
 
-    fcx.in_tail_expr = true;
     if let ty::Dynamic(..) = declared_ret_ty.kind() {
         // FIXME: We need to verify that the return type is `Sized` after the return expression has
         // been evaluated so that we have types available for all the nodes being returned, but that
@@ -119,7 +118,6 @@ pub(super) fn check_fn<'a, 'tcx>(
         fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
         fcx.check_return_expr(&body.value, false);
     }
-    fcx.in_tail_expr = false;
 
     // We insert the deferred_generator_interiors entry after visiting the body.
     // This ensures that all nested generators appear before the entry of this generator.
index 09df50c76b73828500f0466c55e54bb2154adec9..3001e7994767296fc940ee2e653953c89b0dd1a3 100644 (file)
@@ -10,6 +10,7 @@
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::LateBoundRegionConversionTime;
 use rustc_infer::infer::{InferOk, InferResult};
+use rustc_macros::{TypeFoldable, TypeVisitable};
 use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::visit::TypeVisitable;
 use rustc_middle::ty::{self, Ty};
@@ -22,7 +23,7 @@
 use std::iter;
 
 /// What signature do we *expect* the closure to have from context?
-#[derive(Debug)]
+#[derive(Debug, Clone, TypeFoldable, TypeVisitable)]
 struct ExpectedSig<'tcx> {
     /// Span that gave us this expectation, if we know that.
     cause_span: Option<Span>,
@@ -241,9 +242,12 @@ fn deduce_expectations_from_obligations(
             if expected_sig.is_none()
                 && let ty::PredicateKind::Projection(proj_predicate) = bound_predicate.skip_binder()
             {
-                expected_sig = self.deduce_sig_from_projection(
+                expected_sig = self.normalize_associated_types_in(
+                    obligation.cause.span,
+                    self.deduce_sig_from_projection(
                     Some(obligation.cause.span),
-                    bound_predicate.rebind(proj_predicate),
+                        bound_predicate.rebind(proj_predicate),
+                    ),
                 );
             }
 
index e8bf299b0378ea2241f04cd11c3fb29700a925df..71949b4211819b79d08c09b5b32872504294a3a7 100644 (file)
@@ -62,6 +62,7 @@
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::infer::InferCtxtExt as _;
 use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
+use rustc_trait_selection::traits::TraitEngineExt as _;
 use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
 
 use smallvec::{smallvec, SmallVec};
@@ -705,12 +706,7 @@ fn coerce_unsized(&self, mut source: Ty<'tcx>, mut target: Ty<'tcx>) -> CoerceRe
 
                 // Object safety violations or miscellaneous.
                 Err(err) => {
-                    self.err_ctxt().report_selection_error(
-                        obligation.clone(),
-                        &obligation,
-                        &err,
-                        false,
-                    );
+                    self.err_ctxt().report_selection_error(obligation.clone(), &obligation, &err);
                     // Treat this like an obligation and follow through
                     // with the unsizing - the lack of a coercion should
                     // be silent, as it causes a type mismatch later.
@@ -1043,7 +1039,7 @@ pub fn can_coerce(&self, expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> bool {
             let Ok(ok) = coerce.coerce(source, target) else {
                 return false;
             };
-            let mut fcx = traits::FulfillmentContext::new_in_snapshot();
+            let mut fcx = <dyn TraitEngine<'tcx>>::new_in_snapshot(self.tcx);
             fcx.register_predicate_obligations(self, ok.obligations);
             fcx.select_where_possible(&self).is_empty()
         })
@@ -1644,9 +1640,9 @@ pub(crate) fn coerce_inner<'a>(
                 if visitor.ret_exprs.len() > 0 && let Some(expr) = expression {
                     self.note_unreachable_loop_return(&mut err, &expr, &visitor.ret_exprs);
                 }
-                err.emit_unless(unsized_return);
+                let reported = err.emit_unless(unsized_return);
 
-                self.final_ty = Some(fcx.tcx.ty_error());
+                self.final_ty = Some(fcx.tcx.ty_error_with_guaranteed(reported));
             }
         }
     }
index 16febfc46da902ae3333a2bce5ab8add720ac206..9ca7730daa68d3ee71d2b7db1b03a951841c4be1 100644 (file)
@@ -30,6 +30,10 @@ pub fn emit_coerce_suggestions(
         expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
         error: Option<TypeError<'tcx>>,
     ) {
+        if expr_ty == expected {
+            return;
+        }
+
         self.annotate_expected_due_to_let_ty(err, expr, error);
 
         // Use `||` to give these suggestions a precedence
@@ -42,7 +46,9 @@ pub fn emit_coerce_suggestions(
             || self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty)
             || self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected)
             || self.suggest_copied_or_cloned(err, expr, expr_ty, expected)
-            || self.suggest_into(err, expr, expr_ty, expected);
+            || self.suggest_into(err, expr, expr_ty, expected)
+            || self.suggest_option_to_bool(err, expr, expr_ty, expected)
+            || self.suggest_floating_point_literal(err, expr, expected);
 
         self.note_type_is_not_clone(err, expected, expr_ty, expr);
         self.note_need_for_fn_pointer(err, expected, expr_ty);
index cfb408396da05e4d0e55b42ce4b7a3981559e82d..afac6e7d94a8116ca0ef9916c61c569d1f24dbfb 100644 (file)
@@ -125,3 +125,11 @@ pub struct AddMissingParenthesesInRange {
     #[suggestion_part(code = ")")]
     pub right: Span,
 }
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_op_trait_generic_params)]
+pub struct OpMethodGenericParams {
+    #[primary_span]
+    pub span: Span,
+    pub method_name: String,
+}
index 682dbab56bc15b0c63d91c21c415327fdb369308..e948d832e3280997fd134daf86d38b42712ce606 100644 (file)
@@ -80,14 +80,14 @@ fn check_expr_meets_expectation_or_error(
         // coercions from ! to `expected`.
         if ty.is_never() {
             if let Some(adjustments) = self.typeck_results.borrow().adjustments().get(expr.hir_id) {
-                self.tcx().sess.delay_span_bug(
+                let reported = self.tcx().sess.delay_span_bug(
                     expr.span,
                     "expression with never type wound up being adjusted",
                 );
                 return if let [Adjustment { kind: Adjust::NeverToAny, target }] = &adjustments[..] {
                     target.to_owned()
                 } else {
-                    self.tcx().ty_error()
+                    self.tcx().ty_error_with_guaranteed(reported)
                 };
             }
 
@@ -103,8 +103,16 @@ fn check_expr_meets_expectation_or_error(
         }
 
         if let Some(mut err) = self.demand_suptype_diag(expr.span, expected_ty, ty) {
-            let expr = expr.peel_drop_temps();
-            self.suggest_deref_ref_or_into(&mut err, expr, expected_ty, ty, None);
+            // FIXME(compiler-errors): We probably should fold some of the
+            // `suggest_` functions from  `emit_coerce_suggestions` into here,
+            // since some of those aren't necessarily just coerce suggestions.
+            let _ = self.suggest_deref_ref_or_into(
+                &mut err,
+                expr.peel_drop_temps(),
+                expected_ty,
+                ty,
+                None,
+            ) || self.suggest_option_to_bool(&mut err, expr, ty, expected_ty);
             extend_err(&mut err);
             err.emit();
         }
@@ -396,8 +404,7 @@ fn check_expr_unary(
                         {
                             err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
                         }
-                        err.emit();
-                        oprnd_t = tcx.ty_error();
+                        oprnd_t = tcx.ty_error_with_guaranteed(err.emit());
                     }
                 }
                 hir::UnOp::Not => {
@@ -843,7 +850,7 @@ pub(super) fn check_return_expr(
         {
             // Point any obligations that were registered due to opaque type
             // inference at the return expression.
-            self.select_obligations_where_possible(false, |errors| {
+            self.select_obligations_where_possible(|errors| {
                 self.point_at_return_for_opaque_ty_error(errors, span, return_expr_ty);
             });
         }
@@ -1097,12 +1104,8 @@ fn check_expr_assign(
 
             // If the assignment expression itself is ill-formed, don't
             // bother emitting another error
-            if lhs_ty.references_error() || rhs_ty.references_error() {
-                err.delay_as_bug()
-            } else {
-                err.emit();
-            }
-            return self.tcx.ty_error();
+            let reported = err.emit_unless(lhs_ty.references_error() || rhs_ty.references_error());
+            return self.tcx.ty_error_with_guaranteed(reported);
         }
 
         let lhs_ty = self.check_expr_with_needs(&lhs, Needs::MutPlace);
@@ -2738,7 +2741,7 @@ fn check_expr_index(
                 Some((index_ty, element_ty)) => {
                     // two-phase not needed because index_ty is never mutable
                     self.demand_coerce(idx, idx_t, index_ty, None, AllowTwoPhase::No);
-                    self.select_obligations_where_possible(false, |errors| {
+                    self.select_obligations_where_possible(|errors| {
                         self.point_at_index_if_possible(errors, idx.span)
                     });
                     element_ty
@@ -2777,8 +2780,8 @@ fn check_expr_index(
                             );
                         }
                     }
-                    err.emit();
-                    self.tcx.ty_error()
+                    let reported = err.emit();
+                    self.tcx.ty_error_with_guaranteed(reported)
                 }
             }
         }
index 747ecb036b2a15c7e3bb5183d03850eb6f3fa5a6..5d44092a5f68e33c440e652e24608bf9745ba161 100644 (file)
@@ -7,16 +7,16 @@
 use rustc_middle::ty::{self, Ty};
 
 impl<'tcx> FnCtxt<'_, 'tcx> {
-    /// Performs type inference fallback, returning true if any fallback
-    /// occurs.
-    pub(super) fn type_inference_fallback(&self) -> bool {
+    /// Performs type inference fallback, setting `FnCtxt::fallback_has_occurred`
+    /// if fallback has occurred.
+    pub(super) fn type_inference_fallback(&self) {
         debug!(
             "type-inference-fallback start obligations: {:#?}",
             self.fulfillment_cx.borrow_mut().pending_obligations()
         );
 
         // All type checking constraints were added, try to fallback unsolved variables.
-        self.select_obligations_where_possible(false, |_| {});
+        self.select_obligations_where_possible(|_| {});
 
         debug!(
             "type-inference-fallback post selection obligations: {:#?}",
@@ -26,18 +26,17 @@ pub(super) fn type_inference_fallback(&self) -> bool {
         // Check if we have any unsolved variables. If not, no need for fallback.
         let unsolved_variables = self.unsolved_variables();
         if unsolved_variables.is_empty() {
-            return false;
+            return;
         }
 
         let diverging_fallback = self.calculate_diverging_fallback(&unsolved_variables);
 
-        let mut fallback_has_occurred = false;
         // We do fallback in two passes, to try to generate
         // better error messages.
         // The first time, we do *not* replace opaque types.
         for ty in unsolved_variables {
             debug!("unsolved_variable = {:?}", ty);
-            fallback_has_occurred |= self.fallback_if_possible(ty, &diverging_fallback);
+            self.fallback_if_possible(ty, &diverging_fallback);
         }
 
         // We now see if we can make progress. This might cause us to
@@ -63,9 +62,7 @@ pub(super) fn type_inference_fallback(&self) -> bool {
         // If we had tried to fallback the opaque inference variable to `MyType`,
         // we will generate a confusing type-check error that does not explicitly
         // refer to opaque types.
-        self.select_obligations_where_possible(fallback_has_occurred, |_| {});
-
-        fallback_has_occurred
+        self.select_obligations_where_possible(|_| {});
     }
 
     // Tries to apply a fallback to `ty` if it is an unsolved variable.
@@ -81,12 +78,13 @@ pub(super) fn type_inference_fallback(&self) -> bool {
     // Fallback becomes very dubious if we have encountered
     // type-checking errors.  In that case, fallback to Error.
     //
-    // The return value indicates whether fallback has occurred.
+    // Sets `FnCtxt::fallback_has_occurred` if fallback is performed
+    // during this call.
     fn fallback_if_possible(
         &self,
         ty: Ty<'tcx>,
         diverging_fallback: &FxHashMap<Ty<'tcx>, Ty<'tcx>>,
-    ) -> bool {
+    ) {
         // Careful: we do NOT shallow-resolve `ty`. We know that `ty`
         // is an unsolved variable, and we determine its fallback
         // based solely on how it was created, not what other type
@@ -111,7 +109,7 @@ fn fallback_if_possible(
             ty::Infer(ty::FloatVar(_)) => self.tcx.types.f64,
             _ => match diverging_fallback.get(&ty) {
                 Some(&fallback_ty) => fallback_ty,
-                None => return false,
+                None => return,
             },
         };
         debug!("fallback_if_possible(ty={:?}): defaulting to `{:?}`", ty, fallback);
@@ -122,7 +120,7 @@ fn fallback_if_possible(
             .map(|origin| origin.span)
             .unwrap_or(rustc_span::DUMMY_SP);
         self.demand_eqtype(span, ty, fallback);
-        true
+        self.fallback_has_occurred.set(true);
     }
 
     /// The "diverging fallback" system is rather complicated. This is
index 7563c543d3f19d55adc0e4a417115638ac7a7101..c6bd771fad2568e4b8578316c80013836f845e38 100644 (file)
@@ -18,6 +18,7 @@
 use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
 use rustc_infer::infer::{InferOk, InferResult};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
+use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::visit::TypeVisitable;
 use rustc_middle::ty::{
@@ -32,9 +33,7 @@
 use rustc_span::{Span, DUMMY_SP};
 use rustc_trait_selection::infer::InferCtxtExt as _;
 use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
-use rustc_trait_selection::traits::{
-    self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt,
-};
+use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, ObligationCtxt};
 
 use std::collections::hash_map::Entry;
 use std::slice;
@@ -106,7 +105,7 @@ pub(in super::super) fn resolve_vars_with_obligations_and_mutate_fulfillment(
         // possible. This can help substantially when there are
         // indirect dependencies that don't seem worth tracking
         // precisely.
-        self.select_obligations_where_possible(false, mutate_fulfillment_errors);
+        self.select_obligations_where_possible(mutate_fulfillment_errors);
         self.resolve_vars_if_possible(ty)
     }
 
@@ -600,7 +599,7 @@ pub(in super::super) fn resolve_rvalue_scopes(&self, def_id: DefId) {
     pub(in super::super) fn resolve_generator_interiors(&self, def_id: DefId) {
         let mut generators = self.deferred_generator_interiors.borrow_mut();
         for (body_id, interior, kind) in generators.drain(..) {
-            self.select_obligations_where_possible(false, |_| {});
+            self.select_obligations_where_possible(|_| {});
             crate::generator_interior::resolve_interior(self, def_id, body_id, interior, kind);
         }
     }
@@ -611,25 +610,20 @@ pub(in super::super) fn select_all_obligations_or_error(&self) {
 
         if !errors.is_empty() {
             self.adjust_fulfillment_errors_for_expr_obligation(&mut errors);
-            self.err_ctxt().report_fulfillment_errors(&errors, self.inh.body_id, false);
+            self.err_ctxt().report_fulfillment_errors(&errors, self.inh.body_id);
         }
     }
 
     /// Select as many obligations as we can at present.
     pub(in super::super) fn select_obligations_where_possible(
         &self,
-        fallback_has_occurred: bool,
         mutate_fulfillment_errors: impl Fn(&mut Vec<traits::FulfillmentError<'tcx>>),
     ) {
         let mut result = self.fulfillment_cx.borrow_mut().select_where_possible(self);
         if !result.is_empty() {
             mutate_fulfillment_errors(&mut result);
             self.adjust_fulfillment_errors_for_expr_obligation(&mut result);
-            self.err_ctxt().report_fulfillment_errors(
-                &result,
-                self.inh.body_id,
-                fallback_has_occurred,
-            );
+            self.err_ctxt().report_fulfillment_errors(&result, self.inh.body_id);
         }
     }
 
@@ -771,34 +765,16 @@ pub(in super::super) fn expected_inputs_for_expected_output(
 
         let expect_args = self
             .fudge_inference_if_ok(|| {
+                let ocx = ObligationCtxt::new_in_snapshot(self);
+
                 // Attempt to apply a subtyping relationship between the formal
                 // return type (likely containing type variables if the function
                 // is polymorphic) and the expected return type.
                 // No argument expectations are produced if unification fails.
                 let origin = self.misc(call_span);
-                let ures = self.at(&origin, self.param_env).sup(ret_ty, formal_ret);
-
-                // FIXME(#27336) can't use ? here, Try::from_error doesn't default
-                // to identity so the resulting type is not constrained.
-                match ures {
-                    Ok(ok) => {
-                        // Process any obligations locally as much as
-                        // we can.  We don't care if some things turn
-                        // out unconstrained or ambiguous, as we're
-                        // just trying to get hints here.
-                        let errors = self.save_and_restore_in_snapshot_flag(|_| {
-                            let mut fulfill = <dyn TraitEngine<'_>>::new(self.tcx);
-                            for obligation in ok.obligations {
-                                fulfill.register_predicate_obligation(self, obligation);
-                            }
-                            fulfill.select_where_possible(self)
-                        });
-
-                        if !errors.is_empty() {
-                            return Err(());
-                        }
-                    }
-                    Err(_) => return Err(()),
+                ocx.sup(&origin, self.param_env, ret_ty, formal_ret)?;
+                if !ocx.select_where_possible().is_empty() {
+                    return Err(TypeError::Mismatch);
                 }
 
                 // Record all the argument types, with the substitutions
@@ -1217,9 +1193,8 @@ pub fn instantiate_value_path(
                             }
                         }
                     }
-                    err.emit();
-
-                    return (tcx.ty_error(), res);
+                    let reported = err.emit();
+                    return (tcx.ty_error_with_guaranteed(reported), res);
                 }
             }
         } else {
index 4066cca8a4bd4aa46c61821c85c437670bd48eeb..8cf70eb5431a8c4ec2d6fd1a11455ffb4d771158 100644 (file)
@@ -345,7 +345,7 @@ pub(in super::super) fn check_argument_types(
             // an "opportunistic" trait resolution of any trait bounds on
             // the call. This helps coercions.
             if check_closures {
-                self.select_obligations_where_possible(false, |_| {})
+                self.select_obligations_where_possible(|_| {})
             }
 
             // Check each argument, to satisfy the input it was provided for
@@ -597,6 +597,18 @@ fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool {
             }
         };
 
+        let mk_trace = |span, (formal_ty, expected_ty), provided_ty| {
+            let mismatched_ty = if expected_ty == provided_ty {
+                // If expected == provided, then we must have failed to sup
+                // the formal type. Avoid printing out "expected Ty, found Ty"
+                // in that case.
+                formal_ty
+            } else {
+                expected_ty
+            };
+            TypeTrace::types(&self.misc(span), true, mismatched_ty, provided_ty)
+        };
+
         // The algorithm here is inspired by levenshtein distance and longest common subsequence.
         // We'll try to detect 4 different types of mistakes:
         // - An extra parameter has been provided that doesn't satisfy *any* of the other inputs
@@ -661,10 +673,9 @@ fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool {
                         // A tuple wrap suggestion actually occurs within,
                         // so don't do anything special here.
                         err = self.err_ctxt().report_and_explain_type_error(
-                            TypeTrace::types(
-                                &self.misc(*lo),
-                                true,
-                                formal_and_expected_inputs[mismatch_idx.into()].1,
+                            mk_trace(
+                                *lo,
+                                formal_and_expected_inputs[mismatch_idx.into()],
                                 provided_arg_tys[mismatch_idx.into()].0,
                             ),
                             terr,
@@ -748,9 +759,7 @@ fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool {
         errors.drain_filter(|error| {
                 let Error::Invalid(provided_idx, expected_idx, Compatibility::Incompatible(Some(e))) = error else { return false };
                 let (provided_ty, provided_span) = provided_arg_tys[*provided_idx];
-                let (expected_ty, _) = formal_and_expected_inputs[*expected_idx];
-                let cause = &self.misc(provided_span);
-                let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
+                let trace = mk_trace(provided_span, formal_and_expected_inputs[*expected_idx], provided_ty);
                 if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308(_)) {
                     self.err_ctxt().report_and_explain_type_error(trace, *e).emit();
                     return true;
@@ -774,8 +783,7 @@ fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool {
         {
             let (formal_ty, expected_ty) = formal_and_expected_inputs[*expected_idx];
             let (provided_ty, provided_arg_span) = provided_arg_tys[*provided_idx];
-            let cause = &self.misc(provided_arg_span);
-            let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
+            let trace = mk_trace(provided_arg_span, (formal_ty, expected_ty), provided_ty);
             let mut err = self.err_ctxt().report_and_explain_type_error(trace, *err);
             self.emit_coerce_suggestions(
                 &mut err,
@@ -847,8 +855,7 @@ enum SuggestionText {
                     let (formal_ty, expected_ty) = formal_and_expected_inputs[expected_idx];
                     let (provided_ty, provided_span) = provided_arg_tys[provided_idx];
                     if let Compatibility::Incompatible(error) = compatibility {
-                        let cause = &self.misc(provided_span);
-                        let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
+                        let trace = mk_trace(provided_span, (formal_ty, expected_ty), provided_ty);
                         if let Some(e) = error {
                             self.err_ctxt().note_type_err(
                                 &mut err,
index 72388baa261eae30def6f8dc8d449343b814c6ad..d5e4b6de581c3551a2af1020a282790f0807f431 100644 (file)
@@ -68,10 +68,6 @@ pub struct FnCtxt<'a, 'tcx> {
     /// any).
     pub(super) ret_coercion: Option<RefCell<DynamicCoerceMany<'tcx>>>,
 
-    /// Used exclusively to reduce cost of advanced evaluation used for
-    /// more helpful diagnostics.
-    pub(super) in_tail_expr: bool,
-
     /// First span of a return site that we find. Used in error messages.
     pub(super) ret_coercion_span: Cell<Option<Span>>,
 
@@ -115,6 +111,8 @@ pub struct FnCtxt<'a, 'tcx> {
     pub(super) enclosing_breakables: RefCell<EnclosingBreakables<'tcx>>,
 
     pub(super) inh: &'a Inherited<'tcx>,
+
+    pub(super) fallback_has_occurred: Cell<bool>,
 }
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -128,7 +126,6 @@ pub fn new(
             param_env,
             err_count_on_creation: inh.tcx.sess.err_count(),
             ret_coercion: None,
-            in_tail_expr: false,
             ret_coercion_span: Cell::new(None),
             resume_yield_tys: None,
             ps: Cell::new(UnsafetyState::function(hir::Unsafety::Normal, hir::CRATE_HIR_ID)),
@@ -138,6 +135,7 @@ pub fn new(
                 by_id: Default::default(),
             }),
             inh,
+            fallback_has_occurred: Cell::new(false),
         }
     }
 
@@ -159,7 +157,11 @@ pub fn sess(&self) -> &Session {
     ///
     /// [`InferCtxt::err_ctxt`]: infer::InferCtxt::err_ctxt
     pub fn err_ctxt(&'a self) -> TypeErrCtxt<'a, 'tcx> {
-        TypeErrCtxt { infcx: &self.infcx, typeck_results: Some(self.typeck_results.borrow()) }
+        TypeErrCtxt {
+            infcx: &self.infcx,
+            typeck_results: Some(self.typeck_results.borrow()),
+            fallback_has_occurred: self.fallback_has_occurred.get(),
+        }
     }
 
     pub fn errors_reported_since_creation(&self) -> bool {
index e3b3fb499b16ab888026d0f72ba480bc5003e7f4..06e6e4350fcbcb9271aac6bb5b8a850692a211b6 100644 (file)
@@ -13,7 +13,7 @@
 use rustc_infer::infer::{self, TyCtxtInferExt};
 use rustc_infer::traits::{self, StatementAsExpression};
 use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::{self, Binder, IsSuggestable, ToPredicate, Ty};
+use rustc_middle::ty::{self, Binder, DefIdTree, IsSuggestable, ToPredicate, Ty};
 use rustc_session::errors::ExprParenthesesNeeded;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
@@ -374,7 +374,7 @@ pub fn suggest_deref_ref_or_into(
                                 let annotation_span = ty.span;
                                 err.span_suggestion(
                                     annotation_span.with_hi(annotation_span.lo()),
-                                    format!("alternatively, consider changing the type annotation"),
+                                    "alternatively, consider changing the type annotation",
                                     suggest_annotation,
                                     Applicability::MaybeIncorrect,
                                 );
@@ -1116,6 +1116,53 @@ pub(crate) fn suggest_into(
         false
     }
 
+    /// When expecting a `bool` and finding an `Option`, suggests using `let Some(..)` or `.is_some()`
+    pub(crate) fn suggest_option_to_bool(
+        &self,
+        diag: &mut Diagnostic,
+        expr: &hir::Expr<'_>,
+        expr_ty: Ty<'tcx>,
+        expected_ty: Ty<'tcx>,
+    ) -> bool {
+        if !expected_ty.is_bool() {
+            return false;
+        }
+
+        let ty::Adt(def, _) = expr_ty.peel_refs().kind() else { return false; };
+        if !self.tcx.is_diagnostic_item(sym::Option, def.did()) {
+            return false;
+        }
+
+        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();
+        // Don't suggest:
+        //     `let Some(_) = a.is_some() && b`
+        //                     ++++++++++
+        // since the user probably just misunderstood how `let else`
+        // and `&&` work together.
+        if let Some((_, hir::Node::Local(local))) = cond_parent
+            && let hir::PatKind::Path(qpath) | hir::PatKind::TupleStruct(qpath, _, _) = &local.pat.kind
+            && let hir::QPath::Resolved(None, path) = qpath
+            && let Some(did) = path.res.opt_def_id()
+                .and_then(|did| self.tcx.opt_parent(did))
+                .and_then(|did| self.tcx.opt_parent(did))
+            && self.tcx.is_diagnostic_item(sym::Option, did)
+        {
+            return false;
+        }
+
+        diag.span_suggestion(
+            expr.span.shrink_to_hi(),
+            "use `Option::is_some` to test if the `Option` has a value",
+            ".is_some()",
+            Applicability::MachineApplicable,
+        );
+
+        true
+    }
+
     /// Suggest wrapping the block in square brackets instead of curly braces
     /// in case the block was mistaken array syntax, e.g. `{ 1 }` -> `[ 1 ]`.
     pub(crate) fn suggest_block_to_brackets(
@@ -1157,6 +1204,48 @@ pub(crate) fn suggest_block_to_brackets(
         }
     }
 
+    #[instrument(skip(self, err))]
+    pub(crate) fn suggest_floating_point_literal(
+        &self,
+        err: &mut Diagnostic,
+        expr: &hir::Expr<'_>,
+        expected_ty: Ty<'tcx>,
+    ) -> bool {
+        if !expected_ty.is_floating_point() {
+            return false;
+        }
+        match expr.kind {
+            ExprKind::Struct(QPath::LangItem(LangItem::Range, ..), [start, end], _) => {
+                err.span_suggestion_verbose(
+                    start.span.shrink_to_hi().with_hi(end.span.lo()),
+                    "remove the unnecessary `.` operator for a floating point literal",
+                    '.',
+                    Applicability::MaybeIncorrect,
+                );
+                true
+            }
+            ExprKind::Struct(QPath::LangItem(LangItem::RangeFrom, ..), [start], _) => {
+                err.span_suggestion_verbose(
+                    expr.span.with_lo(start.span.hi()),
+                    "remove the unnecessary `.` operator for a floating point literal",
+                    '.',
+                    Applicability::MaybeIncorrect,
+                );
+                true
+            }
+            ExprKind::Struct(QPath::LangItem(LangItem::RangeTo, ..), [end], _) => {
+                err.span_suggestion_verbose(
+                    expr.span.until(end.span),
+                    "remove the unnecessary `.` operator and add an integer part for a floating point literal",
+                    "0.",
+                    Applicability::MaybeIncorrect,
+                );
+                true
+            }
+            _ => false,
+        }
+    }
+
     fn is_loop(&self, id: hir::HirId) -> bool {
         let node = self.tcx.hir().get(id);
         matches!(node, Node::Expr(Expr { kind: ExprKind::Loop(..), .. }))
index b7dd599cd432183b00f9a1233afd83a6bdd03783..7bbfb70f2c3a320021cf1c3b4f104fb75f01c527 100644 (file)
 use rustc_hir::hir_id::HirIdSet;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind};
+use rustc_infer::infer::RegionVariableOrigin;
 use rustc_middle::middle::region::{self, Scope, ScopeData, YieldData};
-use rustc_middle::ty::{self, RvalueScopes, Ty, TyCtxt, TypeVisitable};
+use rustc_middle::ty::fold::FnMutDelegate;
+use rustc_middle::ty::{self, BoundVariableKind, RvalueScopes, Ty, TyCtxt, TypeVisitable};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
+use smallvec::{smallvec, SmallVec};
 
 mod drop_ranges;
 
@@ -211,31 +214,57 @@ pub fn resolve_interior<'a, 'tcx>(
 
     debug!("types in generator {:?}, span = {:?}", types, body.value.span);
 
-    let mut counter = 0;
+    // We want to deduplicate if the lifetimes are the same modulo some non-informative counter.
+    // So, we need to actually do two passes: first by type to anonymize (preserving information
+    // required for diagnostics), then a second pass over all captured types to reassign disjoint
+    // region indices.
     let mut captured_tys = FxHashSet::default();
     let type_causes: Vec<_> = types
         .into_iter()
         .filter_map(|mut cause| {
-            // Erase regions and canonicalize late-bound regions to deduplicate as many types as we
-            // can.
+            // Replace all regions inside the generator interior with late bound regions.
+            // Note that each region slot in the types gets a new fresh late bound region,
+            // which means that none of the regions inside relate to any other, even if
+            // typeck had previously found constraints that would cause them to be related.
+
+            let mut counter = 0;
+            let mut mk_bound_region = |span| {
+                let kind = ty::BrAnon(counter, span);
+                let var = ty::BoundVar::from_u32(counter);
+                counter += 1;
+                ty::BoundRegion { var, kind }
+            };
             let ty = fcx.normalize_associated_types_in(cause.span, cause.ty);
-            let erased = fcx.tcx.erase_regions(ty);
-            if captured_tys.insert(erased) {
-                // Replace all regions inside the generator interior with late bound regions.
-                // Note that each region slot in the types gets a new fresh late bound region,
-                // which means that none of the regions inside relate to any other, even if
-                // typeck had previously found constraints that would cause them to be related.
-                let folded = fcx.tcx.fold_regions(erased, |_, current_depth| {
-                    let br = ty::BoundRegion {
-                        var: ty::BoundVar::from_u32(counter),
-                        kind: ty::BrAnon(counter),
-                    };
-                    let r = fcx.tcx.mk_region(ty::ReLateBound(current_depth, br));
-                    counter += 1;
-                    r
-                });
-
-                cause.ty = folded;
+            let ty = fcx.tcx.fold_regions(ty, |region, current_depth| {
+                let br = match region.kind() {
+                    ty::ReVar(vid) => {
+                        let origin = fcx.region_var_origin(vid);
+                        match origin {
+                            RegionVariableOrigin::EarlyBoundRegion(span, _) => {
+                                mk_bound_region(Some(span))
+                            }
+                            _ => mk_bound_region(None),
+                        }
+                    }
+                    // FIXME: these should use `BrNamed`
+                    ty::ReEarlyBound(region) => {
+                        mk_bound_region(Some(fcx.tcx.def_span(region.def_id)))
+                    }
+                    ty::ReLateBound(_, ty::BoundRegion { kind, .. })
+                    | ty::ReFree(ty::FreeRegion { bound_region: kind, .. }) => match kind {
+                        ty::BoundRegionKind::BrAnon(_, span) => mk_bound_region(span),
+                        ty::BoundRegionKind::BrNamed(def_id, _) => {
+                            mk_bound_region(Some(fcx.tcx.def_span(def_id)))
+                        }
+                        ty::BoundRegionKind::BrEnv => mk_bound_region(None),
+                    },
+                    _ => mk_bound_region(None),
+                };
+                let r = fcx.tcx.mk_region(ty::ReLateBound(current_depth, br));
+                r
+            });
+            if captured_tys.insert(ty) {
+                cause.ty = ty;
                 Some(cause)
             } else {
                 None
@@ -243,11 +272,38 @@ pub fn resolve_interior<'a, 'tcx>(
         })
         .collect();
 
+    let mut bound_vars: SmallVec<[BoundVariableKind; 4]> = smallvec![];
+    let mut counter = 0;
+    // Optimization: If there is only one captured type, then we don't actually
+    // need to fold and reindex (since the first type doesn't change).
+    let type_causes = if captured_tys.len() > 0 {
+        // Optimization: Use `replace_escaping_bound_vars_uncached` instead of
+        // `fold_regions`, since we only have late bound regions, and it skips
+        // types without bound regions.
+        fcx.tcx.replace_escaping_bound_vars_uncached(
+            type_causes,
+            FnMutDelegate {
+                regions: &mut |br| {
+                    let kind = match br.kind {
+                        ty::BrAnon(_, span) => ty::BrAnon(counter, span),
+                        _ => br.kind,
+                    };
+                    let var = ty::BoundVar::from_usize(bound_vars.len());
+                    bound_vars.push(ty::BoundVariableKind::Region(kind));
+                    counter += 1;
+                    fcx.tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { var, kind }))
+                },
+                types: &mut |b| bug!("unexpected bound ty in binder: {b:?}"),
+                consts: &mut |b, ty| bug!("unexpected bound ct in binder: {b:?} {ty}"),
+            },
+        )
+    } else {
+        type_causes
+    };
+
     // Extract type components to build the witness type.
     let type_list = fcx.tcx.mk_type_list(type_causes.iter().map(|cause| cause.ty));
-    let bound_vars = fcx.tcx.mk_bound_variable_kinds(
-        (0..counter).map(|i| ty::BoundVariableKind::Region(ty::BrAnon(i))),
-    );
+    let bound_vars = fcx.tcx.mk_bound_variable_kinds(bound_vars.iter());
     let witness =
         fcx.tcx.mk_generator_witness(ty::Binder::bind_with_vars(type_list, bound_vars.clone()));
 
index 624443d9594c99b2af4c5c6debeba1ed6e627424..183e80f2e0840b610f47765a0972b3ab2d6f0e5f 100644 (file)
@@ -209,6 +209,7 @@ fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::T
     typeck_with_fallback(tcx, def_id, fallback)
 }
 
+#[instrument(level = "debug", skip(tcx, fallback), ret)]
 fn typeck_with_fallback<'tcx>(
     tcx: TyCtxt<'tcx>,
     def_id: LocalDefId,
@@ -316,12 +317,12 @@ fn typeck_with_fallback<'tcx>(
             fcx
         };
 
-        let fallback_has_occurred = fcx.type_inference_fallback();
+        fcx.type_inference_fallback();
 
         // Even though coercion casts provide type hints, we check casts after fallback for
         // backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
         fcx.check_casts();
-        fcx.select_obligations_where_possible(fallback_has_occurred, |_| {});
+        fcx.select_obligations_where_possible(|_| {});
 
         // Closure and generator analysis may run after fallback
         // because they don't constrain other type variables.
index be4ea99862222699c51341f1650fe94b81842cb8..d996d6ec610bae81c64789c6f9d8d676f1c309ed 100644 (file)
@@ -151,8 +151,7 @@ fn adjust_self_ty(
     ) -> Ty<'tcx> {
         // Commit the autoderefs by calling `autoderef` again, but this
         // time writing the results into the various typeck results.
-        let mut autoderef =
-            self.autoderef_overloaded_span(self.span, unadjusted_self_ty, self.call_expr.span);
+        let mut autoderef = self.autoderef(self.call_expr.span, unadjusted_self_ty);
         let Some((ty, n)) = autoderef.nth(pick.autoderefs) else {
             return self.tcx.ty_error_with_message(
                 rustc_span::DUMMY_SP,
index 2c7b3bbf31c201531459586effe51e2cfab70725..4a8b774936543698c07c7f9bba395e96792b2a0b 100644 (file)
@@ -10,6 +10,7 @@
 pub use self::suggest::SelfSource;
 pub use self::MethodError::*;
 
+use crate::errors::OpMethodGenericParams;
 use crate::{Expectation, FnCtxt};
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{Applicability, Diagnostic};
@@ -443,7 +444,13 @@ fn construct_obligation_for_trait(
         };
         let def_id = method_item.def_id;
         let generics = tcx.generics_of(def_id);
-        assert_eq!(generics.params.len(), 0);
+
+        if generics.params.len() != 0 {
+            tcx.sess.emit_fatal(OpMethodGenericParams {
+                span: tcx.def_span(method_item.def_id),
+                method_name: m_name.to_string(),
+            });
+        }
 
         debug!("lookup_in_trait_adjusted: method_item={:?}", method_item);
         let mut obligations = vec![];
index e88701685bc6d47a5451a25e7a9d7733d4506988..3fcd073f5979300fd1d50713b2f196c4c5c797ad 100644 (file)
@@ -475,10 +475,9 @@ fn method_autoderef_steps<'tcx>(
     let (ref infcx, goal, inference_vars) = tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &goal);
     let ParamEnvAnd { param_env, value: self_ty } = goal;
 
-    let mut autoderef =
-        Autoderef::new(infcx, param_env, hir::CRATE_HIR_ID, DUMMY_SP, self_ty, DUMMY_SP)
-            .include_raw_pointers()
-            .silence_errors();
+    let mut autoderef = Autoderef::new(infcx, param_env, hir::CRATE_HIR_ID, DUMMY_SP, self_ty)
+        .include_raw_pointers()
+        .silence_errors();
     let mut reached_raw_pointer = false;
     let mut steps: Vec<_> = autoderef
         .by_ref()
index 04ecd2757b427d3aa9e9cc97a2301fd5d6c5ebc7..43a5145b7e74d6bb974c9dd03d4e3b9df4b0c7fd 100644 (file)
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{ExprKind, Node, QPath};
-use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::infer::{
+    type_variable::{TypeVariableOrigin, TypeVariableOriginKind},
+    RegionVariableOrigin,
+};
+use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
 use rustc_middle::traits::util::supertraits;
 use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
 use rustc_middle::ty::print::with_crate_prefix;
-use rustc_middle::ty::{self, DefIdTree, ToPredicate, Ty, TyCtxt, TypeVisitable};
+use rustc_middle::ty::{
+    self, DefIdTree, GenericArg, GenericArgKind, ToPredicate, Ty, TyCtxt, TypeVisitable,
+};
 use rustc_middle::ty::{IsSuggestable, ToPolyTraitRef};
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::Symbol;
 use rustc_span::{lev_distance, source_map, ExpnKind, FileName, MacroKind, Span};
+use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedNote;
 use rustc_trait_selection::traits::error_reporting::on_unimplemented::TypeErrCtxtExt as _;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 use rustc_trait_selection::traits::{
-    FulfillmentError, Obligation, ObligationCause, ObligationCauseCode, OnUnimplementedNote,
+    FulfillmentError, Obligation, ObligationCause, ObligationCauseCode,
 };
 
 use std::cmp::Ordering;
@@ -279,7 +286,6 @@ pub fn report_method_error(
                 ) {
                     return None;
                 }
-
                 span = item_name.span;
 
                 // Don't show generic arguments when the method can't be found in any implementation (#81576).
@@ -392,28 +398,118 @@ pub fn report_method_error(
                     custom_span_label = true;
                 }
                 if static_candidates.len() == 1 {
-                    let ty_str =
-                        if let Some(CandidateSource::Impl(impl_did)) = static_candidates.get(0) {
-                            // When the "method" is resolved through dereferencing, we really want the
-                            // original type that has the associated function for accurate suggestions.
-                            // (#61411)
-                            let ty = tcx.at(span).type_of(*impl_did);
-                            match (&ty.peel_refs().kind(), &actual.peel_refs().kind()) {
-                                (ty::Adt(def, _), ty::Adt(def_actual, _)) if def == def_actual => {
-                                    // Use `actual` as it will have more `substs` filled in.
-                                    self.ty_to_value_string(actual.peel_refs())
+                    let mut has_unsuggestable_args = false;
+                    let ty_str = if let Some(CandidateSource::Impl(impl_did)) =
+                        static_candidates.get(0)
+                    {
+                        // When the "method" is resolved through dereferencing, we really want the
+                        // original type that has the associated function for accurate suggestions.
+                        // (#61411)
+                        let ty = tcx.at(span).type_of(*impl_did);
+                        match (&ty.peel_refs().kind(), &actual.peel_refs().kind()) {
+                            (ty::Adt(def, _), ty::Adt(def_actual, substs)) if def == def_actual => {
+                                // If there are any inferred arguments, (`{integer}`), we should replace
+                                // them with underscores to allow the compiler to infer them
+                                let infer_substs: Vec<GenericArg<'_>> = substs
+                                    .into_iter()
+                                    .map(|arg| {
+                                        if !arg.is_suggestable(tcx, true) {
+                                            has_unsuggestable_args = true;
+                                            match arg.unpack() {
+                                            GenericArgKind::Lifetime(_) => self
+                                                .next_region_var(RegionVariableOrigin::MiscVariable(
+                                                    rustc_span::DUMMY_SP,
+                                                ))
+                                                .into(),
+                                            GenericArgKind::Type(_) => self
+                                                .next_ty_var(TypeVariableOrigin {
+                                                    span: rustc_span::DUMMY_SP,
+                                                    kind: TypeVariableOriginKind::MiscVariable,
+                                                })
+                                                .into(),
+                                            GenericArgKind::Const(arg) => self
+                                                .next_const_var(
+                                                    arg.ty(),
+                                                    ConstVariableOrigin {
+                                                        span: rustc_span::DUMMY_SP,
+                                                        kind: ConstVariableOriginKind::MiscVariable,
+                                                    },
+                                                )
+                                                .into(),
+                                            }
+                                        } else {
+                                            arg
+                                        }
+                                    })
+                                    .collect::<Vec<_>>();
+
+                                tcx.value_path_str_with_substs(
+                                    def_actual.did(),
+                                    tcx.intern_substs(&infer_substs),
+                                )
+                            }
+                            _ => self.ty_to_value_string(ty.peel_refs()),
+                        }
+                    } else {
+                        self.ty_to_value_string(actual.peel_refs())
+                    };
+                    if let SelfSource::MethodCall(_) = source {
+                        let first_arg = if let Some(CandidateSource::Impl(impl_did)) = static_candidates.get(0) &&
+                            let Some(assoc) = self.associated_value(*impl_did, item_name) {
+                            let sig = self.tcx.fn_sig(assoc.def_id);
+                            if let Some(first) = sig.inputs().skip_binder().get(0) {
+                                if first.peel_refs() == rcvr_ty.peel_refs() {
+                                    None
+                                } else {
+                                    Some(if first.is_region_ptr() {
+                                        if first.is_mutable_ptr() { "&mut " } else { "&" }
+                                    } else {
+                                        ""
+                                    })
                                 }
-                                _ => self.ty_to_value_string(ty.peel_refs()),
+                            } else {
+                                None
                             }
                         } else {
-                            self.ty_to_value_string(actual.peel_refs())
+                            None
+                        };
+                        let mut applicability = Applicability::MachineApplicable;
+                        let args = if let Some((receiver, args)) = args {
+                            // The first arg is the same kind as the receiver
+                            let explicit_args = if first_arg.is_some() {
+                                std::iter::once(receiver).chain(args.iter()).collect::<Vec<_>>()
+                            } else {
+                                // There is no `Self` kind to infer the arguments from
+                                if has_unsuggestable_args {
+                                    applicability = Applicability::HasPlaceholders;
+                                }
+                                args.iter().collect()
+                            };
+                            format!(
+                                "({}{})",
+                                first_arg.unwrap_or(""),
+                                explicit_args
+                                    .iter()
+                                    .map(|arg| tcx
+                                        .sess
+                                        .source_map()
+                                        .span_to_snippet(arg.span)
+                                        .unwrap_or_else(|_| {
+                                            applicability = Applicability::HasPlaceholders;
+                                            "_".to_owned()
+                                        }))
+                                    .collect::<Vec<_>>()
+                                    .join(", "),
+                            )
+                        } else {
+                            applicability = Applicability::HasPlaceholders;
+                            "(...)".to_owned()
                         };
-                    if let SelfSource::MethodCall(expr) = source {
                         err.span_suggestion(
-                            expr.span.to(span),
+                            sugg_span,
                             "use associated function syntax instead",
-                            format!("{}::{}", ty_str, item_name),
-                            Applicability::MachineApplicable,
+                            format!("{}::{}{}", ty_str, item_name, args),
+                            applicability,
                         );
                     } else {
                         err.help(&format!("try with `{}::{}`", ty_str, item_name,));
@@ -1804,6 +1900,12 @@ fn check_for_deref_method(
                         | ty::Str
                         | ty::Projection(_)
                         | ty::Param(_) => format!("{deref_ty}"),
+                        // we need to test something like  <&[_]>::len
+                        // and Vec::function();
+                        // <&[_]>::len doesn't need an extra "<>" between
+                        // but for Adt type like Vec::function()
+                        // we would suggest <[_]>::function();
+                        _ if self.tcx.sess.source_map().span_wrapped_by_angle_bracket(ty.span)  => format!("{deref_ty}"),
                         _ => format!("<{deref_ty}>"),
                     };
                     err.span_suggestion_verbose(
@@ -1826,7 +1928,7 @@ fn check_for_deref_method(
     /// Print out the type for use in value namespace.
     fn ty_to_value_string(&self, ty: Ty<'tcx>) -> String {
         match ty.kind() {
-            ty::Adt(def, substs) => format!("{}", ty::Instance::new(def.did(), substs)),
+            ty::Adt(def, substs) => self.tcx.def_path_str_with_substs(def.did(), substs),
             _ => self.ty_to_string(ty),
         }
     }
index 8598369e884b4e4a1fccbb0fdcb4352619ea0919..38b3dd218a9719b4b28fcc41ff354c66bb50c42b 100644 (file)
@@ -529,8 +529,8 @@ fn check_overloaded_binop(
                         }
                     }
                 }
-                err.emit();
-                self.tcx.ty_error()
+                let reported = err.emit();
+                self.tcx.ty_error_with_guaranteed(reported)
             }
         };
 
@@ -772,7 +772,7 @@ fn lookup_op_method(
         match (method, trait_did) {
             (Some(ok), _) => {
                 let method = self.register_infer_ok_obligations(ok);
-                self.select_obligations_where_possible(false, |_| {});
+                self.select_obligations_where_possible(|_| {});
                 Ok(method)
             }
             (None, None) => Err(vec![]),
index ea90da4a6dc351c559418c2c00558d1e48bec526..eb10f3e2c107f8f943b9d17c30cd8238b5fc9d8f 100644 (file)
@@ -19,7 +19,6 @@
 use rustc_span::source_map::{Span, Spanned};
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::{BytePos, DUMMY_SP};
-use rustc_trait_selection::autoderef::Autoderef;
 use rustc_trait_selection::traits::{ObligationCause, Pattern};
 use ty::VariantDef;
 
@@ -1278,12 +1277,12 @@ fn check_pat_tuple(
         let element_tys = tcx.mk_type_list(element_tys_iter);
         let pat_ty = tcx.mk_ty(ty::Tuple(element_tys));
         if let Some(mut err) = self.demand_eqtype_pat_diag(span, expected, pat_ty, ti) {
-            err.emit();
+            let reported = err.emit();
             // Walk subpatterns with an expected type of `err` in this case to silence
             // further errors being emitted when using the bindings. #50333
-            let element_tys_iter = (0..max_len).map(|_| tcx.ty_error());
+            let element_tys_iter = (0..max_len).map(|_| tcx.ty_error_with_guaranteed(reported));
             for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
-                self.check_pat(elem, tcx.ty_error(), def_bm, ti);
+                self.check_pat(elem, tcx.ty_error_with_guaranteed(reported), def_bm, ti);
             }
             tcx.mk_tup(element_tys_iter)
         } else {
@@ -2132,7 +2131,7 @@ fn error_expected_array_or_slice(&self, span: Span, expected_ty: Ty<'tcx>, ti: T
             && let ty::Array(..) | ty::Slice(..) = ty.kind()
         {
             err.help("the semantics of slice patterns changed recently; see issue #62254");
-        } else if Autoderef::new(&self.infcx, self.param_env, self.body_id, span, expected_ty, span)
+        } else if self.autoderef(span, expected_ty)
             .any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..)))
             && let (Some(span), true) = (ti.span, ti.origin_expr)
             && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
index ba8cf6926f30b19e1b3800043f7316a2fa6da176..952ea14887f7bc7f279de7c1863e523c61c0195a 100644 (file)
@@ -90,8 +90,11 @@ fn negative_index(
                 Applicability::MachineApplicable,
             );
         }
-        err.emit();
-        Some((self.tcx.ty_error(), self.tcx.ty_error()))
+        let reported = err.emit();
+        Some((
+            self.tcx.ty_error_with_guaranteed(reported),
+            self.tcx.ty_error_with_guaranteed(reported),
+        ))
     }
 
     /// To type-check `base_expr[index_expr]`, we progressively autoderef
index bb04e1c49baea08c6492b1f1467424c09142029b..ec4eeb8caa27c9687b2684a29fc7a5c9736c46a0 100644 (file)
@@ -180,6 +180,18 @@ pub enum SourceKindMultiSuggestion<'a> {
     },
 }
 
+#[derive(Subdiagnostic)]
+#[suggestion(
+    infer_suggest_add_let_for_letchains,
+    style = "verbose",
+    applicability = "machine-applicable",
+    code = "let "
+)]
+pub(crate) struct SuggAddLetForLetChains {
+    #[primary_span]
+    pub span: Span,
+}
+
 impl<'a> SourceKindMultiSuggestion<'a> {
     pub fn new_fully_qualified(
         span: Span,
index 6a29d85627a8446f4060bb4c63f6456321e7abcc..7aaa5ce2f4242bd83ded5184a09162e5a0f6b855 100644 (file)
@@ -89,10 +89,13 @@ fn from_early_bound_and_free_regions<'tcx>(
                             };
                             me.span = Some(sp);
                         }
-                        ty::BrAnon(idx) => {
+                        ty::BrAnon(idx, span) => {
                             me.kind = "anon_num_here";
                             me.num_arg = idx+1;
-                            me.span = Some(tcx.def_span(scope));
+                            me.span = match span {
+                                Some(_) => span,
+                                None => Some(tcx.def_span(scope)),
+                            }
                         },
                         _ => {
                             me.kind = "defined_here_reg";
index aa44d582fd6ce7acad3bc55b07db218af1d84840..3dc0d60b1eb0fab07d2358d1cf9c2c959f5c0cbd 100644 (file)
@@ -738,7 +738,7 @@ fn canonical_var_for_region(
         r: ty::Region<'tcx>,
     ) -> ty::Region<'tcx> {
         let var = self.canonical_var(info, r.into());
-        let br = ty::BoundRegion { var, kind: ty::BrAnon(var.as_u32()) };
+        let br = ty::BoundRegion { var, kind: ty::BrAnon(var.as_u32(), None) };
         let region = ty::ReLateBound(self.binder_index, br);
         self.tcx().mk_region(region)
     }
index 9ff703e521ff666aa5b2a44d8bb0effe9b776725..22f32251f6df0bff273c0e52999c9157209dac26 100644 (file)
@@ -1,3 +1,4 @@
+// ignore-tidy-filelength
 //! Error Reporting Code for the inference engine
 //!
 //! Because of the way inference, and in particular region inference,
     StatementAsExpression,
 };
 
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use crate::errors::SuggAddLetForLetChains;
+use hir::intravisit::{walk_expr, walk_stmt};
+use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorGuaranteed, IntoDiagnosticArg};
 use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::Node;
 use rustc_middle::dep_graph::DepContext;
@@ -91,6 +95,7 @@
 pub struct TypeErrCtxt<'a, 'tcx> {
     pub infcx: &'a InferCtxt<'tcx>,
     pub typeck_results: Option<std::cell::Ref<'a, ty::TypeckResults<'tcx>>>,
+    pub fallback_has_occurred: bool,
 }
 
 impl TypeErrCtxt<'_, '_> {
@@ -206,9 +211,12 @@ fn msg_span_from_early_bound_and_free_regions<'tcx>(
                         };
                         (text, sp)
                     }
-                    ty::BrAnon(idx) => (
+                    ty::BrAnon(idx, span) => (
                         format!("the anonymous lifetime #{} defined here", idx + 1),
-                        tcx.def_span(scope)
+                        match span {
+                            Some(span) => span,
+                            None => tcx.def_span(scope)
+                        }
                     ),
                     _ => (
                         format!("the lifetime `{}` as defined here", region),
@@ -1498,9 +1506,9 @@ pub fn note_type_err(
             values = None;
         }
         struct OpaqueTypesVisitor<'tcx> {
-            types: FxHashMap<TyCategory, FxHashSet<Span>>,
-            expected: FxHashMap<TyCategory, FxHashSet<Span>>,
-            found: FxHashMap<TyCategory, FxHashSet<Span>>,
+            types: FxIndexMap<TyCategory, FxIndexSet<Span>>,
+            expected: FxIndexMap<TyCategory, FxIndexSet<Span>>,
+            found: FxIndexMap<TyCategory, FxIndexSet<Span>>,
             ignore_span: Span,
             tcx: TyCtxt<'tcx>,
         }
@@ -1538,7 +1546,7 @@ fn add_labels_for_types(
                 &self,
                 err: &mut Diagnostic,
                 target: &str,
-                types: &FxHashMap<TyCategory, FxHashSet<Span>>,
+                types: &FxIndexMap<TyCategory, FxIndexSet<Span>>,
             ) {
                 for (key, values) in types.iter() {
                     let count = values.len();
@@ -2332,6 +2340,11 @@ fn escape_literal(s: &str) -> String {
                                 }
                             }
                         }
+                        // For code `if Some(..) = expr `, the type mismatch may be expected `bool` but found `()`,
+                        // we try to suggest to add the missing `let` for `if let Some(..) = expr`
+                        (ty::Bool, ty::Tuple(list)) => if list.len() == 0 {
+                            self.suggest_let_for_letchains(&mut err, &trace.cause, span);
+                        }
                         _ => {}
                     }
                 }
@@ -2356,6 +2369,67 @@ fn escape_literal(s: &str) -> String {
         diag
     }
 
+    /// Try to find code with pattern `if Some(..) = expr`
+    /// use a `visitor` to mark the `if` which its span contains given error span,
+    /// and then try to find a assignment in the `cond` part, which span is equal with error span
+    fn suggest_let_for_letchains(
+        &self,
+        err: &mut Diagnostic,
+        cause: &ObligationCause<'_>,
+        span: Span,
+    ) {
+        let hir = self.tcx.hir();
+        let fn_hir_id = hir.get_parent_node(cause.body_id);
+        if let Some(node) = self.tcx.hir().find(fn_hir_id) &&
+            let hir::Node::Item(hir::Item {
+                    kind: hir::ItemKind::Fn(_sig, _, body_id), ..
+                }) = node {
+        let body = hir.body(*body_id);
+
+        /// Find the if expression with given span
+        struct IfVisitor {
+            pub result: bool,
+            pub found_if: bool,
+            pub err_span: Span,
+        }
+
+        impl<'v> Visitor<'v> for IfVisitor {
+            fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
+                if self.result { return; }
+                match ex.kind {
+                    hir::ExprKind::If(cond, _, _) => {
+                        self.found_if = true;
+                        walk_expr(self, cond);
+                        self.found_if = false;
+                    }
+                    _ => walk_expr(self, ex),
+                }
+            }
+
+            fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) {
+                if let hir::StmtKind::Local(hir::Local {
+                        span, pat: hir::Pat{..}, ty: None, init: Some(_), ..
+                    }) = &ex.kind
+                    && self.found_if
+                    && span.eq(&self.err_span) {
+                        self.result = true;
+                }
+                walk_stmt(self, ex);
+            }
+
+            fn visit_body(&mut self, body: &'v hir::Body<'v>) {
+                hir::intravisit::walk_body(self, body);
+            }
+        }
+
+        let mut visitor = IfVisitor { err_span: span, found_if: false, result: false };
+        visitor.visit_body(&body);
+        if visitor.result {
+                err.subdiagnostic(SuggAddLetForLetChains{span: span.shrink_to_lo()});
+            }
+        }
+    }
+
     fn emit_tuple_wrap_err(
         &self,
         err: &mut Diagnostic,
@@ -3254,7 +3328,7 @@ pub fn consider_returning_binding(
         if blk.expr.is_some() {
             return false;
         }
-        let mut shadowed = FxHashSet::default();
+        let mut shadowed = FxIndexSet::default();
         let mut candidate_idents = vec![];
         let mut find_compatible_candidates = |pat: &hir::Pat<'_>| {
             if let hir::PatKind::Binding(_, hir_id, ident, _) = &pat.kind
index c5f2a1a3f7dce687ef0f44c2bb334393edef90b9..1067ccda20ca0ea4a80c64960c7330ce895cf8e7 100644 (file)
@@ -9,7 +9,7 @@
 use crate::infer::lexical_region_resolve::RegionResolutionError;
 use crate::infer::{SubregionOrigin, TypeTrace};
 use crate::traits::ObligationCauseCode;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::{ErrorGuaranteed, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::intravisit::Visitor;
@@ -73,7 +73,7 @@ pub(super) fn try_report_mismatched_static_lifetime(&self) -> Option<ErrorGuaran
 
             // Next, let's figure out the set of trait objects with implicit static bounds
             let ty = self.tcx().type_of(*impl_def_id);
-            let mut v = super::static_impl_trait::TraitObjectVisitor(FxHashSet::default());
+            let mut v = super::static_impl_trait::TraitObjectVisitor(FxIndexSet::default());
             v.visit_ty(ty);
             let mut traits = vec![];
             for matching_def_id in v.0 {
index aaf5a7af00afaaa246e491bdc53af45ffec85163..8a0e332f9c704b4f5f958e6f59bd546c65fa629a 100644 (file)
@@ -10,6 +10,7 @@
 mod mismatched_static_lifetime;
 mod named_anon_conflict;
 mod placeholder_error;
+mod placeholder_relation;
 mod static_impl_trait;
 mod trait_impl_difference;
 mod util;
@@ -52,7 +53,9 @@ fn tcx(&self) -> TyCtxt<'tcx> {
     pub fn try_report_from_nll(&self) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
         // Due to the improved diagnostics returned by the MIR borrow checker, only a subset of
         // the nice region errors are required when running under the MIR borrow checker.
-        self.try_report_named_anon_conflict().or_else(|| self.try_report_placeholder_conflict())
+        self.try_report_named_anon_conflict()
+            .or_else(|| self.try_report_placeholder_conflict())
+            .or_else(|| self.try_report_placeholder_relation())
     }
 
     pub fn try_report(&self) -> Option<ErrorGuaranteed> {
index 76cb76d9ff4e51acbda44550d973a67966956def..3fe7c1598fc3fbbf2e6ad540f2b2e9a557387e40 100644 (file)
@@ -68,7 +68,7 @@ pub(super) fn try_report_named_anon_conflict(
         let is_impl_item = region_info.is_impl_item;
 
         match br {
-            ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(_) => {}
+            ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(..) => {}
             _ => {
                 /* not an anonymous region */
                 debug!("try_report_named_anon_conflict: not an anonymous region");
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs
new file mode 100644 (file)
index 0000000..c42240f
--- /dev/null
@@ -0,0 +1,79 @@
+use crate::infer::{
+    error_reporting::nice_region_error::NiceRegionError, RegionResolutionError, SubregionOrigin,
+};
+use rustc_data_structures::intern::Interned;
+use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
+use rustc_middle::ty::{self, RePlaceholder, Region};
+
+impl<'tcx> NiceRegionError<'_, 'tcx> {
+    /// Emitted wwhen given a `ConcreteFailure` when relating two placeholders.
+    pub(super) fn try_report_placeholder_relation(
+        &self,
+    ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
+        match &self.error {
+            Some(RegionResolutionError::ConcreteFailure(
+                SubregionOrigin::RelateRegionParamBound(span),
+                Region(Interned(RePlaceholder(ty::Placeholder { name: sub_name, .. }), _)),
+                Region(Interned(RePlaceholder(ty::Placeholder { name: sup_name, .. }), _)),
+            )) => {
+                let msg = "lifetime bound not satisfied";
+                let mut err = self.tcx().sess.struct_span_err(*span, msg);
+                let (sub_span, sub_symbol) = match sub_name {
+                    ty::BrNamed(def_id, symbol) => {
+                        (Some(self.tcx().def_span(def_id)), Some(symbol))
+                    }
+                    ty::BrAnon(_, span) => (*span, None),
+                    ty::BrEnv => (None, None),
+                };
+                let (sup_span, sup_symbol) = match sup_name {
+                    ty::BrNamed(def_id, symbol) => {
+                        (Some(self.tcx().def_span(def_id)), Some(symbol))
+                    }
+                    ty::BrAnon(_, span) => (*span, None),
+                    ty::BrEnv => (None, None),
+                };
+                match (sub_span, sup_span, sub_symbol, sup_symbol) {
+                    (Some(sub_span), Some(sup_span), Some(sub_symbol), Some(sup_symbol)) => {
+                        err.span_note(
+                            sub_span,
+                            format!("the lifetime `{sub_symbol}` defined here..."),
+                        );
+                        err.span_note(
+                            sup_span,
+                            format!("...must outlive the lifetime `{sup_symbol}` defined here"),
+                        );
+                    }
+                    (Some(sub_span), Some(sup_span), _, Some(sup_symbol)) => {
+                        err.span_note(sub_span, format!("the lifetime defined here..."));
+                        err.span_note(
+                            sup_span,
+                            format!("...must outlive the lifetime `{sup_symbol}` defined here"),
+                        );
+                    }
+                    (Some(sub_span), Some(sup_span), Some(sub_symbol), _) => {
+                        err.span_note(
+                            sub_span,
+                            format!("the lifetime `{sub_symbol}` defined here..."),
+                        );
+                        err.span_note(
+                            sup_span,
+                            format!("...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.note("this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)");
+                Some(err)
+            }
+
+            _ => None,
+        }
+    }
+}
index 9bf755d7fcdf974855b4ac88687c671cd00669e7..b4efe8da1259266507da5ddd265f1021d00d03c9 100644 (file)
@@ -4,7 +4,7 @@
 use crate::infer::lexical_region_resolve::RegionResolutionError;
 use crate::infer::{SubregionOrigin, TypeTrace};
 use crate::traits::{ObligationCauseCode, UnifyReceiverContext};
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan};
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{walk_ty, Visitor};
@@ -236,7 +236,7 @@ pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorGuaranteed> {
             // Same case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a `'static`
             // lifetime as above, but called using a fully-qualified path to the method:
             // `Foo::qux(bar)`.
-            let mut v = TraitObjectVisitor(FxHashSet::default());
+            let mut v = TraitObjectVisitor(FxIndexSet::default());
             v.visit_ty(param.param_ty);
             if let Some((ident, self_ty)) =
                 self.get_impl_ident_and_self_ty_from_trait(item_def_id, &v.0)
@@ -408,7 +408,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
     fn get_impl_ident_and_self_ty_from_trait(
         &self,
         def_id: DefId,
-        trait_objects: &FxHashSet<DefId>,
+        trait_objects: &FxIndexSet<DefId>,
     ) -> Option<(Ident, &'tcx hir::Ty<'tcx>)> {
         let tcx = self.tcx();
         match tcx.hir().get_if_local(def_id) {
@@ -490,7 +490,7 @@ fn find_impl_on_dyn_trait(
             return false;
         };
 
-        let mut v = TraitObjectVisitor(FxHashSet::default());
+        let mut v = TraitObjectVisitor(FxIndexSet::default());
         v.visit_ty(ty);
 
         // Get the `Ident` of the method being called and the corresponding `impl` (to point at
@@ -506,7 +506,7 @@ fn find_impl_on_dyn_trait(
     fn suggest_constrain_dyn_trait_in_impl(
         &self,
         err: &mut Diagnostic,
-        found_dids: &FxHashSet<DefId>,
+        found_dids: &FxIndexSet<DefId>,
         ident: Ident,
         self_ty: &hir::Ty<'_>,
     ) -> bool {
@@ -538,7 +538,7 @@ fn suggest_constrain_dyn_trait_in_impl(
 }
 
 /// Collect all the trait objects in a type that could have received an implicit `'static` lifetime.
-pub struct TraitObjectVisitor(pub FxHashSet<DefId>);
+pub struct TraitObjectVisitor(pub FxIndexSet<DefId>);
 
 impl<'tcx> TypeVisitor<'tcx> for TraitObjectVisitor {
     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
index f1461d7010d5b41aab675347de2fa296e200c7a5..fd26d7d29c5ee6ba1f13554126a8255e54323fd5 100644 (file)
@@ -149,6 +149,8 @@ fn includes_region(
         region: ty::BoundRegionKind,
     ) -> bool {
         let late_bound_regions = self.tcx().collect_referenced_late_bound_regions(&ty);
+        // We are only checking is any region meets the condition so order doesn't matter
+        #[allow(rustc::potential_query_instability)]
         late_bound_regions.iter().any(|r| *r == region)
     }
 
index 5f13b2b3deb1b6e0c7fce6f27bd78280a495238b..ba990acfe6fc4a5991bfcba2d65c7355f25a971b 100644 (file)
@@ -842,6 +842,9 @@ fn region_order_key(x: &RegionAndOrigin<'_>) -> u8 {
         // are placeholders as upper bounds, but the universe of the
         // variable `'a`, or some variable that `'a` has to outlive, doesn't
         // permit those placeholders.
+        //
+        // We only iterate to find the min, which means it doesn't cause reproducibility issues
+        #[allow(rustc::potential_query_instability)]
         let min_universe = lower_vid_bounds
             .into_iter()
             .map(|vid| self.var_infos[vid].universe)
index c2eecd9e87a384f16725433eb85bd9ddd0d97059..fd3b3e4d59fa699d7570a708814025e0519e7e3e 100644 (file)
@@ -10,6 +10,7 @@
 
 use crate::traits::{self, ObligationCause, PredicateObligations, TraitEngine, TraitEngineExt};
 
+use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::undo_log::Rollback;
@@ -294,7 +295,7 @@ pub struct InferCtxt<'tcx> {
 
     /// the set of predicates on which errors have been reported, to
     /// avoid reporting the same error twice.
-    pub reported_trait_errors: RefCell<FxHashMap<Span, Vec<ty::Predicate<'tcx>>>>,
+    pub reported_trait_errors: RefCell<FxIndexMap<Span, Vec<ty::Predicate<'tcx>>>>,
 
     pub reported_closure_mismatch: RefCell<FxHashSet<(Span, Option<Span>)>>,
 
@@ -677,9 +678,9 @@ pub struct CombinedSnapshot<'tcx> {
 
 impl<'tcx> InferCtxt<'tcx> {
     /// Creates a `TypeErrCtxt` for emitting various inference errors.
-    /// During typeck, use `FnCtxt::infer_err` instead.
+    /// During typeck, use `FnCtxt::err_ctxt` instead.
     pub fn err_ctxt(&self) -> TypeErrCtxt<'_, 'tcx> {
-        TypeErrCtxt { infcx: self, typeck_results: None }
+        TypeErrCtxt { infcx: self, typeck_results: None, fallback_has_occurred: false }
     }
 
     /// calls `tcx.try_unify_abstract_consts` after
@@ -777,32 +778,6 @@ fn combine_fields<'a>(
         }
     }
 
-    /// Clear the "currently in a snapshot" flag, invoke the closure,
-    /// then restore the flag to its original value. This flag is a
-    /// debugging measure designed to detect cases where we start a
-    /// snapshot, create type variables, and register obligations
-    /// which may involve those type variables in the fulfillment cx,
-    /// potentially leaving "dangling type variables" behind.
-    /// In such cases, an assertion will fail when attempting to
-    /// register obligations, within a snapshot. Very useful, much
-    /// better than grovelling through megabytes of `RUSTC_LOG` output.
-    ///
-    /// HOWEVER, in some cases the flag is unhelpful. In particular, we
-    /// sometimes create a "mini-fulfilment-cx" in which we enroll
-    /// obligations. As long as this fulfillment cx is fully drained
-    /// before we return, this is not a problem, as there won't be any
-    /// escaping obligations in the main cx. In those cases, you can
-    /// use this function.
-    pub fn save_and_restore_in_snapshot_flag<F, R>(&self, func: F) -> R
-    where
-        F: FnOnce(&Self) -> R,
-    {
-        let flag = self.in_snapshot.replace(false);
-        let result = func(self);
-        self.in_snapshot.set(flag);
-        result
-    }
-
     fn start_snapshot(&self) -> CombinedSnapshot<'tcx> {
         debug!("start_snapshot()");
 
index 90858e3072ac028db31427fd05cbf69889086570..22b4bbb17d47fd3e38948d6dd51e545588d39ade 100644 (file)
@@ -1,6 +1,7 @@
 use super::*;
 use crate::infer::CombinedSnapshot;
 use rustc_data_structures::{
+    fx::FxIndexMap,
     graph::{scc::Sccs, vec_graph::VecGraph},
     undo_log::UndoLogs,
 };
@@ -371,7 +372,7 @@ struct LeakCheckScc {
 /// an edge `R1 -> R2` in the graph.
 struct MiniGraph<'tcx> {
     /// Map from a region to the index of the node in the graph.
-    nodes: FxHashMap<ty::Region<'tcx>, LeakCheckNode>,
+    nodes: FxIndexMap<ty::Region<'tcx>, LeakCheckNode>,
 
     /// Map from node index to SCC, and stores the successors of each SCC. All
     /// the regions in the same SCC are equal to one another, and if `S1 -> S2`,
@@ -388,7 +389,7 @@ fn new<'a>(
     where
         'tcx: 'a,
     {
-        let mut nodes = FxHashMap::default();
+        let mut nodes = FxIndexMap::default();
         let mut edges = Vec::new();
 
         // Note that if `R2: R1`, we get a callback `r1, r2`, so `target` is first parameter.
@@ -438,7 +439,7 @@ fn iterate_undo_log<'a>(
     }
 
     fn add_node(
-        nodes: &mut FxHashMap<ty::Region<'tcx>, LeakCheckNode>,
+        nodes: &mut FxIndexMap<ty::Region<'tcx>, LeakCheckNode>,
         r: ty::Region<'tcx>,
     ) -> LeakCheckNode {
         let l = nodes.len();
index 67b3da687200e9538aff976cbf4db4af520c482e..985c5d360db8e814b4a7b9b7e69924e2ae9fabcc 100644 (file)
@@ -7,7 +7,7 @@
     InferCtxtUndoLogs, MiscVariable, RegionVariableOrigin, Rollback, Snapshot, SubregionOrigin,
 };
 
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
 use rustc_data_structures::intern::Interned;
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::undo_log::UndoLogs;
@@ -125,7 +125,7 @@ pub struct RegionConstraintData<'tcx> {
     /// we record the fact that `'a <= 'b` is implied by the fn
     /// signature, and then ignore the constraint when solving
     /// equations. This is a bit of a hack but seems to work.
-    pub givens: FxHashSet<(Region<'tcx>, ty::RegionVid)>,
+    pub givens: FxIndexSet<(Region<'tcx>, ty::RegionVid)>,
 }
 
 /// Represents a constraint that influences the inference process.
index e040634edb088da85d65e9dd86aab0dda27b22b3..4c119a443555e35fcd444cd6668fb74d028c7d44 100644 (file)
@@ -12,7 +12,6 @@
 //!
 //! This API is completely unstable and subject to change.
 
-#![allow(rustc::potential_query_instability)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(box_patterns)]
 #![feature(control_flow_enum)]
index f8b5009a58d4bf9acf2506fab24b038a39fdce76..4d53519581b3795bdc9b7bf27e9b9820011078a4 100644 (file)
@@ -1,7 +1,7 @@
 use super::ObjectSafetyViolation;
 
 use crate::infer::InferCtxt;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::{struct_span_err, DiagnosticBuilder, ErrorGuaranteed, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -56,7 +56,7 @@ pub fn report_object_safety_error<'tcx>(
     );
     err.span_label(span, format!("`{}` cannot be made into an object", trait_str));
 
-    let mut reported_violations = FxHashSet::default();
+    let mut reported_violations = FxIndexSet::default();
     let mut multi_span = vec![];
     let mut messages = vec![];
     for violation in violations {
index a41a749ee68e5f240c49bbfd129301c49f4d4ab9..542b638bbd7a40dcb5596aca193092332b93a811 100644 (file)
@@ -1,4 +1,5 @@
 #![feature(box_patterns)]
+#![feature(decl_macro)]
 #![feature(internal_output_capture)]
 #![feature(thread_spawn_unchecked)]
 #![feature(once_cell)]
index 62ee72f9883083185e691cae4e023eb319c0b25c..2fe3fb2fa5668013978287aa75086ea0d42480ce 100644 (file)
@@ -327,7 +327,7 @@ fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> M
     let mut file: Option<PathBuf> = None;
 
     let expected_names = &[
-        format!("rustc_codegen_{}-{}", backend_name, release_str().expect("CFG_RELEASE")),
+        format!("rustc_codegen_{}-{}", backend_name, env!("CFG_RELEASE")),
         format!("rustc_codegen_{}", backend_name),
     ];
     for entry in d.filter_map(|e| e.ok()) {
@@ -554,22 +554,12 @@ pub fn build_output_filenames(
     }
 }
 
-/// Returns a version string such as "1.46.0 (04488afe3 2020-08-24)"
-pub fn version_str() -> Option<&'static str> {
+/// Returns a version string such as "1.46.0 (04488afe3 2020-08-24)" when invoked by an in-tree tool.
+pub macro version_str() {
     option_env!("CFG_VERSION")
 }
 
-/// Returns a version string such as "0.12.0-dev".
-pub fn release_str() -> Option<&'static str> {
-    option_env!("CFG_RELEASE")
-}
-
-/// Returns the full SHA1 hash of HEAD of the Git repo from which rustc was built.
-pub fn commit_hash_str() -> Option<&'static str> {
-    option_env!("CFG_VER_HASH")
-}
-
-/// Returns the "commit date" of HEAD of the Git repo from which rustc was built as a static string.
-pub fn commit_date_str() -> Option<&'static str> {
-    option_env!("CFG_VER_DATE")
+/// Returns the version string for `rustc` itself (which may be different from a tool version).
+pub fn rustc_version_str() -> Option<&'static str> {
+    version_str!()
 }
index dd2c09cae02fdd83f659e1591e38429854d610a9..d4140cb295f32d6977993329036bdd654319115d 100644 (file)
@@ -205,13 +205,13 @@ pub enum RawStrError {
 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
 pub enum Base {
     /// Literal starts with "0b".
-    Binary,
+    Binary = 2,
     /// Literal starts with "0o".
-    Octal,
-    /// Literal starts with "0x".
-    Hexadecimal,
+    Octal = 8,
     /// Literal doesn't contain a prefix.
-    Decimal,
+    Decimal = 10,
+    /// Literal starts with "0x".
+    Hexadecimal = 16,
 }
 
 /// `rustc` allows files to have a shebang, e.g. "#!/usr/bin/rustrun",
index 8f64b5f5158e4222ec74ec5acddc0095cf045b99..e405013dcabf83047cb34a88c635e6d4d7ec8a28 100644 (file)
@@ -52,10 +52,8 @@ pub enum EscapeError {
 
     /// Unicode escape code in byte literal.
     UnicodeEscapeInByte,
-    /// Non-ascii character in byte literal.
+    /// Non-ascii character in byte literal, byte string literal, or raw byte string literal.
     NonAsciiCharInByte,
-    /// Non-ascii character in byte string literal.
-    NonAsciiCharInByteString,
 
     /// After a line ending with '\', the next line contains whitespace
     /// characters that are not skipped.
@@ -78,54 +76,33 @@ pub fn is_fatal(&self) -> bool {
 /// Takes a contents of a literal (without quotes) and produces a
 /// sequence of escaped characters or errors.
 /// Values are returned through invoking of the provided callback.
-pub fn unescape_literal<F>(literal_text: &str, mode: Mode, callback: &mut F)
+pub fn unescape_literal<F>(src: &str, mode: Mode, callback: &mut F)
 where
     F: FnMut(Range<usize>, Result<char, EscapeError>),
 {
     match mode {
         Mode::Char | Mode::Byte => {
-            let mut chars = literal_text.chars();
-            let result = unescape_char_or_byte(&mut chars, mode);
-            // The Chars iterator moved forward.
-            callback(0..(literal_text.len() - chars.as_str().len()), result);
+            let mut chars = src.chars();
+            let res = unescape_char_or_byte(&mut chars, mode == Mode::Byte);
+            callback(0..(src.len() - chars.as_str().len()), res);
         }
-        Mode::Str | Mode::ByteStr => unescape_str_or_byte_str(literal_text, mode, callback),
-        // NOTE: Raw strings do not perform any explicit character escaping, here we
-        // only translate CRLF to LF and produce errors on bare CR.
+        Mode::Str | Mode::ByteStr => unescape_str_or_byte_str(src, mode == Mode::ByteStr, callback),
         Mode::RawStr | Mode::RawByteStr => {
-            unescape_raw_str_or_raw_byte_str(literal_text, mode, callback)
+            unescape_raw_str_or_raw_byte_str(src, mode == Mode::RawByteStr, callback)
         }
     }
 }
 
-/// Takes a contents of a byte, byte string or raw byte string (without quotes)
-/// and produces a sequence of bytes or errors.
-/// Values are returned through invoking of the provided callback.
-pub fn unescape_byte_literal<F>(literal_text: &str, mode: Mode, callback: &mut F)
-where
-    F: FnMut(Range<usize>, Result<u8, EscapeError>),
-{
-    debug_assert!(mode.is_bytes());
-    unescape_literal(literal_text, mode, &mut |range, result| {
-        callback(range, result.map(byte_from_char));
-    })
-}
-
 /// Takes a contents of a char literal (without quotes), and returns an
-/// unescaped char or an error
-pub fn unescape_char(literal_text: &str) -> Result<char, (usize, EscapeError)> {
-    let mut chars = literal_text.chars();
-    unescape_char_or_byte(&mut chars, Mode::Char)
-        .map_err(|err| (literal_text.len() - chars.as_str().len(), err))
+/// unescaped char or an error.
+pub fn unescape_char(src: &str) -> Result<char, EscapeError> {
+    unescape_char_or_byte(&mut src.chars(), false)
 }
 
 /// Takes a contents of a byte literal (without quotes), and returns an
 /// unescaped byte or an error.
-pub fn unescape_byte(literal_text: &str) -> Result<u8, (usize, EscapeError)> {
-    let mut chars = literal_text.chars();
-    unescape_char_or_byte(&mut chars, Mode::Byte)
-        .map(byte_from_char)
-        .map_err(|err| (literal_text.len() - chars.as_str().len(), err))
+pub fn unescape_byte(src: &str) -> Result<u8, EscapeError> {
+    unescape_char_or_byte(&mut src.chars(), true).map(byte_from_char)
 }
 
 /// What kind of literal do we parse.
@@ -147,7 +124,7 @@ pub fn in_double_quotes(self) -> bool {
         }
     }
 
-    pub fn is_bytes(self) -> bool {
+    pub fn is_byte(self) -> bool {
         match self {
             Mode::Byte | Mode::ByteStr | Mode::RawByteStr => true,
             Mode::Char | Mode::Str | Mode::RawStr => false,
@@ -155,12 +132,9 @@ pub fn is_bytes(self) -> bool {
     }
 }
 
-fn scan_escape(chars: &mut Chars<'_>, mode: Mode) -> Result<char, EscapeError> {
+fn scan_escape(chars: &mut Chars<'_>, is_byte: bool) -> Result<char, EscapeError> {
     // Previous character was '\\', unescape what follows.
-
-    let second_char = chars.next().ok_or(EscapeError::LoneSlash)?;
-
-    let res = match second_char {
+    let res = match chars.next().ok_or(EscapeError::LoneSlash)? {
         '"' => '"',
         'n' => '\n',
         'r' => '\r',
@@ -181,7 +155,7 @@ fn scan_escape(chars: &mut Chars<'_>, mode: Mode) -> Result<char, EscapeError> {
             let value = hi * 16 + lo;
 
             // For a non-byte literal verify that it is within ASCII range.
-            if !mode.is_bytes() && !is_ascii(value) {
+            if !is_byte && !is_ascii(value) {
                 return Err(EscapeError::OutOfRangeHexEscape);
             }
             let value = value as u8;
@@ -217,7 +191,7 @@ fn scan_escape(chars: &mut Chars<'_>, mode: Mode) -> Result<char, EscapeError> {
 
                         // Incorrect syntax has higher priority for error reporting
                         // than unallowed value for a literal.
-                        if mode.is_bytes() {
+                        if is_byte {
                             return Err(EscapeError::UnicodeEscapeInByte);
                         }
 
@@ -249,23 +223,22 @@ fn scan_escape(chars: &mut Chars<'_>, mode: Mode) -> Result<char, EscapeError> {
 }
 
 #[inline]
-fn ascii_check(first_char: char, mode: Mode) -> Result<char, EscapeError> {
-    if mode.is_bytes() && !first_char.is_ascii() {
+fn ascii_check(c: char, is_byte: bool) -> Result<char, EscapeError> {
+    if is_byte && !c.is_ascii() {
         // Byte literal can't be a non-ascii character.
         Err(EscapeError::NonAsciiCharInByte)
     } else {
-        Ok(first_char)
+        Ok(c)
     }
 }
 
-fn unescape_char_or_byte(chars: &mut Chars<'_>, mode: Mode) -> Result<char, EscapeError> {
-    debug_assert!(mode == Mode::Char || mode == Mode::Byte);
-    let first_char = chars.next().ok_or(EscapeError::ZeroChars)?;
-    let res = match first_char {
-        '\\' => scan_escape(chars, mode),
+fn unescape_char_or_byte(chars: &mut Chars<'_>, is_byte: bool) -> Result<char, EscapeError> {
+    let c = chars.next().ok_or(EscapeError::ZeroChars)?;
+    let res = match c {
+        '\\' => scan_escape(chars, is_byte),
         '\n' | '\t' | '\'' => Err(EscapeError::EscapeOnlyChar),
         '\r' => Err(EscapeError::BareCarriageReturn),
-        _ => ascii_check(first_char, mode),
+        _ => ascii_check(c, is_byte),
     }?;
     if chars.next().is_some() {
         return Err(EscapeError::MoreThanOneChar);
@@ -275,20 +248,20 @@ fn unescape_char_or_byte(chars: &mut Chars<'_>, mode: Mode) -> Result<char, Esca
 
 /// Takes a contents of a string literal (without quotes) and produces a
 /// sequence of escaped characters or errors.
-fn unescape_str_or_byte_str<F>(src: &str, mode: Mode, callback: &mut F)
+fn unescape_str_or_byte_str<F>(src: &str, is_byte: bool, callback: &mut F)
 where
     F: FnMut(Range<usize>, Result<char, EscapeError>),
 {
-    debug_assert!(mode == Mode::Str || mode == Mode::ByteStr);
-    let initial_len = src.len();
     let mut chars = src.chars();
-    while let Some(first_char) = chars.next() {
-        let start = initial_len - chars.as_str().len() - first_char.len_utf8();
 
-        let unescaped_char = match first_char {
+    // The `start` and `end` computation here is complicated because
+    // `skip_ascii_whitespace` makes us to skip over chars without counting
+    // them in the range computation.
+    while let Some(c) = chars.next() {
+        let start = src.len() - chars.as_str().len() - c.len_utf8();
+        let res = match c {
             '\\' => {
-                let second_char = chars.clone().next();
-                match second_char {
+                match chars.clone().next() {
                     Some('\n') => {
                         // Rust language specification requires us to skip whitespaces
                         // if unescaped '\' character is followed by '\n'.
@@ -297,17 +270,17 @@ fn unescape_str_or_byte_str<F>(src: &str, mode: Mode, callback: &mut F)
                         skip_ascii_whitespace(&mut chars, start, callback);
                         continue;
                     }
-                    _ => scan_escape(&mut chars, mode),
+                    _ => scan_escape(&mut chars, is_byte),
                 }
             }
             '\n' => Ok('\n'),
             '\t' => Ok('\t'),
             '"' => Err(EscapeError::EscapeOnlyChar),
             '\r' => Err(EscapeError::BareCarriageReturn),
-            _ => ascii_check(first_char, mode),
+            _ => ascii_check(c, is_byte),
         };
-        let end = initial_len - chars.as_str().len();
-        callback(start..end, unescaped_char);
+        let end = src.len() - chars.as_str().len();
+        callback(start..end, res);
     }
 
     fn skip_ascii_whitespace<F>(chars: &mut Chars<'_>, start: usize, callback: &mut F)
@@ -340,30 +313,29 @@ fn skip_ascii_whitespace<F>(chars: &mut Chars<'_>, start: usize, callback: &mut
 /// Takes a contents of a string literal (without quotes) and produces a
 /// sequence of characters or errors.
 /// NOTE: Raw strings do not perform any explicit character escaping, here we
-/// only translate CRLF to LF and produce errors on bare CR.
-fn unescape_raw_str_or_raw_byte_str<F>(literal_text: &str, mode: Mode, callback: &mut F)
+/// only produce errors on bare CR.
+fn unescape_raw_str_or_raw_byte_str<F>(src: &str, is_byte: bool, callback: &mut F)
 where
     F: FnMut(Range<usize>, Result<char, EscapeError>),
 {
-    debug_assert!(mode == Mode::RawStr || mode == Mode::RawByteStr);
-    let initial_len = literal_text.len();
-
-    let mut chars = literal_text.chars();
-    while let Some(curr) = chars.next() {
-        let start = initial_len - chars.as_str().len() - curr.len_utf8();
+    let mut chars = src.chars();
 
-        let result = match curr {
+    // The `start` and `end` computation here matches the one in
+    // `unescape_str_or_byte_str` for consistency, even though this function
+    // doesn't have to worry about skipping any chars.
+    while let Some(c) = chars.next() {
+        let start = src.len() - chars.as_str().len() - c.len_utf8();
+        let res = match c {
             '\r' => Err(EscapeError::BareCarriageReturnInRawString),
-            c if mode.is_bytes() && !c.is_ascii() => Err(EscapeError::NonAsciiCharInByteString),
-            c => Ok(c),
+            _ => ascii_check(c, is_byte),
         };
-        let end = initial_len - chars.as_str().len();
-
-        callback(start..end, result);
+        let end = src.len() - chars.as_str().len();
+        callback(start..end, res);
     }
 }
 
-fn byte_from_char(c: char) -> u8 {
+#[inline]
+pub fn byte_from_char(c: char) -> u8 {
     let res = c as u32;
     debug_assert!(res <= u8::MAX as u32, "guaranteed because of Mode::ByteStr");
     res as u8
index fa61554afde6c5d16c87b462e0ca802b15a7e0a7..c7ca8fd16ae479cf7978913e8a0ea961cde2afc1 100644 (file)
@@ -3,8 +3,7 @@
 #[test]
 fn test_unescape_char_bad() {
     fn check(literal_text: &str, expected_error: EscapeError) {
-        let actual_result = unescape_char(literal_text).map_err(|(_offset, err)| err);
-        assert_eq!(actual_result, Err(expected_error));
+        assert_eq!(unescape_char(literal_text), Err(expected_error));
     }
 
     check("", EscapeError::ZeroChars);
@@ -68,8 +67,7 @@ fn check(literal_text: &str, expected_error: EscapeError) {
 #[test]
 fn test_unescape_char_good() {
     fn check(literal_text: &str, expected_char: char) {
-        let actual_result = unescape_char(literal_text);
-        assert_eq!(actual_result, Ok(expected_char));
+        assert_eq!(unescape_char(literal_text), Ok(expected_char));
     }
 
     check("a", 'a');
@@ -149,8 +147,7 @@ fn check(literal_text: &str, expected: &str) {
 #[test]
 fn test_unescape_byte_bad() {
     fn check(literal_text: &str, expected_error: EscapeError) {
-        let actual_result = unescape_byte(literal_text).map_err(|(_offset, err)| err);
-        assert_eq!(actual_result, Err(expected_error));
+        assert_eq!(unescape_byte(literal_text), Err(expected_error));
     }
 
     check("", EscapeError::ZeroChars);
@@ -219,8 +216,7 @@ fn check(literal_text: &str, expected_error: EscapeError) {
 #[test]
 fn test_unescape_byte_good() {
     fn check(literal_text: &str, expected_byte: u8) {
-        let actual_result = unescape_byte(literal_text);
-        assert_eq!(actual_result, Ok(expected_byte));
+        assert_eq!(unescape_byte(literal_text), Ok(expected_byte));
     }
 
     check("a", b'a');
@@ -246,10 +242,10 @@ fn check(literal_text: &str, expected_byte: u8) {
 fn test_unescape_byte_str_good() {
     fn check(literal_text: &str, expected: &[u8]) {
         let mut buf = Ok(Vec::with_capacity(literal_text.len()));
-        unescape_byte_literal(literal_text, Mode::ByteStr, &mut |range, c| {
+        unescape_literal(literal_text, Mode::ByteStr, &mut |range, c| {
             if let Ok(b) = &mut buf {
                 match c {
-                    Ok(c) => b.push(c),
+                    Ok(c) => b.push(byte_from_char(c)),
                     Err(e) => buf = Err((range, e)),
                 }
             }
@@ -280,18 +276,13 @@ fn check(literal: &str, expected: &[(Range<usize>, Result<char, EscapeError>)])
 
 #[test]
 fn test_unescape_raw_byte_str() {
-    fn check(literal: &str, expected: &[(Range<usize>, Result<u8, EscapeError>)]) {
+    fn check(literal: &str, expected: &[(Range<usize>, Result<char, EscapeError>)]) {
         let mut unescaped = Vec::with_capacity(literal.len());
-        unescape_byte_literal(literal, Mode::RawByteStr, &mut |range, res| {
-            unescaped.push((range, res))
-        });
+        unescape_literal(literal, Mode::RawByteStr, &mut |range, res| unescaped.push((range, res)));
         assert_eq!(unescaped, expected);
     }
 
     check("\r", &[(0..1, Err(EscapeError::BareCarriageReturnInRawString))]);
-    check("🦀", &[(0..4, Err(EscapeError::NonAsciiCharInByteString))]);
-    check(
-        "🦀a",
-        &[(0..4, Err(EscapeError::NonAsciiCharInByteString)), (4..5, Ok(byte_from_char('a')))],
-    );
+    check("🦀", &[(0..4, Err(EscapeError::NonAsciiCharInByte))]);
+    check("🦀a", &[(0..4, Err(EscapeError::NonAsciiCharInByte)), (4..5, Ok('a'))]);
 }
index cec0003ffea78b1460f2a999be9a9c1799d6ed0f..28f6ac61c5bddbed6d2553ef552b69f244063b75 100644 (file)
@@ -579,6 +579,7 @@ pub trait LintContext: Sized {
     /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation.
     ///
     /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature
+    #[rustc_lint_diagnostics]
     fn lookup_with_diagnostics(
         &self,
         lint: &'static Lint,
@@ -882,6 +883,7 @@ fn lookup_with_diagnostics(
     /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation.
     ///
     /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature
+    #[rustc_lint_diagnostics]
     fn lookup<S: Into<MultiSpan>>(
         &self,
         lint: &'static Lint,
@@ -908,6 +910,7 @@ fn emit_spanned_lint<S: Into<MultiSpan>>(
     /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation.
     ///
     /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature
+    #[rustc_lint_diagnostics]
     fn struct_span_lint<S: Into<MultiSpan>>(
         &self,
         lint: &'static Lint,
@@ -933,6 +936,7 @@ fn emit_lint(&self, lint: &'static Lint, decorator: impl for<'a> DecorateLint<'a
     /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation.
     ///
     /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature
+    #[rustc_lint_diagnostics]
     fn lint(
         &self,
         lint: &'static Lint,
index db0a3419e6a5da4e084a6d1ce32b3b2d4de9de1c..efae2669006347a639c77c7243dddf9453d09e6c 100644 (file)
@@ -163,7 +163,7 @@ fn shallow_lint_levels_on(tcx: TyCtxt<'_>, owner: hir::OwnerId) -> ShallowLintLe
         // Otherwise, we need to visit the attributes in source code order, so we fetch HIR and do
         // a standard visit.
         // FIXME(#102522) Just iterate on attrs once that iteration order matches HIR's.
-        _ => match tcx.hir().expect_owner(owner) {
+        _ => match tcx.hir().owner(owner) {
             hir::OwnerNode::Item(item) => levels.visit_item(item),
             hir::OwnerNode::ForeignItem(item) => levels.visit_foreign_item(item),
             hir::OwnerNode::TraitItem(item) => levels.visit_trait_item(item),
@@ -1073,6 +1073,7 @@ pub fn lint_level(&self, lint: &'static Lint) -> LevelAndSource {
     /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation.
     ///
     /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature
+    #[rustc_lint_diagnostics]
     pub(crate) fn struct_lint(
         &self,
         lint: &'static Lint,
index 5288fc542d79a0b0f200f9bab547da6cbf1fa948..ebb7de70e0570303252825af7696f440e8e33c26 100644 (file)
@@ -36,6 +36,7 @@
 #![feature(let_chains)]
 #![feature(min_specialization)]
 #![feature(never_type)]
+#![feature(rustc_attrs)]
 #![recursion_limit = "256"]
 
 #[macro_use]
index 46706e498445107b8a26a065f167fb7ab5102fe9..ff0fb9bae923229ba85cd50d758aafe5eddbab02 100644 (file)
@@ -9,7 +9,7 @@
 use rustc_hir::def_id::DefId;
 use rustc_infer::traits::util::elaborate_predicates_with_span;
 use rustc_middle::ty::adjustment;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, DefIdTree, Ty};
 use rustc_span::symbol::Symbol;
 use rustc_span::symbol::{kw, sym};
 use rustc_span::{BytePos, Span};
 
 impl<'tcx> LateLintPass<'tcx> for UnusedResults {
     fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
-        let expr = match s.kind {
-            hir::StmtKind::Semi(ref expr) => &**expr,
-            _ => return,
-        };
+        let hir::StmtKind::Semi(expr) = s.kind else { return; };
 
         if let hir::ExprKind::Ret(..) = expr.kind {
             return;
         }
 
+        if let hir::ExprKind::Match(await_expr, _arms, hir::MatchSource::AwaitDesugar) = expr.kind
+            && let ty = cx.typeck_results().expr_ty(&await_expr)
+            && let ty::Opaque(future_def_id, _) = ty.kind()
+            && cx.tcx.ty_is_opaque_future(ty)
+            // FIXME: This also includes non-async fns that return `impl Future`.
+            && let async_fn_def_id = cx.tcx.parent(*future_def_id)
+            && check_must_use_def(
+                cx,
+                async_fn_def_id,
+                expr.span,
+                "output of future returned by ",
+                "",
+            )
+        {
+            // We have a bare `foo().await;` on an opaque type from an async function that was
+            // annotated with `#[must_use]`.
+            return;
+        }
+
         let ty = cx.typeck_results().expr_ty(&expr);
-        let type_permits_lack_of_use = check_must_use_ty(cx, ty, &expr, s.span, "", "", 1);
+        let type_permits_lack_of_use = check_must_use_ty(cx, ty, &expr, expr.span, "", "", 1);
 
         let mut fn_warned = false;
         let mut op_warned = false;
@@ -119,7 +135,7 @@ fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
             _ => None,
         };
         if let Some(def_id) = maybe_def_id {
-            fn_warned = check_must_use_def(cx, def_id, s.span, "return value of ", "");
+            fn_warned = check_must_use_def(cx, def_id, expr.span, "return value of ", "");
         } else if type_permits_lack_of_use {
             // We don't warn about unused unit or uninhabited types.
             // (See https://github.com/rust-lang/rust/issues/43806 for details.)
@@ -565,10 +581,24 @@ fn emit_unused_delims(
             lint.set_arg("delim", Self::DELIM_STR);
             lint.set_arg("item", msg);
             if let Some((lo, hi)) = spans {
-                let replacement = vec![
-                    (lo, if keep_space.0 { " ".into() } else { "".into() }),
-                    (hi, if keep_space.1 { " ".into() } else { "".into() }),
-                ];
+                let sm = cx.sess().source_map();
+                let lo_replace =
+                    if keep_space.0 &&
+                        let Ok(snip) = sm.span_to_prev_source(lo) && !snip.ends_with(" ") {
+                        " ".to_string()
+                        } else {
+                            "".to_string()
+                        };
+
+                let hi_replace =
+                    if keep_space.1 &&
+                        let Ok(snip) = sm.span_to_next_source(hi) && !snip.starts_with(" ") {
+                        " ".to_string()
+                        } else {
+                            "".to_string()
+                        };
+
+                let replacement = vec![(lo, lo_replace), (hi, hi_replace)];
                 lint.multipart_suggestion(
                     fluent::suggestion,
                     replacement,
@@ -765,6 +795,7 @@ fn check_unused_parens_pat(
         value: &ast::Pat,
         avoid_or: bool,
         avoid_mut: bool,
+        keep_space: (bool, bool),
     ) {
         use ast::{BindingAnnotation, PatKind};
 
@@ -789,7 +820,7 @@ fn check_unused_parens_pat(
             } else {
                 None
             };
-            self.emit_unused_delims(cx, value.span, spans, "pattern", (false, false));
+            self.emit_unused_delims(cx, value.span, spans, "pattern", keep_space);
         }
     }
 }
@@ -798,7 +829,7 @@ impl EarlyLintPass for UnusedParens {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
         match e.kind {
             ExprKind::Let(ref pat, _, _) | ExprKind::ForLoop(ref pat, ..) => {
-                self.check_unused_parens_pat(cx, pat, false, false);
+                self.check_unused_parens_pat(cx, pat, false, false, (true, true));
             }
             // We ignore parens in cases like `if (((let Some(0) = Some(1))))` because we already
             // handle a hard error for them during AST lowering in `lower_expr_mut`, but we still
@@ -842,6 +873,7 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
 
     fn check_pat(&mut self, cx: &EarlyContext<'_>, p: &ast::Pat) {
         use ast::{Mutability, PatKind::*};
+        let keep_space = (false, false);
         match &p.kind {
             // Do not lint on `(..)` as that will result in the other arms being useless.
             Paren(_)
@@ -849,33 +881,33 @@ fn check_pat(&mut self, cx: &EarlyContext<'_>, p: &ast::Pat) {
             | Wild | Rest | Lit(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) => {},
             // These are list-like patterns; parens can always be removed.
             TupleStruct(_, _, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps {
-                self.check_unused_parens_pat(cx, p, false, false);
+                self.check_unused_parens_pat(cx, p, false, false, keep_space);
             },
             Struct(_, _, fps, _) => for f in fps {
-                self.check_unused_parens_pat(cx, &f.pat, false, false);
+                self.check_unused_parens_pat(cx, &f.pat, false, false, keep_space);
             },
             // Avoid linting on `i @ (p0 | .. | pn)` and `box (p0 | .. | pn)`, #64106.
-            Ident(.., Some(p)) | Box(p) => self.check_unused_parens_pat(cx, p, true, false),
+            Ident(.., Some(p)) | Box(p) => self.check_unused_parens_pat(cx, p, true, false, keep_space),
             // Avoid linting on `&(mut x)` as `&mut x` has a different meaning, #55342.
             // Also avoid linting on `& mut? (p0 | .. | pn)`, #64106.
-            Ref(p, m) => self.check_unused_parens_pat(cx, p, true, *m == Mutability::Not),
+            Ref(p, m) => self.check_unused_parens_pat(cx, p, true, *m == Mutability::Not, keep_space),
         }
     }
 
     fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
         if let StmtKind::Local(ref local) = s.kind {
-            self.check_unused_parens_pat(cx, &local.pat, true, false);
+            self.check_unused_parens_pat(cx, &local.pat, true, false, (false, false));
         }
 
         <Self as UnusedDelimLint>::check_stmt(self, cx, s)
     }
 
     fn check_param(&mut self, cx: &EarlyContext<'_>, param: &ast::Param) {
-        self.check_unused_parens_pat(cx, &param.pat, true, false);
+        self.check_unused_parens_pat(cx, &param.pat, true, false, (false, false));
     }
 
     fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &ast::Arm) {
-        self.check_unused_parens_pat(cx, &arm.pat, false, false);
+        self.check_unused_parens_pat(cx, &arm.pat, false, false, (false, false));
     }
 
     fn check_ty(&mut self, cx: &EarlyContext<'_>, ty: &ast::Ty) {
index 28e092c1eb72c1c9205068aa388bc5d912dc0a8c..d35e4191cc0b1dfc1ae36d59caf4e74556a6997c 100644 (file)
@@ -334,7 +334,7 @@ fn main() {
         "c++"
     } else if target.contains("netbsd") && llvm_static_stdcpp.is_some() {
         // NetBSD uses a separate library when relocation is required
-        "stdc++_pic"
+        "stdc++_p"
     } else if llvm_use_libcxx.is_some() {
         "c++"
     } else {
index 0b1ededa77510fe44f43472ea9d40ef71410d063..4612f54e4b17639292af0024191668a74d41f922 100644 (file)
@@ -84,7 +84,7 @@ pub(crate) fn invalid_attr(attr: &Attribute, meta: &Meta) -> Diagnostic {
     }
 }
 
-/// Emit a error diagnostic for an invalid attribute (optionally performing additional decoration
+/// Emit an error diagnostic for an invalid attribute (optionally performing additional decoration
 /// using the `FnOnce` passed in `diag`) and return `Err(ErrorHandled)`.
 ///
 /// For methods that return a `Result<_, DiagnosticDeriveError>`:
@@ -126,7 +126,7 @@ pub(crate) fn invalid_nested_attr(attr: &Attribute, nested: &NestedMeta) -> Diag
     }
 }
 
-/// Emit a error diagnostic for an invalid nested attribute (optionally performing additional
+/// Emit an error diagnostic for an invalid nested attribute (optionally performing additional
 /// decoration using the `FnOnce` passed in `diag`) and return `Err(ErrorHandled)`.
 ///
 /// For methods that return a `Result<_, DiagnosticDeriveError>`:
index 83a4d16d7a92578a40b5d3579a6132284a36e492..14f50ae87de0639fc4c58f88dfbc5c89c6ec9e21 100644 (file)
@@ -353,6 +353,10 @@ pub fn get_generics(self, id: LocalDefId) -> Option<&'hir Generics<'hir>> {
         node.node.generics()
     }
 
+    pub fn owner(self, id: OwnerId) -> OwnerNode<'hir> {
+        self.tcx.hir_owner(id).unwrap_or_else(|| bug!("expected owner for {:?}", id)).node
+    }
+
     pub fn item(self, id: ItemId) -> &'hir Item<'hir> {
         self.tcx.hir_owner(id.owner_id).unwrap().node.expect_item()
     }
@@ -822,8 +826,11 @@ pub fn get_foreign_abi(self, hir_id: HirId) -> Abi {
         )
     }
 
-    pub fn expect_owner(self, id: OwnerId) -> OwnerNode<'hir> {
-        self.tcx.hir_owner(id).unwrap_or_else(|| bug!("expected owner for {:?}", id)).node
+    pub fn expect_owner(self, def_id: LocalDefId) -> OwnerNode<'hir> {
+        self.tcx
+            .hir_owner(OwnerId { def_id })
+            .unwrap_or_else(|| bug!("expected owner for {:?}", def_id))
+            .node
     }
 
     pub fn expect_item(self, id: LocalDefId) -> &'hir Item<'hir> {
index 8d1ed4b2a5228d4a82560676f93f400e7f7ea757..0331d764b38a1469bcdf81dc65129478167f5978 100644 (file)
@@ -336,8 +336,10 @@ pub fn make_identity(&self, tcx: TyCtxt<'tcx>) -> Self {
                         tcx.mk_ty(ty::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i).into())).into()
                     }
                     GenericArgKind::Lifetime(..) => {
-                        let br =
-                            ty::BoundRegion { var: ty::BoundVar::from_u32(i), kind: ty::BrAnon(i) };
+                        let br = ty::BoundRegion {
+                            var: ty::BoundVar::from_u32(i),
+                            kind: ty::BrAnon(i, None),
+                        };
                         tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into()
                     }
                     GenericArgKind::Const(ct) => tcx
index a58cbc3767ed658980878daebc399a2cb7a6d672..6bdf591fdd79208632a82b19e051e7976da5f446 100644 (file)
@@ -43,7 +43,6 @@
 #![feature(type_alias_impl_trait)]
 #![feature(associated_type_bounds)]
 #![feature(rustc_attrs)]
-#![cfg_attr(bootstrap, feature(half_open_range_patterns))]
 #![feature(control_flow_enum)]
 #![feature(associated_type_defaults)]
 #![feature(trusted_step)]
index ffbd6d10da6b20aaeee2c63541bd04aafa2fac88..3a91522d362298400438eb5ee0446c2f10522d7c 100644 (file)
@@ -1,12 +1,14 @@
 //! A pass that checks to make sure private fields and methods aren't used
 //! outside their scopes. This pass will also generate a set of exported items
 //! which are available for use externally when compiled as a library.
-use crate::ty::{DefIdTree, Visibility};
+use crate::ty::{DefIdTree, TyCtxt, Visibility};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_hir::def::DefKind;
 use rustc_macros::HashStable;
 use rustc_query_system::ich::StableHashingContext;
 use rustc_span::def_id::LocalDefId;
+use std::hash::Hash;
 
 /// Represents the levels of effective visibility an item can have.
 ///
@@ -74,9 +76,9 @@ pub fn from_vis(vis: Visibility) -> EffectiveVisibility {
 }
 
 /// Holds a map of effective visibilities for reachable HIR nodes.
-#[derive(Default, Clone, Debug)]
-pub struct EffectiveVisibilities {
-    map: FxHashMap<LocalDefId, EffectiveVisibility>,
+#[derive(Clone, Debug)]
+pub struct EffectiveVisibilities<Id = LocalDefId> {
+    map: FxHashMap<Id, EffectiveVisibility>,
 }
 
 impl EffectiveVisibilities {
@@ -111,12 +113,30 @@ pub fn public_at_level(&self, id: LocalDefId) -> Option<Level> {
         })
     }
 
-    pub fn effective_vis(&self, id: LocalDefId) -> Option<&EffectiveVisibility> {
-        self.map.get(&id)
-    }
-
-    pub fn iter(&self) -> impl Iterator<Item = (&LocalDefId, &EffectiveVisibility)> {
-        self.map.iter()
+    // FIXME: Share code with `fn update`.
+    pub fn update_eff_vis(
+        &mut self,
+        def_id: LocalDefId,
+        eff_vis: &EffectiveVisibility,
+        tree: impl DefIdTree,
+    ) {
+        use std::collections::hash_map::Entry;
+        match self.map.entry(def_id) {
+            Entry::Occupied(mut occupied) => {
+                let old_eff_vis = occupied.get_mut();
+                for l in Level::all_levels() {
+                    let vis_at_level = eff_vis.at_level(l);
+                    let old_vis_at_level = old_eff_vis.at_level_mut(l);
+                    if vis_at_level != old_vis_at_level
+                        && vis_at_level.is_at_least(*old_vis_at_level, tree)
+                    {
+                        *old_vis_at_level = *vis_at_level
+                    }
+                }
+                old_eff_vis
+            }
+            Entry::Vacant(vacant) => vacant.insert(*eff_vis),
+        };
     }
 
     pub fn set_public_at_level(
@@ -137,26 +157,82 @@ pub fn set_public_at_level(
         self.map.insert(id, effective_vis);
     }
 
+    pub fn check_invariants(&self, tcx: TyCtxt<'_>, early: bool) {
+        if !cfg!(debug_assertions) {
+            return;
+        }
+        for (&def_id, ev) in &self.map {
+            // More direct visibility levels can never go farther than less direct ones,
+            // neither of effective visibilities can go farther than nominal visibility,
+            // and all effective visibilities are larger or equal than private visibility.
+            let private_vis = Visibility::Restricted(tcx.parent_module_from_def_id(def_id));
+            let span = tcx.def_span(def_id.to_def_id());
+            if !ev.direct.is_at_least(private_vis, tcx) {
+                span_bug!(span, "private {:?} > direct {:?}", private_vis, ev.direct);
+            }
+            if !ev.reexported.is_at_least(ev.direct, tcx) {
+                span_bug!(span, "direct {:?} > reexported {:?}", ev.direct, ev.reexported);
+            }
+            if !ev.reachable.is_at_least(ev.reexported, tcx) {
+                span_bug!(span, "reexported {:?} > reachable {:?}", ev.reexported, ev.reachable);
+            }
+            if !ev.reachable_through_impl_trait.is_at_least(ev.reachable, tcx) {
+                span_bug!(
+                    span,
+                    "reachable {:?} > reachable_through_impl_trait {:?}",
+                    ev.reachable,
+                    ev.reachable_through_impl_trait
+                );
+            }
+            let nominal_vis = tcx.visibility(def_id);
+            let def_kind = tcx.opt_def_kind(def_id);
+            // FIXME: `rustc_privacy` is not yet updated for the new logic and can set
+            // effective visibilities that are larger than the nominal one.
+            if !nominal_vis.is_at_least(ev.reachable_through_impl_trait, tcx) && early {
+                span_bug!(
+                    span,
+                    "{:?}: reachable_through_impl_trait {:?} > nominal {:?}",
+                    def_id,
+                    ev.reachable_through_impl_trait,
+                    nominal_vis
+                );
+            }
+            // Fully private items are never put into the table, this is important for performance.
+            // FIXME: Fully private `mod` items are currently put into the table.
+            if ev.reachable_through_impl_trait == private_vis && def_kind != Some(DefKind::Mod) {
+                span_bug!(span, "fully private item in the table {:?}: {:?}", def_id, ev.direct);
+            }
+        }
+    }
+}
+
+impl<Id: Eq + Hash> EffectiveVisibilities<Id> {
+    pub fn iter(&self) -> impl Iterator<Item = (&Id, &EffectiveVisibility)> {
+        self.map.iter()
+    }
+
+    pub fn effective_vis(&self, id: Id) -> Option<&EffectiveVisibility> {
+        self.map.get(&id)
+    }
+
     // `parent_id` is not necessarily a parent in source code tree,
     // it is the node from which the maximum effective visibility is inherited.
     pub fn update(
         &mut self,
-        id: LocalDefId,
+        id: Id,
         nominal_vis: Visibility,
-        default_vis: impl FnOnce() -> Visibility,
-        parent_id: LocalDefId,
+        default_vis: Visibility,
+        inherited_eff_vis: Option<EffectiveVisibility>,
         level: Level,
         tree: impl DefIdTree,
     ) -> bool {
         let mut changed = false;
-        let mut current_effective_vis = self.effective_vis(id).copied().unwrap_or_else(|| {
-            if id.is_top_level_module() {
-                EffectiveVisibility::from_vis(Visibility::Public)
-            } else {
-                EffectiveVisibility::from_vis(default_vis())
-            }
-        });
-        if let Some(inherited_effective_vis) = self.effective_vis(parent_id) {
+        let mut current_effective_vis = self
+            .map
+            .get(&id)
+            .copied()
+            .unwrap_or_else(|| EffectiveVisibility::from_vis(default_vis));
+        if let Some(inherited_effective_vis) = inherited_eff_vis {
             let mut inherited_effective_vis_at_prev_level =
                 *inherited_effective_vis.at_level(level);
             let mut calculated_effective_vis = inherited_effective_vis_at_prev_level;
@@ -194,6 +270,12 @@ pub fn update(
     }
 }
 
+impl<Id> Default for EffectiveVisibilities<Id> {
+    fn default() -> Self {
+        EffectiveVisibilities { map: Default::default() }
+    }
+}
+
 impl<'a> HashStable<StableHashingContext<'a>> for EffectiveVisibilities {
     fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
         let EffectiveVisibilities { ref map } = *self;
index 5e3dfcbcc496221c9bd1c09abb3a7f9eda8beac4..32ec585576920948dbdd5438039f934005d315ac 100644 (file)
@@ -106,6 +106,7 @@ macro_rules! throw_machine_stop {
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::{HashMapExt, Lock};
 use rustc_data_structures::tiny_list::TinyList;
+use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def_id::DefId;
 use rustc_macros::HashStable;
 use rustc_middle::ty::print::with_no_trimmed_paths;
@@ -176,7 +177,7 @@ pub enum LitToConstError {
     /// This is used for graceful error handling (`delay_span_bug`) in
     /// type checking (`Const::from_anon_const`).
     TypeError,
-    Reported,
+    Reported(ErrorGuaranteed),
 }
 
 #[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
index 0a96d23e3543b49306b959ff04bc65fa04a54cfa..a4495d2934df3b58318a4340912357f0a1432446 100644 (file)
@@ -138,6 +138,48 @@ pub fn phase_index(&self) -> usize {
             }
         }
     }
+
+    /// Parses an `MirPhase` from a pair of strings. Panics if this isn't possible for any reason.
+    pub fn parse(dialect: String, phase: Option<String>) -> Self {
+        match &*dialect.to_ascii_lowercase() {
+            "built" => {
+                assert!(phase.is_none(), "Cannot specify a phase for `Built` MIR");
+                MirPhase::Built
+            }
+            "analysis" => Self::Analysis(AnalysisPhase::parse(phase)),
+            "runtime" => Self::Runtime(RuntimePhase::parse(phase)),
+            _ => panic!("Unknown MIR dialect {}", dialect),
+        }
+    }
+}
+
+impl AnalysisPhase {
+    pub fn parse(phase: Option<String>) -> Self {
+        let Some(phase) = phase else {
+            return Self::Initial;
+        };
+
+        match &*phase.to_ascii_lowercase() {
+            "initial" => Self::Initial,
+            "post_cleanup" | "post-cleanup" | "postcleanup" => Self::PostCleanup,
+            _ => panic!("Unknown analysis phase {}", phase),
+        }
+    }
+}
+
+impl RuntimePhase {
+    pub fn parse(phase: Option<String>) -> Self {
+        let Some(phase) = phase else {
+            return Self::Initial;
+        };
+
+        match &*phase.to_ascii_lowercase() {
+            "initial" => Self::Initial,
+            "post_cleanup" | "post-cleanup" | "postcleanup" => Self::PostCleanup,
+            "optimized" => Self::Optimized,
+            _ => panic!("Unknown runtime phase {}", phase),
+        }
+    }
 }
 
 impl Display for MirPhase {
@@ -293,6 +335,13 @@ pub struct Body<'tcx> {
     /// potentially allow things like `[u8; std::mem::size_of::<T>() * 0]` due to this.
     pub is_polymorphic: bool,
 
+    /// The phase at which this MIR should be "injected" into the compilation process.
+    ///
+    /// Everything that comes before this `MirPhase` should be skipped.
+    ///
+    /// This is only `Some` if the function that this body comes from was annotated with `rustc_custom_mir`.
+    pub injection_phase: Option<MirPhase>,
+
     pub tainted_by_errors: Option<ErrorGuaranteed>,
 }
 
@@ -339,6 +388,7 @@ pub fn new(
             span,
             required_consts: Vec::new(),
             is_polymorphic: false,
+            injection_phase: None,
             tainted_by_errors,
         };
         body.is_polymorphic = body.has_non_region_param();
@@ -366,6 +416,7 @@ pub fn new_cfg_only(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>) ->
             required_consts: Vec::new(),
             var_debug_info: Vec::new(),
             is_polymorphic: false,
+            injection_phase: None,
             tainted_by_errors: None,
         };
         body.is_polymorphic = body.has_non_region_param();
@@ -508,6 +559,14 @@ pub fn generator_drop(&self) -> Option<&Body<'tcx>> {
     pub fn generator_kind(&self) -> Option<GeneratorKind> {
         self.generator.as_ref().map(|generator| generator.generator_kind)
     }
+
+    #[inline]
+    pub fn should_skip(&self) -> bool {
+        let Some(injection_phase) = self.injection_phase else {
+            return false;
+        };
+        injection_phase > self.phase
+    }
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, Debug, TyEncodable, TyDecodable, HashStable)]
@@ -1898,6 +1957,7 @@ pub fn allows_two_phase_borrow(&self) -> bool {
         }
     }
 
+    // FIXME: won't be used after diagnostic migration
     pub fn describe_mutability(&self) -> &str {
         match *self {
             BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => "immutable",
@@ -2192,7 +2252,9 @@ pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
                 match tcx.const_eval_resolve(param_env, uneval, None) {
                     Ok(val) => Self::Val(val, ty),
                     Err(ErrorHandled::TooGeneric | ErrorHandled::Linted) => self,
-                    Err(_) => Self::Ty(tcx.const_error(ty)),
+                    Err(ErrorHandled::Reported(guar)) => {
+                        Self::Ty(tcx.const_error_with_guaranteed(ty, guar))
+                    }
                 }
             }
         }
index 00242e7eed775ff925c370f6aedcf5315e186b45..1564cf414bd251bda3ccd4f26b815986b8aa8141 100644 (file)
         desc { |tcx| "getting the native library for `{}`", tcx.def_path_str(def_id) }
     }
 
-    /// Does lifetime resolution, but does not descend into trait items. This
-    /// should only be used for resolving lifetimes of on trait definitions,
-    /// and is used to avoid cycles. Importantly, `resolve_lifetimes` still visits
-    /// the same lifetimes and is responsible for diagnostics.
-    /// See `rustc_resolve::late::lifetimes for details.
-    query resolve_lifetimes_trait_definition(_: LocalDefId) -> ResolveLifetimes {
-        arena_cache
-        desc { "resolving lifetimes for a trait definition" }
-    }
     /// Does lifetime resolution on items. Importantly, we can't resolve
     /// lifetimes directly on things like trait methods, because of trait params.
     /// See `rustc_resolve::late::lifetimes for details.
-    query resolve_lifetimes(_: LocalDefId) -> ResolveLifetimes {
+    query resolve_lifetimes(_: hir::OwnerId) -> ResolveLifetimes {
         arena_cache
         desc { "resolving lifetimes" }
     }
index a29f0722ff705056ee9535f5ad3e0a6a158b4246..05382bd887cd9e2bb92b4c706109b21953e43e9c 100644 (file)
@@ -576,9 +576,6 @@ pub enum SelectionError<'tcx> {
     /// Signaling that an error has already been emitted, to avoid
     /// multiple errors being shown.
     ErrorReporting,
-    /// Multiple applicable `impl`s where found. The `DefId`s correspond to
-    /// all the `impl`s' Items.
-    Ambiguous(Vec<DefId>),
 }
 
 /// When performing resolution, it is typically the case that there
index 33fdf1a83709465ed858e95f839111412dc37c43..e2e2761501b48c5cf0e544e9befbf8100c18d940 100644 (file)
@@ -2,7 +2,6 @@
 use crate::mir::ConstantKind;
 use crate::ty::{self, InternalSubsts, ParamEnv, ParamEnvAnd, Ty, TyCtxt};
 use rustc_data_structures::intern::Interned;
-use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_macros::HashStable;
@@ -225,7 +224,7 @@ pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Const<'tcx> {
         if let Some(val) = self.kind().try_eval_for_typeck(tcx, param_env) {
             match val {
                 Ok(val) => Const::from_value(tcx, val, self.ty()),
-                Err(ErrorGuaranteed { .. }) => tcx.const_error(self.ty()),
+                Err(guar) => tcx.const_error_with_guaranteed(self.ty(), guar),
             }
         } else {
             // Either the constant isn't evaluatable or ValTree creation failed.
@@ -240,7 +239,7 @@ pub fn eval_for_mir(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Const
         if let Some(val) = self.kind().try_eval_for_mir(tcx, param_env) {
             match val {
                 Ok(const_val) => ConstantKind::from_value(const_val, self.ty()),
-                Err(ErrorGuaranteed { .. }) => ConstantKind::Ty(tcx.const_error(self.ty())),
+                Err(guar) => ConstantKind::Ty(tcx.const_error_with_guaranteed(self.ty(), guar)),
             }
         } else {
             ConstantKind::Ty(self)
index fc706b890d5fb504ba632a8fb9f1e9e8eb7bb881..8f96f5a9eb3e99b3e8db919853a31c4c5aff0b0b 100644 (file)
@@ -198,12 +198,8 @@ fn intern_ty(
                         Fingerprint::ZERO
                     } else {
                         let mut hasher = StableHasher::new();
-                        let mut hcx = StableHashingContext::ignore_spans(
-                            sess,
-                            definitions,
-                            cstore,
-                            source_span,
-                        );
+                        let mut hcx =
+                            StableHashingContext::new(sess, definitions, cstore, source_span);
                         kind.hash_stable(&mut hcx, &mut hasher);
                         hasher.finish()
                     };
@@ -1283,6 +1279,12 @@ pub fn create_global_ctxt(
         }
     }
 
+    /// Constructs a `TyKind::Error` type with current `ErrorGuaranteed`
+    #[track_caller]
+    pub fn ty_error_with_guaranteed(self, reported: ErrorGuaranteed) -> Ty<'tcx> {
+        self.mk_ty(Error(reported))
+    }
+
     /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` to ensure it gets used.
     #[track_caller]
     pub fn ty_error(self) -> Ty<'tcx> {
@@ -1297,6 +1299,16 @@ pub fn ty_error_with_message<S: Into<MultiSpan>>(self, span: S, msg: &str) -> Ty
         self.mk_ty(Error(reported))
     }
 
+    /// Like [TyCtxt::ty_error] but for constants, with current `ErrorGuaranteed`
+    #[track_caller]
+    pub fn const_error_with_guaranteed(
+        self,
+        ty: Ty<'tcx>,
+        reported: ErrorGuaranteed,
+    ) -> Const<'tcx> {
+        self.mk_const(ty::ConstKind::Error(reported), ty)
+    }
+
     /// Like [TyCtxt::ty_error] but for constants.
     #[track_caller]
     pub fn const_error(self, ty: Ty<'tcx>) -> Const<'tcx> {
@@ -2856,6 +2868,7 @@ pub fn emit_lint(
     /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation.
     ///
     /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature
+    #[rustc_lint_diagnostics]
     pub fn struct_lint_node(
         self,
         lint: &'static Lint,
index 4e6cdb786025e0bcd8f78e2d213e7b6758487476..dc13374f992eb7589f6eb919b50024314ab5d1ba 100644 (file)
@@ -430,7 +430,9 @@ pub fn note_and_explain_type_err(
                     (ty::Projection(_), ty::Projection(_)) => {
                         diag.note("an associated type was expected, but a different one was found");
                     }
-                    (ty::Param(p), ty::Projection(proj)) | (ty::Projection(proj), ty::Param(p)) => {
+                    (ty::Param(p), ty::Projection(proj)) | (ty::Projection(proj), ty::Param(p))
+                        if self.def_kind(proj.item_def_id) != DefKind::ImplTraitPlaceholder =>
+                    {
                         let generics = self.generics_of(body_owner_def_id);
                         let p_span = self.def_span(generics.type_param(p, self).def_id);
                         if !sp.contains(p_span) {
index a329753726ef2b91a114d9e3d24a9862226e1525..2842b3c3102d24cceadc3058acb654015b0b4fc7 100644 (file)
@@ -598,7 +598,7 @@ pub fn anonymize_late_bound_regions<T>(self, sig: Binder<'tcx, T>) -> Binder<'tc
             .replace_late_bound_regions(sig, |_| {
                 let br = ty::BoundRegion {
                     var: ty::BoundVar::from_u32(counter),
-                    kind: ty::BrAnon(counter),
+                    kind: ty::BrAnon(counter, None),
                 };
                 let r = self.mk_region(ty::ReLateBound(ty::INNERMOST, br));
                 counter += 1;
@@ -606,7 +606,7 @@ pub fn anonymize_late_bound_regions<T>(self, sig: Binder<'tcx, T>) -> Binder<'tc
             })
             .0;
         let bound_vars = self.mk_bound_variable_kinds(
-            (0..counter).map(|i| ty::BoundVariableKind::Region(ty::BrAnon(i))),
+            (0..counter).map(|i| ty::BoundVariableKind::Region(ty::BrAnon(i, None))),
         );
         Binder::bind_with_vars(inner, bound_vars)
     }
@@ -626,7 +626,9 @@ fn replace_region(&mut self, br: ty::BoundRegion) -> ty::Region<'tcx> {
                 let index = entry.index();
                 let var = ty::BoundVar::from_usize(index);
                 let kind = entry
-                    .or_insert_with(|| ty::BoundVariableKind::Region(ty::BrAnon(index as u32)))
+                    .or_insert_with(|| {
+                        ty::BoundVariableKind::Region(ty::BrAnon(index as u32, None))
+                    })
                     .expect_region();
                 let br = ty::BoundRegion { var, kind };
                 self.tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br))
index 3312f44c67b2a884319601a67df751396701b1f5..c74d6bc3774a2d19030b27fc481a6d363b85cb02 100644 (file)
@@ -189,8 +189,8 @@ pub enum LayoutError<'tcx> {
     NormalizationFailure(Ty<'tcx>, NormalizationError<'tcx>),
 }
 
-impl<'a> IntoDiagnostic<'a, !> for LayoutError<'a> {
-    fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, !> {
+impl IntoDiagnostic<'_, !> for LayoutError<'_> {
+    fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, !> {
         let mut diag = handler.struct_fatal("");
 
         match self {
@@ -1126,8 +1126,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
-impl<'tcx> IntoDiagnostic<'tcx, !> for FnAbiError<'tcx> {
-    fn into_diagnostic(self, handler: &'tcx Handler) -> DiagnosticBuilder<'tcx, !> {
+impl IntoDiagnostic<'_, !> for FnAbiError<'_> {
+    fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, !> {
         handler.struct_fatal(self.to_string())
     }
 }
index 27090c62d21ed135d895f4c702651ea280a006e3..18eb06b83c9dfa87f54fbdf56fed2f0e014dd8f5 100644 (file)
@@ -2506,6 +2506,10 @@ pub fn trait_is_auto(self, trait_def_id: DefId) -> bool {
         self.trait_def(trait_def_id).has_auto_impl
     }
 
+    pub fn trait_is_coinductive(self, trait_def_id: DefId) -> bool {
+        self.trait_is_auto(trait_def_id) || self.lang_items().sized_trait() == Some(trait_def_id)
+    }
+
     /// Returns layout of a generator. Layout might be unavailable if the
     /// generator is tainted by errors.
     pub fn generator_layout(self, def_id: DefId) -> Option<&'tcx GeneratorLayout<'tcx>> {
@@ -2550,11 +2554,11 @@ pub fn is_builtin_derive(self, def_id: DefId) -> bool {
 
     /// Looks up the span of `impl_did` if the impl is local; otherwise returns `Err`
     /// with the name of the crate containing the impl.
-    pub fn span_of_impl(self, impl_did: DefId) -> Result<Span, Symbol> {
-        if let Some(impl_did) = impl_did.as_local() {
-            Ok(self.def_span(impl_did))
+    pub fn span_of_impl(self, impl_def_id: DefId) -> Result<Span, Symbol> {
+        if let Some(impl_def_id) = impl_def_id.as_local() {
+            Ok(self.def_span(impl_def_id))
         } else {
-            Err(self.crate_name(impl_did.krate))
+            Err(self.crate_name(impl_def_id.krate))
         }
     }
 
index fab85c39d253594fb8bd1dc35044dd9a4de39137..48e803597b02e1aaa9666d709128abc301debf78 100644 (file)
@@ -1659,6 +1659,12 @@ pub fn def_path_str_with_substs(self, def_id: DefId, substs: &'t [GenericArg<'t>
         debug!("def_path_str: def_id={:?}, ns={:?}", def_id, ns);
         FmtPrinter::new(self, ns).print_def_path(def_id, substs).unwrap().into_buffer()
     }
+
+    pub fn value_path_str_with_substs(self, def_id: DefId, substs: &'t [GenericArg<'t>]) -> String {
+        let ns = guess_def_namespace(self, def_id);
+        debug!("value_path_str: def_id={:?}, ns={:?}", def_id, ns);
+        FmtPrinter::new(self, ns).print_value_path(def_id, substs).unwrap().into_buffer()
+    }
 }
 
 impl fmt::Write for FmtPrinter<'_, '_> {
@@ -2115,7 +2121,7 @@ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
                 // If this is an anonymous placeholder, don't rename. Otherwise, in some
                 // async fns, we get a `for<'r> Send` bound
                 match kind {
-                    ty::BrAnon(_) | ty::BrEnv => r,
+                    ty::BrAnon(..) | ty::BrEnv => r,
                     _ => {
                         // Index doesn't matter, since this is just for naming and these never get bound
                         let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind };
@@ -2219,46 +2225,12 @@ fn name_by_region_index(
         // this is not *quite* right and changes the ordering of some output
         // anyways.
         let (new_value, map) = if self.should_print_verbose() {
-            let regions: Vec<_> = value
-                .bound_vars()
-                .into_iter()
-                .map(|var| {
-                    let ty::BoundVariableKind::Region(var) = var else {
-                    // This doesn't really matter because it doesn't get used,
-                    // it's just an empty value
-                    return ty::BrAnon(0);
-                };
-                    match var {
-                        ty::BrAnon(_) | ty::BrEnv => {
-                            start_or_continue(&mut self, "for<", ", ");
-                            let name = next_name(&self);
-                            debug!(?name);
-                            do_continue(&mut self, name);
-                            ty::BrNamed(CRATE_DEF_ID.to_def_id(), name)
-                        }
-                        ty::BrNamed(def_id, kw::UnderscoreLifetime) => {
-                            start_or_continue(&mut self, "for<", ", ");
-                            let name = next_name(&self);
-                            do_continue(&mut self, name);
-                            ty::BrNamed(def_id, name)
-                        }
-                        ty::BrNamed(def_id, name) => {
-                            start_or_continue(&mut self, "for<", ", ");
-                            do_continue(&mut self, name);
-                            ty::BrNamed(def_id, name)
-                        }
-                    }
-                })
-                .collect();
+            for var in value.bound_vars().iter() {
+                start_or_continue(&mut self, "for<", ", ");
+                write!(self, "{:?}", var)?;
+            }
             start_or_continue(&mut self, "", "> ");
-
-            self.tcx.replace_late_bound_regions(value.clone(), |br| {
-                let kind = regions[br.var.as_usize()];
-                self.tcx.mk_region(ty::ReLateBound(
-                    ty::INNERMOST,
-                    ty::BoundRegion { var: br.var, kind },
-                ))
-            })
+            (value.clone().skip_binder(), BTreeMap::default())
         } else {
             let tcx = self.tcx;
 
@@ -2271,7 +2243,7 @@ fn name_by_region_index(
                             binder_level_idx: ty::DebruijnIndex,
                             br: ty::BoundRegion| {
                 let (name, kind) = match br.kind {
-                    ty::BrAnon(_) | ty::BrEnv => {
+                    ty::BrAnon(..) | ty::BrEnv => {
                         let name = next_name(&self);
 
                         if let Some(lt_idx) = lifetime_idx {
index f2070869ce0cd887cf5ae297121ef41f95d6cdad..9f0598d0ba86b2e461b2110c57f4465859bbc92a 100644 (file)
@@ -68,7 +68,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 impl fmt::Debug for ty::BoundRegionKind {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self {
-            ty::BrAnon(n) => write!(f, "BrAnon({:?})", n),
+            ty::BrAnon(n, span) => write!(f, "BrAnon({n:?}, {span:?})"),
             ty::BrNamed(did, name) => {
                 if did.is_crate_root() {
                     write!(f, "BrNamed({})", name)
index 5f108bf0ef30644a1849beab3e4bb6838a7f2d82..49d82b503a4bb9f59caee7ddf9753aa951aab749 100644 (file)
@@ -59,7 +59,7 @@ pub struct FreeRegion {
 #[derive(HashStable)]
 pub enum BoundRegionKind {
     /// An anonymous region parameter for a given fn (&T)
-    BrAnon(u32),
+    BrAnon(u32, Option<Span>),
 
     /// Named region parameters for functions (a in &'a T)
     ///
index 0660e9b79a700988fe4b20731f8a56af53011c32..2bcb2d824842efc5e1a0683a89c8aad6cead84bd 100644 (file)
@@ -506,6 +506,9 @@ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::Br
     }
 }
 
+/// Similar to [`super::Binder`] except that it tracks early bound generics, i.e. `struct Foo<T>(T)`
+/// needs `T` substituted immediately. This type primarily exists to avoid forgetting to call
+/// `subst`.
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
 #[derive(Encodable, Decodable, HashStable)]
 pub struct EarlyBinder<T>(pub T);
index f0e9f990a8115e8f00bc7cefc9fc68b0408bab81..5e366ef703f254f22b9fec8a17c8813e733aafa9 100644 (file)
@@ -97,7 +97,11 @@ fn references_error(&self) -> bool {
     }
     fn error_reported(&self) -> Result<(), ErrorGuaranteed> {
         if self.references_error() {
-            Err(ErrorGuaranteed::unchecked_claim_error_was_emitted())
+            if let Some(reported) = ty::tls::with(|tcx| tcx.sess.has_errors()) {
+                Err(reported)
+            } else {
+                bug!("expect tcx.sess.has_errors return true");
+            }
         } else {
             Ok(())
         }
index 5ca51c25a9ce17a79306072d31261c4f2b78cc20..6eae94511e4d63c05f1a508da14027ac07cf0399 100644 (file)
@@ -66,7 +66,7 @@ pub(super) fn vtable_allocation_provider<'tcx>(
     let layout = tcx
         .layout_of(ty::ParamEnv::reveal_all().and(ty))
         .expect("failed to build vtable representation");
-    assert!(!layout.is_unsized(), "can't create a vtable for an unsized type");
+    assert!(layout.is_sized(), "can't create a vtable for an unsized type");
     let size = layout.size.bytes();
     let align = layout.align.abi.bytes();
 
index f4b4c3fb05a7cb9e666741851661948f101a5215..f4562cdfb88dcfdfa07c488896a761f3fef5872f 100644 (file)
@@ -185,7 +185,8 @@ fn find_item_ty_spans(
                 });
                 if check_params && let Some(args) = path.segments.last().unwrap().args {
                     let params_in_repr = tcx.params_in_repr(def_id);
-                    for (i, arg) in args.args.iter().enumerate() {
+                    // the domain size check is needed because the HIR may not be well-formed at this point
+                    for (i, arg) in args.args.iter().enumerate().take(params_in_repr.domain_size()) {
                         if let hir::GenericArg::Type(ty) = arg && params_in_repr.contains(i as u32) {
                             find_item_ty_spans(tcx, ty, needle, spans, seen_representable);
                         }
diff --git a/compiler/rustc_mir_build/src/build/custom/mod.rs b/compiler/rustc_mir_build/src/build/custom/mod.rs
new file mode 100644 (file)
index 0000000..68d8766
--- /dev/null
@@ -0,0 +1,155 @@
+//! Provides the implementation of the `custom_mir` attribute.
+//!
+//! Up until MIR building, this attribute has absolutely no effect. The `mir!` macro is a normal
+//! decl macro that expands like any other, and the code goes through parsing, name resolution and
+//! type checking like all other code. In MIR building we finally detect whether this attribute is
+//! present, and if so we branch off into this module, which implements the attribute by
+//! implementing a custom lowering from THIR to MIR.
+//!
+//! The result of this lowering is returned "normally" from the `mir_built` query, with the only
+//! notable difference being that the `injected` field in the body is set. Various components of the
+//! MIR pipeline, like borrowck and the pass manager will then consult this field (via
+//! `body.should_skip()`) to skip the parts of the MIR pipeline that precede the MIR phase the user
+//! specified.
+//!
+//! This file defines the general framework for the custom parsing. The parsing for all the
+//! "top-level" constructs can be found in the `parse` submodule, while the parsing for statements,
+//! terminators, and everything below can be found in the `parse::instruction` submodule.
+//!
+
+use rustc_ast::Attribute;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir::def_id::DefId;
+use rustc_index::vec::IndexVec;
+use rustc_middle::{
+    mir::*,
+    thir::*,
+    ty::{Ty, TyCtxt},
+};
+use rustc_span::Span;
+
+mod parse;
+
+pub(super) fn build_custom_mir<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    did: DefId,
+    thir: &Thir<'tcx>,
+    expr: ExprId,
+    params: &IndexVec<ParamId, Param<'tcx>>,
+    return_ty: Ty<'tcx>,
+    return_ty_span: Span,
+    span: Span,
+    attr: &Attribute,
+) -> Body<'tcx> {
+    let mut body = Body {
+        basic_blocks: BasicBlocks::new(IndexVec::new()),
+        source: MirSource::item(did),
+        phase: MirPhase::Built,
+        source_scopes: IndexVec::new(),
+        generator: None,
+        local_decls: LocalDecls::new(),
+        user_type_annotations: IndexVec::new(),
+        arg_count: params.len(),
+        spread_arg: None,
+        var_debug_info: Vec::new(),
+        span,
+        required_consts: Vec::new(),
+        is_polymorphic: false,
+        tainted_by_errors: None,
+        injection_phase: None,
+        pass_count: 1,
+    };
+
+    body.local_decls.push(LocalDecl::new(return_ty, return_ty_span));
+    body.basic_blocks_mut().push(BasicBlockData::new(None));
+    body.source_scopes.push(SourceScopeData {
+        span,
+        parent_scope: None,
+        inlined: None,
+        inlined_parent_scope: None,
+        local_data: ClearCrossCrate::Clear,
+    });
+    body.injection_phase = Some(parse_attribute(attr));
+
+    let mut pctxt = ParseCtxt {
+        tcx,
+        thir,
+        source_info: SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE },
+        body: &mut body,
+        local_map: FxHashMap::default(),
+        block_map: FxHashMap::default(),
+    };
+
+    let res = (|| {
+        pctxt.parse_args(&params)?;
+        pctxt.parse_body(expr)
+    })();
+    if let Err(err) = res {
+        tcx.sess.diagnostic().span_fatal(
+            err.span,
+            format!("Could not parse {}, found: {:?}", err.expected, err.item_description),
+        )
+    }
+
+    body
+}
+
+fn parse_attribute(attr: &Attribute) -> MirPhase {
+    let meta_items = attr.meta_item_list().unwrap();
+    let mut dialect: Option<String> = None;
+    let mut phase: Option<String> = None;
+
+    for nested in meta_items {
+        let name = nested.name_or_empty();
+        let value = nested.value_str().unwrap().as_str().to_string();
+        match name.as_str() {
+            "dialect" => {
+                assert!(dialect.is_none());
+                dialect = Some(value);
+            }
+            "phase" => {
+                assert!(phase.is_none());
+                phase = Some(value);
+            }
+            other => {
+                panic!("Unexpected key {}", other);
+            }
+        }
+    }
+
+    let Some(dialect) = dialect else {
+        assert!(phase.is_none());
+        return MirPhase::Built;
+    };
+
+    MirPhase::parse(dialect, phase)
+}
+
+struct ParseCtxt<'tcx, 'body> {
+    tcx: TyCtxt<'tcx>,
+    thir: &'body Thir<'tcx>,
+    source_info: SourceInfo,
+
+    body: &'body mut Body<'tcx>,
+    local_map: FxHashMap<LocalVarId, Local>,
+    block_map: FxHashMap<LocalVarId, BasicBlock>,
+}
+
+struct ParseError {
+    span: Span,
+    item_description: String,
+    expected: String,
+}
+
+impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
+    fn expr_error(&self, expr: ExprId, expected: &'static str) -> ParseError {
+        let expr = &self.thir[expr];
+        ParseError {
+            span: expr.span,
+            item_description: format!("{:?}", expr.kind),
+            expected: expected.to_string(),
+        }
+    }
+}
+
+type PResult<T> = Result<T, ParseError>;
diff --git a/compiler/rustc_mir_build/src/build/custom/parse.rs b/compiler/rustc_mir_build/src/build/custom/parse.rs
new file mode 100644 (file)
index 0000000..52cb0a4
--- /dev/null
@@ -0,0 +1,245 @@
+use rustc_index::vec::IndexVec;
+use rustc_middle::{mir::*, thir::*, ty::Ty};
+use rustc_span::Span;
+
+use super::{PResult, ParseCtxt, ParseError};
+
+mod instruction;
+
+/// Helper macro for parsing custom MIR.
+///
+/// Example usage looks something like:
+/// ```rust,ignore (incomplete example)
+/// parse_by_kind!(
+///     self, // : &ParseCtxt
+///     expr_id, // what you're matching against
+///     "assignment", // the thing you're trying to parse
+///     @call("mir_assign", args) => { args[0] }, // match invocations of the `mir_assign` special function
+///     ExprKind::Assign { lhs, .. } => { lhs }, // match thir assignment expressions
+///     // no need for fallthrough case - reasonable error is automatically generated
+/// )
+/// ```
+macro_rules! parse_by_kind {
+    (
+        $self:ident,
+        $expr_id:expr,
+        $expected:literal,
+        $(
+            @call($name:literal, $args:ident) => $call_expr:expr,
+        )*
+        $(
+            $pat:pat => $expr:expr,
+        )*
+    ) => {{
+        let expr_id = $self.preparse($expr_id);
+        let expr = &$self.thir[expr_id];
+        match &expr.kind {
+            $(
+                ExprKind::Call { ty, fun: _, args: $args, .. } if {
+                    match ty.kind() {
+                        ty::FnDef(did, _) => {
+                            $self.tcx.is_diagnostic_item(rustc_span::Symbol::intern($name), *did)
+                        }
+                        _ => false,
+                    }
+                } => $call_expr,
+            )*
+            $(
+                $pat => $expr,
+            )*
+            #[allow(unreachable_patterns)]
+            _ => return Err($self.expr_error(expr_id, $expected))
+        }
+    }};
+}
+pub(crate) use parse_by_kind;
+
+impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
+    /// Expressions should only ever be matched on after preparsing them. This removes extra scopes
+    /// we don't care about.
+    fn preparse(&self, expr_id: ExprId) -> ExprId {
+        let expr = &self.thir[expr_id];
+        match expr.kind {
+            ExprKind::Scope { value, .. } => self.preparse(value),
+            _ => expr_id,
+        }
+    }
+
+    fn statement_as_expr(&self, stmt_id: StmtId) -> PResult<ExprId> {
+        match &self.thir[stmt_id].kind {
+            StmtKind::Expr { expr, .. } => Ok(*expr),
+            kind @ StmtKind::Let { pattern, .. } => {
+                return Err(ParseError {
+                    span: pattern.span,
+                    item_description: format!("{:?}", kind),
+                    expected: "expression".to_string(),
+                });
+            }
+        }
+    }
+
+    pub fn parse_args(&mut self, params: &IndexVec<ParamId, Param<'tcx>>) -> PResult<()> {
+        for param in params.iter() {
+            let (var, span) = {
+                let pat = param.pat.as_ref().unwrap();
+                match &pat.kind {
+                    PatKind::Binding { var, .. } => (*var, pat.span),
+                    _ => {
+                        return Err(ParseError {
+                            span: pat.span,
+                            item_description: format!("{:?}", pat.kind),
+                            expected: "local".to_string(),
+                        });
+                    }
+                }
+            };
+            let decl = LocalDecl::new(param.ty, span);
+            let local = self.body.local_decls.push(decl);
+            self.local_map.insert(var, local);
+        }
+
+        Ok(())
+    }
+
+    /// Bodies are of the form:
+    ///
+    /// ```text
+    /// {
+    ///     let bb1: BasicBlock;
+    ///     let bb2: BasicBlock;
+    ///     {
+    ///         let RET: _;
+    ///         let local1;
+    ///         let local2;
+    ///
+    ///         {
+    ///             { // entry block
+    ///                 statement1;
+    ///                 terminator1
+    ///             };
+    ///
+    ///             bb1 = {
+    ///                 statement2;
+    ///                 terminator2
+    ///             };
+    ///
+    ///             bb2 = {
+    ///                 statement3;
+    ///                 terminator3
+    ///             }
+    ///
+    ///             RET
+    ///         }
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// This allows us to easily parse the basic blocks declarations, local declarations, and
+    /// basic block definitions in order.
+    pub fn parse_body(&mut self, expr_id: ExprId) -> PResult<()> {
+        let body = parse_by_kind!(self, expr_id, "whole body",
+            ExprKind::Block { block } => self.thir[*block].expr.unwrap(),
+        );
+        let (block_decls, rest) = parse_by_kind!(self, body, "body with block decls",
+            ExprKind::Block { block } => {
+                let block = &self.thir[*block];
+                (&block.stmts, block.expr.unwrap())
+            },
+        );
+        self.parse_block_decls(block_decls.iter().copied())?;
+
+        let (local_decls, rest) = parse_by_kind!(self, rest, "body with local decls",
+            ExprKind::Block { block } => {
+                let block = &self.thir[*block];
+                (&block.stmts, block.expr.unwrap())
+            },
+        );
+        self.parse_local_decls(local_decls.iter().copied())?;
+
+        let block_defs = parse_by_kind!(self, rest, "body with block defs",
+            ExprKind::Block { block } => &self.thir[*block].stmts,
+        );
+        for (i, block_def) in block_defs.iter().enumerate() {
+            let block = self.parse_block_def(self.statement_as_expr(*block_def)?)?;
+            self.body.basic_blocks_mut()[BasicBlock::from_usize(i)] = block;
+        }
+
+        Ok(())
+    }
+
+    fn parse_block_decls(&mut self, stmts: impl Iterator<Item = StmtId>) -> PResult<()> {
+        for stmt in stmts {
+            let (var, _, _) = self.parse_let_statement(stmt)?;
+            let data = BasicBlockData::new(None);
+            let block = self.body.basic_blocks_mut().push(data);
+            self.block_map.insert(var, block);
+        }
+
+        Ok(())
+    }
+
+    fn parse_local_decls(&mut self, mut stmts: impl Iterator<Item = StmtId>) -> PResult<()> {
+        let (ret_var, ..) = self.parse_let_statement(stmts.next().unwrap())?;
+        self.local_map.insert(ret_var, Local::from_u32(0));
+
+        for stmt in stmts {
+            let (var, ty, span) = self.parse_let_statement(stmt)?;
+            let decl = LocalDecl::new(ty, span);
+            let local = self.body.local_decls.push(decl);
+            self.local_map.insert(var, local);
+        }
+
+        Ok(())
+    }
+
+    fn parse_let_statement(&mut self, stmt_id: StmtId) -> PResult<(LocalVarId, Ty<'tcx>, Span)> {
+        let pattern = match &self.thir[stmt_id].kind {
+            StmtKind::Let { pattern, .. } => pattern,
+            StmtKind::Expr { expr, .. } => {
+                return Err(self.expr_error(*expr, "let statement"));
+            }
+        };
+
+        self.parse_var(pattern)
+    }
+
+    fn parse_var(&mut self, mut pat: &Pat<'tcx>) -> PResult<(LocalVarId, Ty<'tcx>, Span)> {
+        // Make sure we throw out any `AscribeUserType` we find
+        loop {
+            match &pat.kind {
+                PatKind::Binding { var, ty, .. } => break Ok((*var, *ty, pat.span)),
+                PatKind::AscribeUserType { subpattern, .. } => {
+                    pat = subpattern;
+                }
+                _ => {
+                    break Err(ParseError {
+                        span: pat.span,
+                        item_description: format!("{:?}", pat.kind),
+                        expected: "local".to_string(),
+                    });
+                }
+            }
+        }
+    }
+
+    fn parse_block_def(&self, expr_id: ExprId) -> PResult<BasicBlockData<'tcx>> {
+        let block = parse_by_kind!(self, expr_id, "basic block",
+            ExprKind::Block { block } => &self.thir[*block],
+        );
+
+        let mut data = BasicBlockData::new(None);
+        for stmt_id in &*block.stmts {
+            let stmt = self.statement_as_expr(*stmt_id)?;
+            let statement = self.parse_statement(stmt)?;
+            data.statements.push(Statement { source_info: self.source_info, kind: statement });
+        }
+
+        let Some(trailing) = block.expr else {
+            return Err(self.expr_error(expr_id, "terminator"))
+        };
+        let terminator = self.parse_terminator(trailing)?;
+        data.terminator = Some(Terminator { source_info: self.source_info, kind: terminator });
+
+        Ok(data)
+    }
+}
diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
new file mode 100644 (file)
index 0000000..6d61765
--- /dev/null
@@ -0,0 +1,72 @@
+use rustc_middle::{mir::*, thir::*, ty};
+
+use super::{parse_by_kind, PResult, ParseCtxt};
+
+impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
+    pub fn parse_statement(&self, expr_id: ExprId) -> PResult<StatementKind<'tcx>> {
+        parse_by_kind!(self, expr_id, "statement",
+            @call("mir_retag", args) => {
+                Ok(StatementKind::Retag(RetagKind::Default, Box::new(self.parse_place(args[0])?)))
+            },
+            @call("mir_retag_raw", args) => {
+                Ok(StatementKind::Retag(RetagKind::Raw, Box::new(self.parse_place(args[0])?)))
+            },
+            ExprKind::Assign { lhs, rhs } => {
+                let lhs = self.parse_place(*lhs)?;
+                let rhs = self.parse_rvalue(*rhs)?;
+                Ok(StatementKind::Assign(Box::new((lhs, rhs))))
+            },
+        )
+    }
+
+    pub fn parse_terminator(&self, expr_id: ExprId) -> PResult<TerminatorKind<'tcx>> {
+        parse_by_kind!(self, expr_id, "terminator",
+            @call("mir_return", _args) => {
+                Ok(TerminatorKind::Return)
+            },
+            @call("mir_goto", args) => {
+                Ok(TerminatorKind::Goto { target: self.parse_block(args[0])? } )
+            },
+        )
+    }
+
+    fn parse_rvalue(&self, expr_id: ExprId) -> PResult<Rvalue<'tcx>> {
+        parse_by_kind!(self, expr_id, "rvalue",
+            ExprKind::Borrow { borrow_kind, arg } => Ok(
+                Rvalue::Ref(self.tcx.lifetimes.re_erased, *borrow_kind, self.parse_place(*arg)?)
+            ),
+            ExprKind::AddressOf { mutability, arg } => Ok(
+                Rvalue::AddressOf(*mutability, self.parse_place(*arg)?)
+            ),
+            _ => self.parse_operand(expr_id).map(Rvalue::Use),
+        )
+    }
+
+    fn parse_operand(&self, expr_id: ExprId) -> PResult<Operand<'tcx>> {
+        parse_by_kind!(self, expr_id, "operand",
+            @call("mir_move", args) => self.parse_place(args[0]).map(Operand::Move),
+            _ => self.parse_place(expr_id).map(Operand::Copy),
+        )
+    }
+
+    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),
+        )
+    }
+
+    fn parse_local(&self, expr_id: ExprId) -> PResult<Local> {
+        parse_by_kind!(self, expr_id, "local",
+            ExprKind::VarRef { id } => Ok(self.local_map[id]),
+        )
+    }
+
+    fn parse_block(&self, expr_id: ExprId) -> PResult<BasicBlock> {
+        parse_by_kind!(self, expr_id, "basic block",
+            ExprKind::VarRef { id } => Ok(self.block_map[id]),
+        )
+    }
+}
index 98df9c3f0e8df364a961a1f6d8f9699d554058ab..7d8a940bde5cefc78c9d5988c364f90bff270786 100644 (file)
@@ -9,6 +9,7 @@
 use rustc_middle::mir::*;
 use rustc_middle::thir::*;
 use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, TyCtxt};
+use rustc_span::DUMMY_SP;
 use rustc_target::abi::Size;
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
@@ -26,7 +27,9 @@ pub(crate) fn as_constant(&mut self, expr: &Expr<'tcx>) -> Constant<'tcx> {
                 let literal =
                     match lit_to_mir_constant(tcx, LitToConstInput { lit: &lit.node, ty, neg }) {
                         Ok(c) => c,
-                        Err(LitToConstError::Reported) => ConstantKind::Ty(tcx.const_error(ty)),
+                        Err(LitToConstError::Reported(guar)) => {
+                            ConstantKind::Ty(tcx.const_error_with_guaranteed(ty, guar))
+                        }
                         Err(LitToConstError::TypeError) => {
                             bug!("encountered type error in `lit_to_mir_constant")
                         }
@@ -105,7 +108,15 @@ pub(crate) fn lit_to_mir_constant<'tcx>(
     let LitToConstInput { lit, ty, neg } = lit_input;
     let trunc = |n| {
         let param_ty = ty::ParamEnv::reveal_all().and(ty);
-        let width = tcx.layout_of(param_ty).map_err(|_| LitToConstError::Reported)?.size;
+        let width = tcx
+            .layout_of(param_ty)
+            .map_err(|_| {
+                LitToConstError::Reported(tcx.sess.delay_span_bug(
+                    DUMMY_SP,
+                    format!("couldn't compute width of literal: {:?}", lit_input.lit),
+                ))
+            })?
+            .size;
         trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits());
         let result = width.truncate(n);
         trace!("trunc result: {}", result);
@@ -136,12 +147,20 @@ pub(crate) fn lit_to_mir_constant<'tcx>(
         (ast::LitKind::Int(n, _), ty::Uint(_)) | (ast::LitKind::Int(n, _), ty::Int(_)) => {
             trunc(if neg { (*n as i128).overflowing_neg().0 as u128 } else { *n })?
         }
-        (ast::LitKind::Float(n, _), ty::Float(fty)) => {
-            parse_float_into_constval(*n, *fty, neg).ok_or(LitToConstError::Reported)?
-        }
+        (ast::LitKind::Float(n, _), ty::Float(fty)) => parse_float_into_constval(*n, *fty, neg)
+            .ok_or_else(|| {
+                LitToConstError::Reported(tcx.sess.delay_span_bug(
+                    DUMMY_SP,
+                    format!("couldn't parse float literal: {:?}", lit_input.lit),
+                ))
+            })?,
         (ast::LitKind::Bool(b), ty::Bool) => ConstValue::Scalar(Scalar::from_bool(*b)),
         (ast::LitKind::Char(c), ty::Char) => ConstValue::Scalar(Scalar::from_char(*c)),
-        (ast::LitKind::Err, _) => return Err(LitToConstError::Reported),
+        (ast::LitKind::Err, _) => {
+            return Err(LitToConstError::Reported(
+                tcx.sess.delay_span_bug(DUMMY_SP, "encountered LitKind::Err during mir build"),
+            ));
+        }
         _ => return Err(LitToConstError::TypeError),
     };
 
index cbcf9cd129f3f76c8886127cd9c10a167670c0de..437ac8d82a1a3136bd38ff9d6f51b33f42884a77 100644 (file)
@@ -481,6 +481,22 @@ fn construct_fn<'tcx>(
         (None, fn_sig.output())
     };
 
+    if let Some(custom_mir_attr) =
+        tcx.hir().attrs(fn_id).iter().find(|attr| attr.name_or_empty() == sym::custom_mir)
+    {
+        return custom::build_custom_mir(
+            tcx,
+            fn_def.did.to_def_id(),
+            thir,
+            expr,
+            arguments,
+            return_ty,
+            return_ty_span,
+            span,
+            custom_mir_attr,
+        );
+    }
+
     let infcx = tcx.infer_ctxt().build();
     let mut builder = Builder::new(
         thir,
@@ -1033,6 +1049,7 @@ pub(crate) fn parse_float_into_scalar(
 
 mod block;
 mod cfg;
+mod custom;
 mod expr;
 mod matches;
 mod misc;
index f626571b5b2c59f88e2da701e9f5fb5671924901..85e8801bda3ec929453c3473eaf01d2ce06dcbe1 100644 (file)
@@ -1,6 +1,7 @@
 use rustc_ast as ast;
 use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
 use rustc_middle::ty::{self, ParamEnv, ScalarInt, TyCtxt};
+use rustc_span::DUMMY_SP;
 
 pub(crate) fn lit_to_const<'tcx>(
     tcx: TyCtxt<'tcx>,
@@ -10,7 +11,15 @@ pub(crate) fn lit_to_const<'tcx>(
 
     let trunc = |n| {
         let param_ty = ParamEnv::reveal_all().and(ty);
-        let width = tcx.layout_of(param_ty).map_err(|_| LitToConstError::Reported)?.size;
+        let width = tcx
+            .layout_of(param_ty)
+            .map_err(|_| {
+                LitToConstError::Reported(tcx.sess.delay_span_bug(
+                    DUMMY_SP,
+                    format!("couldn't compute width of literal: {:?}", lit_input.lit),
+                ))
+            })?
+            .size;
         trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits());
         let result = width.truncate(n);
         trace!("trunc result: {}", result);
@@ -44,7 +53,11 @@ pub(crate) fn lit_to_const<'tcx>(
         }
         (ast::LitKind::Bool(b), ty::Bool) => ty::ValTree::from_scalar_int((*b).into()),
         (ast::LitKind::Char(c), ty::Char) => ty::ValTree::from_scalar_int((*c).into()),
-        (ast::LitKind::Err, _) => return Err(LitToConstError::Reported),
+        (ast::LitKind::Err, _) => {
+            return Err(LitToConstError::Reported(
+                tcx.sess.delay_span_bug(DUMMY_SP, "encountered LitKind::Err during mir build"),
+            ));
+        }
         _ => return Err(LitToConstError::TypeError),
     };
 
index c7a7c3e3fa8eefd6f42747e13488e362416d1322..c4639d3a513dfb7e4e13a32c741e312988abe218 100644 (file)
@@ -51,11 +51,17 @@ pub(super) fn mirror_expr_inner(&mut self, hir_expr: &'tcx hir::Expr<'tcx>) -> E
         trace!(?expr.ty);
 
         // Now apply adjustments, if any.
-        for adjustment in self.typeck_results.expr_adjustments(hir_expr) {
-            trace!(?expr, ?adjustment);
-            let span = expr.span;
-            expr =
-                self.apply_adjustment(hir_expr, expr, adjustment, adjustment_span.unwrap_or(span));
+        if self.apply_adjustments {
+            for adjustment in self.typeck_results.expr_adjustments(hir_expr) {
+                trace!(?expr, ?adjustment);
+                let span = expr.span;
+                expr = self.apply_adjustment(
+                    hir_expr,
+                    expr,
+                    adjustment,
+                    adjustment_span.unwrap_or(span),
+                );
+            }
         }
 
         trace!(?expr.ty, "after adjustments");
index 1d95d6b53fbece1e34833720875f6ea20a5d8a7b..b5c4b7b137d4c28a2ea2399e6bf1d8dfad156068 100644 (file)
@@ -80,6 +80,9 @@ struct Cx<'tcx> {
     /// for the receiver.
     adjustment_span: Option<(HirId, Span)>,
 
+    /// False to indicate that adjustments should not be applied. Only used for `custom_mir`
+    apply_adjustments: bool,
+
     /// The `DefId` of the owner of this body.
     body_owner: DefId,
 }
@@ -87,6 +90,8 @@ struct Cx<'tcx> {
 impl<'tcx> Cx<'tcx> {
     fn new(tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam<LocalDefId>) -> Cx<'tcx> {
         let typeck_results = tcx.typeck_opt_const_arg(def);
+        let did = def.did;
+        let hir = tcx.hir();
         Cx {
             tcx,
             thir: Thir::new(),
@@ -94,8 +99,12 @@ fn new(tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam<LocalDefId>) -> Cx<'tcx> {
             region_scope_tree: tcx.region_scope_tree(def.did),
             typeck_results,
             rvalue_scopes: &typeck_results.rvalue_scopes,
-            body_owner: def.did.to_def_id(),
+            body_owner: did.to_def_id(),
             adjustment_span: None,
+            apply_adjustments: hir
+                .attrs(hir.local_def_id_to_hir_id(did))
+                .iter()
+                .all(|attr| attr.name_or_empty() != rustc_span::sym::custom_mir),
         }
     }
 
index 2526522a25c8c882aa536d9864245aeb6c555c15..776c748c7e5fe626fc09e999597ed05baa0ee99e 100644 (file)
@@ -614,7 +614,7 @@ fn lower_lit(&mut self, expr: &'tcx hir::Expr<'tcx>) -> PatKind<'tcx> {
             LitToConstInput { lit: &lit.node, ty: self.typeck_results.expr_ty(expr), neg };
         match self.tcx.at(expr.span).lit_to_mir_constant(lit_input) {
             Ok(constant) => self.const_to_pat(constant, expr.hir_id, lit.span, false).kind,
-            Err(LitToConstError::Reported) => PatKind::Wild,
+            Err(LitToConstError::Reported(_)) => PatKind::Wild,
             Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"),
         }
     }
index 269d9f3b102c196d0c4279eee54ace23c52edc55..e783d189137749cabfc28a12872bf7ff4ad64006 100644 (file)
@@ -471,6 +471,14 @@ fn unsafety_check_result<'tcx>(
     // `mir_built` force this.
     let body = &tcx.mir_built(def).borrow();
 
+    if body.should_skip() {
+        return tcx.arena.alloc(UnsafetyCheckResult {
+            violations: Vec::new(),
+            used_unsafe_blocks: FxHashSet::default(),
+            unused_unsafes: Some(Vec::new()),
+        });
+    }
+
     let param_env = tcx.param_env(def.did);
 
     let mut checker = UnsafetyChecker::new(body, def.did, tcx, param_env);
index 4e4515888454b8a1038a583478ac845cbd868892..4f30e8a0be03ef3cda925f60540da06bb4111d56 100644 (file)
@@ -385,7 +385,7 @@ fn new(
             // I don't know how return types can seem to be unsized but this happens in the
             // `type/type-unsatisfiable.rs` test.
             .filter(|ret_layout| {
-                !ret_layout.is_unsized() && ret_layout.size < Size::from_bytes(MAX_ALLOC_LIMIT)
+                ret_layout.is_sized() && ret_layout.size < Size::from_bytes(MAX_ALLOC_LIMIT)
             })
             .unwrap_or_else(|| ecx.layout_of(tcx.types.unit).unwrap());
 
index 479c4e577d4e3aad83e0098e3c18764cd654af67..163446c52e4c28112ad4d90681c3f01d5a365c21 100644 (file)
@@ -199,7 +199,7 @@ fn new(
             // I don't know how return types can seem to be unsized but this happens in the
             // `type/type-unsatisfiable.rs` test.
             .filter(|ret_layout| {
-                !ret_layout.is_unsized() && ret_layout.size < Size::from_bytes(MAX_ALLOC_LIMIT)
+                ret_layout.is_sized() && ret_layout.size < Size::from_bytes(MAX_ALLOC_LIMIT)
             })
             .unwrap_or_else(|| ecx.layout_of(tcx.types.unit).unwrap());
 
index 230c6a7cb4b00e438ca32ca439fea4b52930bc0d..27dbc3e22c97a58ac53b09eec34d355229906ce3 100644 (file)
@@ -96,45 +96,48 @@ fn run_passes_inner<'tcx>(
     phase_change: Option<MirPhase>,
     validate_each: bool,
 ) {
-    let validate = validate_each & tcx.sess.opts.unstable_opts.validate_mir;
+    let validate = validate_each & tcx.sess.opts.unstable_opts.validate_mir & !body.should_skip();
     let overridden_passes = &tcx.sess.opts.unstable_opts.mir_enable_passes;
     trace!(?overridden_passes);
 
-    for pass in passes {
-        let name = pass.name();
-
-        let overridden =
-            overridden_passes.iter().rev().find(|(s, _)| s == &*name).map(|(_name, polarity)| {
-                trace!(
-                    pass = %name,
-                    "{} as requested by flag",
-                    if *polarity { "Running" } else { "Not running" },
-                );
-                *polarity
-            });
-        if !overridden.unwrap_or_else(|| pass.is_enabled(&tcx.sess)) {
-            continue;
+    if !body.should_skip() {
+        for pass in passes {
+            let name = pass.name();
+
+            let overridden = overridden_passes.iter().rev().find(|(s, _)| s == &*name).map(
+                |(_name, polarity)| {
+                    trace!(
+                        pass = %name,
+                        "{} as requested by flag",
+                        if *polarity { "Running" } else { "Not running" },
+                    );
+                    *polarity
+                },
+            );
+            if !overridden.unwrap_or_else(|| pass.is_enabled(&tcx.sess)) {
+                continue;
+            }
+
+            let dump_enabled = pass.is_mir_dump_enabled();
+
+            if dump_enabled {
+                dump_mir_for_pass(tcx, body, &name, false);
+            }
+            if validate {
+                validate_body(tcx, body, format!("before pass {}", name));
+            }
+
+            pass.run_pass(tcx, body);
+
+            if dump_enabled {
+                dump_mir_for_pass(tcx, body, &name, true);
+            }
+            if validate {
+                validate_body(tcx, body, format!("after pass {}", name));
+            }
+
+            body.pass_count += 1;
         }
-
-        let dump_enabled = pass.is_mir_dump_enabled();
-
-        if dump_enabled {
-            dump_mir_for_pass(tcx, body, &name, false);
-        }
-        if validate {
-            validate_body(tcx, body, format!("before pass {}", name));
-        }
-
-        pass.run_pass(tcx, body);
-
-        if dump_enabled {
-            dump_mir_for_pass(tcx, body, &name, true);
-        }
-        if validate {
-            validate_body(tcx, body, format!("after pass {}", name));
-        }
-
-        body.pass_count += 1;
     }
 
     if let Some(new_phase) = phase_change {
index cc75947d9dda73b2f38b6e47cc03a5bf47311e2b..0ea8f2ba93fd8a1c621338441d08255aab439e21 100644 (file)
@@ -17,7 +17,7 @@ fn visit_constant(&mut self, constant: &Constant<'tcx>, _: Location) {
         let literal = constant.literal;
         match literal {
             ConstantKind::Ty(c) => match c.kind() {
-                ConstKind::Param(_) => {}
+                ConstKind::Param(_) | ConstKind::Error(_) => {}
                 _ => bug!("only ConstKind::Param should be encountered here, got {:#?}", c),
             },
             ConstantKind::Unevaluated(..) => self.required_consts.push(*constant),
index 0924c8537159c50322c6004836c271ee738dfea0..d59982f7063f33e5756cdf62cfb60eecc0b7e576 100644 (file)
@@ -420,6 +420,15 @@ pub(crate) struct ExpectedExpressionFoundLet {
     pub span: Span,
 }
 
+#[derive(Diagnostic)]
+#[diag(parser_expect_eq_instead_of_eqeq)]
+pub(crate) struct ExpectedEqForLetExpr {
+    #[primary_span]
+    pub span: Span,
+    #[suggestion(applicability = "maybe-incorrect", code = "=", style = "verbose")]
+    pub sugg_span: Span,
+}
+
 #[derive(Diagnostic)]
 #[diag(parser_expected_else_block)]
 pub(crate) struct ExpectedElseBlock {
@@ -1156,10 +1165,12 @@ pub(crate) struct ParenthesesInForHead {
 #[derive(Subdiagnostic)]
 #[multipart_suggestion(suggestion, applicability = "machine-applicable")]
 pub(crate) struct ParenthesesInForHeadSugg {
-    #[suggestion_part(code = "")]
+    #[suggestion_part(code = "{left_snippet}")]
     pub left: Span,
-    #[suggestion_part(code = "")]
+    pub left_snippet: String,
+    #[suggestion_part(code = "{right_snippet}")]
     pub right: Span,
+    pub right_snippet: String,
 }
 
 #[derive(Diagnostic)]
index de8f1c00c1295747ca42619c8c52520e7e4554ac..645262bd2f1d37dcf5d714b618457e94e3a3f81b 100644 (file)
@@ -353,55 +353,55 @@ fn cook_doc_comment(
     fn cook_lexer_literal(
         &self,
         start: BytePos,
-        suffix_start: BytePos,
+        end: BytePos,
         kind: rustc_lexer::LiteralKind,
     ) -> (token::LitKind, Symbol) {
-        // prefix means `"` or `br"` or `r###"`, ...
-        let (lit_kind, mode, prefix_len, postfix_len) = match kind {
+        match kind {
             rustc_lexer::LiteralKind::Char { terminated } => {
                 if !terminated {
                     self.sess.span_diagnostic.span_fatal_with_code(
-                        self.mk_sp(start, suffix_start),
+                        self.mk_sp(start, end),
                         "unterminated character literal",
                         error_code!(E0762),
                     )
                 }
-                (token::Char, Mode::Char, 1, 1) // ' '
+                self.cook_quoted(token::Char, Mode::Char, start, end, 1, 1) // ' '
             }
             rustc_lexer::LiteralKind::Byte { terminated } => {
                 if !terminated {
                     self.sess.span_diagnostic.span_fatal_with_code(
-                        self.mk_sp(start + BytePos(1), suffix_start),
+                        self.mk_sp(start + BytePos(1), end),
                         "unterminated byte constant",
                         error_code!(E0763),
                     )
                 }
-                (token::Byte, Mode::Byte, 2, 1) // b' '
+                self.cook_quoted(token::Byte, Mode::Byte, start, end, 2, 1) // b' '
             }
             rustc_lexer::LiteralKind::Str { terminated } => {
                 if !terminated {
                     self.sess.span_diagnostic.span_fatal_with_code(
-                        self.mk_sp(start, suffix_start),
+                        self.mk_sp(start, end),
                         "unterminated double quote string",
                         error_code!(E0765),
                     )
                 }
-                (token::Str, Mode::Str, 1, 1) // " "
+                self.cook_quoted(token::Str, Mode::Str, start, end, 1, 1) // " "
             }
             rustc_lexer::LiteralKind::ByteStr { terminated } => {
                 if !terminated {
                     self.sess.span_diagnostic.span_fatal_with_code(
-                        self.mk_sp(start + BytePos(1), suffix_start),
+                        self.mk_sp(start + BytePos(1), end),
                         "unterminated double quote byte string",
                         error_code!(E0766),
                     )
                 }
-                (token::ByteStr, Mode::ByteStr, 2, 1) // b" "
+                self.cook_quoted(token::ByteStr, Mode::ByteStr, start, end, 2, 1) // b" "
             }
             rustc_lexer::LiteralKind::RawStr { n_hashes } => {
                 if let Some(n_hashes) = n_hashes {
                     let n = u32::from(n_hashes);
-                    (token::StrRaw(n_hashes), Mode::RawStr, 2 + n, 1 + n) // r##" "##
+                    let kind = token::StrRaw(n_hashes);
+                    self.cook_quoted(kind, Mode::RawStr, start, end, 2 + n, 1 + n) // r##" "##
                 } else {
                     self.report_raw_str_error(start, 1);
                 }
@@ -409,56 +409,59 @@ fn cook_lexer_literal(
             rustc_lexer::LiteralKind::RawByteStr { n_hashes } => {
                 if let Some(n_hashes) = n_hashes {
                     let n = u32::from(n_hashes);
-                    (token::ByteStrRaw(n_hashes), Mode::RawByteStr, 3 + n, 1 + n) // br##" "##
+                    let kind = token::ByteStrRaw(n_hashes);
+                    self.cook_quoted(kind, Mode::RawByteStr, start, end, 3 + n, 1 + n) // br##" "##
                 } else {
                     self.report_raw_str_error(start, 2);
                 }
             }
             rustc_lexer::LiteralKind::Int { base, empty_int } => {
-                return if empty_int {
+                if empty_int {
                     self.sess
                         .span_diagnostic
                         .struct_span_err_with_code(
-                            self.mk_sp(start, suffix_start),
+                            self.mk_sp(start, end),
                             "no valid digits found for number",
                             error_code!(E0768),
                         )
                         .emit();
                     (token::Integer, sym::integer(0))
                 } else {
-                    self.validate_int_literal(base, start, suffix_start);
-                    (token::Integer, self.symbol_from_to(start, suffix_start))
-                };
+                    if matches!(base, Base::Binary | Base::Octal) {
+                        let base = base as u32;
+                        let s = self.str_from_to(start + BytePos(2), end);
+                        for (idx, c) in s.char_indices() {
+                            if c != '_' && c.to_digit(base).is_none() {
+                                self.err_span_(
+                                    start + BytePos::from_usize(2 + idx),
+                                    start + BytePos::from_usize(2 + idx + c.len_utf8()),
+                                    &format!("invalid digit for a base {} literal", base),
+                                );
+                            }
+                        }
+                    }
+                    (token::Integer, self.symbol_from_to(start, end))
+                }
             }
             rustc_lexer::LiteralKind::Float { base, empty_exponent } => {
                 if empty_exponent {
                     self.err_span_(start, self.pos, "expected at least one digit in exponent");
                 }
-
                 match base {
-                    Base::Hexadecimal => self.err_span_(
-                        start,
-                        suffix_start,
-                        "hexadecimal float literal is not supported",
-                    ),
+                    Base::Hexadecimal => {
+                        self.err_span_(start, end, "hexadecimal float literal is not supported")
+                    }
                     Base::Octal => {
-                        self.err_span_(start, suffix_start, "octal float literal is not supported")
+                        self.err_span_(start, end, "octal float literal is not supported")
                     }
                     Base::Binary => {
-                        self.err_span_(start, suffix_start, "binary float literal is not supported")
+                        self.err_span_(start, end, "binary float literal is not supported")
                     }
-                    _ => (),
+                    _ => {}
                 }
-
-                let id = self.symbol_from_to(start, suffix_start);
-                return (token::Float, id);
+                (token::Float, self.symbol_from_to(start, end))
             }
-        };
-        let content_start = start + BytePos(prefix_len);
-        let content_end = suffix_start - BytePos(postfix_len);
-        let id = self.symbol_from_to(content_start, content_end);
-        self.validate_literal_escape(mode, content_start, content_end, prefix_len, postfix_len);
-        (lit_kind, id)
+        }
     }
 
     #[inline]
@@ -649,20 +652,22 @@ fn report_too_many_hashes(&self, start: BytePos, found: u32) -> ! {
         )
     }
 
-    fn validate_literal_escape(
+    fn cook_quoted(
         &self,
+        kind: token::LitKind,
         mode: Mode,
-        content_start: BytePos,
-        content_end: BytePos,
+        start: BytePos,
+        end: BytePos,
         prefix_len: u32,
         postfix_len: u32,
-    ) {
+    ) -> (token::LitKind, Symbol) {
+        let content_start = start + BytePos(prefix_len);
+        let content_end = end - BytePos(postfix_len);
         let lit_content = self.str_from_to(content_start, content_end);
         unescape::unescape_literal(lit_content, mode, &mut |range, result| {
             // Here we only check for errors. The actual unescaping is done later.
             if let Err(err) = result {
-                let span_with_quotes = self
-                    .mk_sp(content_start - BytePos(prefix_len), content_end + BytePos(postfix_len));
+                let span_with_quotes = self.mk_sp(start, end);
                 let (start, end) = (range.start as u32, range.end as u32);
                 let lo = content_start + BytePos(start);
                 let hi = lo + BytePos(end - start);
@@ -678,23 +683,7 @@ fn validate_literal_escape(
                 );
             }
         });
-    }
-
-    fn validate_int_literal(&self, base: Base, content_start: BytePos, content_end: BytePos) {
-        let base = match base {
-            Base::Binary => 2,
-            Base::Octal => 8,
-            _ => return,
-        };
-        let s = self.str_from_to(content_start + BytePos(2), content_end);
-        for (idx, c) in s.char_indices() {
-            let idx = idx as u32;
-            if c != '_' && c.to_digit(base).is_none() {
-                let lo = content_start + BytePos(2 + idx);
-                let hi = content_start + BytePos(2 + idx + c.len_utf8() as u32);
-                self.err_span_(lo, hi, &format!("invalid digit for a base {} literal", base));
-            }
-        }
+        (kind, Symbol::intern(lit_content))
     }
 }
 
index f075de714267688eb0711fe0e631f14cb9c485d3..6373f5b4fd6ff36f32f99b14bd80ec9326663dfc 100644 (file)
@@ -108,7 +108,7 @@ pub(crate) fn emit_unescape_error(
             }
 
             if !has_help {
-                let (prefix, msg) = if mode.is_bytes() {
+                let (prefix, msg) = if mode.is_byte() {
                     ("b", "if you meant to write a byte string literal, use double quotes")
                 } else {
                     ("", "if you meant to write a `str` literal, use double quotes")
@@ -142,7 +142,7 @@ pub(crate) fn emit_unescape_error(
         EscapeError::EscapeOnlyChar => {
             let (c, char_span) = last_char();
 
-            let msg = if mode.is_bytes() {
+            let msg = if mode.is_byte() {
                 "byte constant must be escaped"
             } else {
                 "character constant must be escaped"
@@ -182,11 +182,11 @@ pub(crate) fn emit_unescape_error(
             let (c, span) = last_char();
 
             let label =
-                if mode.is_bytes() { "unknown byte escape" } else { "unknown character escape" };
+                if mode.is_byte() { "unknown byte escape" } else { "unknown character escape" };
             let ec = escaped_char(c);
             let mut diag = handler.struct_span_err(span, &format!("{}: `{}`", label, ec));
             diag.span_label(span, label);
-            if c == '{' || c == '}' && !mode.is_bytes() {
+            if c == '{' || c == '}' && !mode.is_byte() {
                 diag.help(
                     "if used in a formatting string, curly braces are escaped with `{{` and `}}`",
                 );
@@ -196,7 +196,7 @@ pub(crate) fn emit_unescape_error(
                      version control settings",
                 );
             } else {
-                if !mode.is_bytes() {
+                if !mode.is_byte() {
                     diag.span_suggestion(
                         span_with_quotes,
                         "if you meant to write a literal backslash (perhaps escaping in a regular expression), consider a raw string literal",
@@ -231,16 +231,23 @@ pub(crate) fn emit_unescape_error(
                 .emit();
         }
         EscapeError::NonAsciiCharInByte => {
-            assert!(mode.is_bytes());
             let (c, span) = last_char();
-            let mut err = handler.struct_span_err(span, "non-ASCII character in byte constant");
+            let desc = match mode {
+                Mode::Byte => "byte literal",
+                Mode::ByteStr => "byte string literal",
+                Mode::RawByteStr => "raw byte string literal",
+                _ => panic!("non-is_byte literal paired with NonAsciiCharInByte"),
+            };
+            let mut err = handler.struct_span_err(span, format!("non-ASCII character in {}", desc));
             let postfix = if unicode_width::UnicodeWidthChar::width(c).unwrap_or(1) == 0 {
                 format!(" but is {:?}", c)
             } else {
                 String::new()
             };
-            err.span_label(span, &format!("byte constant must be ASCII{}", postfix));
-            if (c as u32) <= 0xFF {
+            err.span_label(span, &format!("must be ASCII{}", postfix));
+            // Note: the \\xHH suggestions are not given for raw byte string
+            // literals, because they are araw and so cannot use any escapes.
+            if (c as u32) <= 0xFF && mode != Mode::RawByteStr {
                 err.span_suggestion(
                     span,
                     &format!(
@@ -250,9 +257,9 @@ pub(crate) fn emit_unescape_error(
                     format!("\\x{:X}", c as u32),
                     Applicability::MaybeIncorrect,
                 );
-            } else if matches!(mode, Mode::Byte) {
+            } else if mode == Mode::Byte {
                 err.span_label(span, "this multibyte character does not fit into a single byte");
-            } else if matches!(mode, Mode::ByteStr) {
+            } else if mode != Mode::RawByteStr {
                 let mut utf8 = String::new();
                 utf8.push(c);
                 err.span_suggestion(
@@ -270,19 +277,6 @@ pub(crate) fn emit_unescape_error(
             }
             err.emit();
         }
-        EscapeError::NonAsciiCharInByteString => {
-            assert!(mode.is_bytes());
-            let (c, span) = last_char();
-            let postfix = if unicode_width::UnicodeWidthChar::width(c).unwrap_or(1) == 0 {
-                format!(" but is {:?}", c)
-            } else {
-                String::new()
-            };
-            handler
-                .struct_span_err(span, "raw byte string must be ASCII")
-                .span_label(span, &format!("must be ASCII{}", postfix))
-                .emit();
-        }
         EscapeError::OutOfRangeHexEscape => {
             handler
                 .struct_span_err(span, "out of range hex escape")
index 1b16ecb5ec2d6434a52cfc86a5e7b9fabb966a1f..c8160548763c88420c902f4f84f2af1ef00b069b 100644 (file)
@@ -5,7 +5,8 @@
 use rustc_ast::{self as ast};
 use rustc_ast::{AttrVec, Attribute, HasAttrs, HasTokens};
 use rustc_errors::PResult;
-use rustc_span::{sym, Span};
+use rustc_session::parse::ParseSess;
+use rustc_span::{sym, Span, DUMMY_SP};
 
 use std::convert::TryInto;
 use std::ops::Range;
@@ -39,8 +40,13 @@ pub(super) fn new(attrs: AttrVec, start_pos: usize) -> AttrWrapper {
     pub fn empty() -> AttrWrapper {
         AttrWrapper { attrs: AttrVec::new(), start_pos: usize::MAX }
     }
-    // FIXME: Delay span bug here?
-    pub(crate) fn take_for_recovery(self) -> AttrVec {
+
+    pub(crate) fn take_for_recovery(self, sess: &ParseSess) -> AttrVec {
+        sess.span_diagnostic.delay_span_bug(
+            self.attrs.get(0).map(|attr| attr.span).unwrap_or(DUMMY_SP),
+            "AttrVec is taken for recovery but no error is produced",
+        );
+
         self.attrs
     }
 
index 7dc4fd0044f1ff5d3487fd8d2648e932b8e0df8c..0bbe073fe2af4621c19f95e570bdd13367249e82 100644 (file)
@@ -1653,15 +1653,29 @@ pub(super) fn recover_parens_around_for_head(
             (token::CloseDelim(Delimiter::Parenthesis), Some(begin_par_sp)) => {
                 self.bump();
 
+                let sm = self.sess.source_map();
+                let left = begin_par_sp;
+                let right = self.prev_token.span;
+                let left_snippet = if let Ok(snip) = sm.span_to_prev_source(left) &&
+                        !snip.ends_with(" ") {
+                                " ".to_string()
+                            } else {
+                                "".to_string()
+                            };
+
+                let right_snippet = if let Ok(snip) = sm.span_to_next_source(right) &&
+                        !snip.starts_with(" ") {
+                                " ".to_string()
+                            } else {
+                                "".to_string()
+                        };
+
                 self.sess.emit_err(ParenthesesInForHead {
-                    span: vec![begin_par_sp, self.prev_token.span],
+                    span: vec![left, right],
                     // With e.g. `for (x) in y)` this would replace `(x) in y)`
                     // with `x) in y)` which is syntactically invalid.
                     // However, this is prevented before we get here.
-                    sugg: ParenthesesInForHeadSugg {
-                        left: begin_par_sp,
-                        right: self.prev_token.span,
-                    },
+                    sugg: ParenthesesInForHeadSugg { left, right, left_snippet, right_snippet },
                 });
 
                 // Unwrap `(pat)` into `pat` to avoid the `unused_parens` lint.
@@ -2468,11 +2482,15 @@ pub(crate) fn maybe_recover_colon_colon_in_pat_typo(
     }
 
     pub(crate) fn maybe_recover_unexpected_block_label(&mut self) -> bool {
-        let Some(label) = self.eat_label().filter(|_| {
-            self.eat(&token::Colon) && self.token.kind == token::OpenDelim(Delimiter::Brace)
-        }) else {
+        // Check for `'a : {`
+        if !(self.check_lifetime()
+            && self.look_ahead(1, |tok| tok.kind == token::Colon)
+            && self.look_ahead(2, |tok| tok.kind == token::OpenDelim(Delimiter::Brace)))
+        {
             return false;
-        };
+        }
+        let label = self.eat_label().expect("just checked if a label exists");
+        self.bump(); // eat `:`
         let span = label.ident.span.to(self.prev_token.span);
         let mut err = self.struct_span_err(span, "block label not supported here");
         err.span_label(span, "not supported here");
index 4a1162b95998378494c7b6399ca3481a77593fc7..b072573af23f044e1e18d675984fc879697767fe 100644 (file)
@@ -9,9 +9,9 @@
     ArrayBracketsInsteadOfSpaces, ArrayBracketsInsteadOfSpacesSugg, AsyncMoveOrderIncorrect,
     BinaryFloatLiteralNotSupported, BracesForStructLiteral, CatchAfterTry, CommaAfterBaseStruct,
     ComparisonInterpretedAsGeneric, ComparisonOrShiftInterpretedAsGenericSugg,
-    DoCatchSyntaxRemoved, DotDotDot, EqFieldInit, ExpectedElseBlock, ExpectedExpressionFoundLet,
-    FieldExpressionWithGeneric, FloatLiteralRequiresIntegerPart, FoundExprWouldBeStmt,
-    HexadecimalFloatLiteralNotSupported, IfExpressionMissingCondition,
+    DoCatchSyntaxRemoved, DotDotDot, EqFieldInit, ExpectedElseBlock, ExpectedEqForLetExpr,
+    ExpectedExpressionFoundLet, FieldExpressionWithGeneric, FloatLiteralRequiresIntegerPart,
+    FoundExprWouldBeStmt, HexadecimalFloatLiteralNotSupported, IfExpressionMissingCondition,
     IfExpressionMissingThenBlock, IfExpressionMissingThenBlockSub, IntLiteralTooLarge,
     InvalidBlockMacroSegment, InvalidComparisonOperator, InvalidComparisonOperatorSub,
     InvalidFloatLiteralSuffix, InvalidFloatLiteralWidth, InvalidIntLiteralWidth,
@@ -33,6 +33,7 @@
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Delimiter, Token, TokenKind};
 use rustc_ast::tokenstream::Spacing;
+use rustc_ast::util::case::Case;
 use rustc_ast::util::classify;
 use rustc_ast::util::literal::LitError;
 use rustc_ast::util::parser::{prec_let_scrutinee_needs_par, AssocOp, Fixity};
@@ -833,16 +834,11 @@ fn parse_and_disallow_postfix_after_cast(
                 ("cast", None)
             };
 
-        // Save the memory location of expr before parsing any following postfix operators.
-        // This will be compared with the memory location of the output expression.
-        // If they different we can assume we parsed another expression because the existing expression is not reallocated.
-        let addr_before = &*cast_expr as *const _ as usize;
         let with_postfix = self.parse_dot_or_call_expr_with_(cast_expr, span)?;
-        let changed = addr_before != &*with_postfix as *const _ as usize;
 
         // Check if an illegal postfix operator has been added after the cast.
-        // If the resulting expression is not a cast, or has a different memory location, it is an illegal postfix operator.
-        if !matches!(with_postfix.kind, ExprKind::Cast(_, _) | ExprKind::Type(_, _)) || changed {
+        // If the resulting expression is not a cast, it is an illegal postfix operator.
+        if !matches!(with_postfix.kind, ExprKind::Cast(_, _) | ExprKind::Type(_, _)) {
             let msg = format!(
                 "{cast_kind} cannot be followed by {}",
                 match with_postfix.kind {
@@ -2095,7 +2091,7 @@ fn parse_closure_expr(&mut self) -> PResult<'a, P<Expr>> {
             if self.eat_keyword(kw::Static) { Movability::Static } else { Movability::Movable };
 
         let asyncness = if self.token.uninterpolated_span().rust_2018() {
-            self.parse_asyncness()
+            self.parse_asyncness(Case::Sensitive)
         } else {
             Async::No
         };
@@ -2276,7 +2272,7 @@ fn parse_if_after_cond(&mut self, lo: Span, mut cond: P<Expr>) -> PResult<'a, P<
                 self.mk_block_err(cond_span.shrink_to_hi())
             }
         } else {
-            let attrs = self.parse_outer_attributes()?.take_for_recovery(); // For recovery.
+            let attrs = self.parse_outer_attributes()?; // For recovery.
             let block = if self.check(&token::OpenDelim(Delimiter::Brace)) {
                 self.parse_block()?
             } else {
@@ -2293,7 +2289,7 @@ fn parse_if_after_cond(&mut self, lo: Span, mut cond: P<Expr>) -> PResult<'a, P<
                     })?
                 }
             };
-            self.error_on_if_block_attrs(lo, false, block.span, &attrs);
+            self.error_on_if_block_attrs(lo, false, block.span, attrs);
             block
         };
         let els = if self.eat_keyword(kw::Else) { Some(self.parse_else_expr()?) } else { None };
@@ -2334,7 +2330,15 @@ fn parse_let_expr(&mut self) -> PResult<'a, P<Expr>> {
             RecoverColon::Yes,
             CommaRecoveryMode::LikelyTuple,
         )?;
-        self.expect(&token::Eq)?;
+        if self.token == token::EqEq {
+            self.sess.emit_err(ExpectedEqForLetExpr {
+                span: self.token.span,
+                sugg_span: self.token.span,
+            });
+            self.bump();
+        } else {
+            self.expect(&token::Eq)?;
+        }
         let expr = self.with_res(self.restrictions | Restrictions::NO_STRUCT_LITERAL, |this| {
             this.parse_assoc_expr_with(1 + prec_let_scrutinee_needs_par(), None.into())
         })?;
@@ -2346,7 +2350,7 @@ fn parse_let_expr(&mut self) -> PResult<'a, P<Expr>> {
     /// Parses an `else { ... }` expression (`else` token already eaten).
     fn parse_else_expr(&mut self) -> PResult<'a, P<Expr>> {
         let else_span = self.prev_token.span; // `else`
-        let attrs = self.parse_outer_attributes()?.take_for_recovery(); // For recovery.
+        let attrs = self.parse_outer_attributes()?; // For recovery.
         let expr = if self.eat_keyword(kw::If) {
             self.parse_if_expr()?
         } else if self.check(&TokenKind::OpenDelim(Delimiter::Brace)) {
@@ -2381,7 +2385,7 @@ fn parse_else_expr(&mut self) -> PResult<'a, P<Expr>> {
                 },
             }
         };
-        self.error_on_if_block_attrs(else_span, true, expr.span, &attrs);
+        self.error_on_if_block_attrs(else_span, true, expr.span, attrs);
         Ok(expr)
     }
 
@@ -2390,8 +2394,13 @@ fn error_on_if_block_attrs(
         ctx_span: Span,
         is_ctx_else: bool,
         branch_span: Span,
-        attrs: &[ast::Attribute],
+        attrs: AttrWrapper,
     ) {
+        if attrs.is_empty() {
+            return;
+        }
+
+        let attrs: &[ast::Attribute] = &attrs.take_for_recovery(self.sess);
         let (attributes, last) = match attrs {
             [] => return,
             [x0 @ xn] | [x0, .., xn] => (x0.span.to(xn.span), xn.span),
index bda301c52e9603061c215e18e8c5cb9df1acb5cc..494f0cf56a80f6c82f8dc5fe408f5dde81b8c25d 100644 (file)
@@ -8,6 +8,7 @@
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Delimiter, TokenKind};
 use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree};
+use rustc_ast::util::case::Case;
 use rustc_ast::{self as ast, AttrVec, Attribute, DUMMY_NODE_ID};
 use rustc_ast::{Async, Const, Defaultness, IsAuto, Mutability, Unsafe, UseTree, UseTreeKind};
 use rustc_ast::{BindingAnnotation, Block, FnDecl, FnSig, Param, SelfKind};
@@ -34,7 +35,7 @@ pub fn parse_crate_mod(&mut self) -> PResult<'a, ast::Crate> {
 
     /// Parses a `mod <foo> { ... }` or `mod <foo>;` item.
     fn parse_item_mod(&mut self, attrs: &mut AttrVec) -> PResult<'a, ItemInfo> {
-        let unsafety = self.parse_unsafety();
+        let unsafety = self.parse_unsafety(Case::Sensitive);
         self.expect_keyword(kw::Mod)?;
         let id = self.parse_ident()?;
         let mod_kind = if self.eat(&token::Semi) {
@@ -143,8 +144,15 @@ fn parse_item_common_(
         let lo = self.token.span;
         let vis = self.parse_visibility(FollowedByType::No)?;
         let mut def = self.parse_defaultness();
-        let kind =
-            self.parse_item_kind(&mut attrs, mac_allowed, lo, &vis, &mut def, fn_parse_mode)?;
+        let kind = self.parse_item_kind(
+            &mut attrs,
+            mac_allowed,
+            lo,
+            &vis,
+            &mut def,
+            fn_parse_mode,
+            Case::Sensitive,
+        )?;
         if let Some((ident, kind)) = kind {
             self.error_on_unconsumed_default(def, &kind);
             let span = lo.to(self.prev_token.span);
@@ -205,16 +213,17 @@ fn parse_item_kind(
         vis: &Visibility,
         def: &mut Defaultness,
         fn_parse_mode: FnParseMode,
+        case: Case,
     ) -> PResult<'a, Option<ItemInfo>> {
         let def_final = def == &Defaultness::Final;
-        let mut def = || mem::replace(def, Defaultness::Final);
+        let mut def_ = || mem::replace(def, Defaultness::Final);
 
-        let info = if self.eat_keyword(kw::Use) {
+        let info = if self.eat_keyword_case(kw::Use, case) {
             self.parse_use_item()?
-        } else if self.check_fn_front_matter(def_final) {
+        } else if self.check_fn_front_matter(def_final, case) {
             // FUNCTION ITEM
             let (ident, sig, generics, body) = self.parse_fn(attrs, fn_parse_mode, lo, vis)?;
-            (ident, ItemKind::Fn(Box::new(Fn { defaultness: def(), sig, generics, body })))
+            (ident, ItemKind::Fn(Box::new(Fn { defaultness: def_(), sig, generics, body })))
         } else if self.eat_keyword(kw::Extern) {
             if self.eat_keyword(kw::Crate) {
                 // EXTERN CRATE
@@ -225,7 +234,7 @@ fn parse_item_kind(
             }
         } else if self.is_unsafe_foreign_mod() {
             // EXTERN BLOCK
-            let unsafety = self.parse_unsafety();
+            let unsafety = self.parse_unsafety(Case::Sensitive);
             self.expect_keyword(kw::Extern)?;
             self.parse_item_foreign_mod(attrs, unsafety)?
         } else if self.is_static_global() {
@@ -234,15 +243,15 @@ fn parse_item_kind(
             let m = self.parse_mutability();
             let (ident, ty, expr) = self.parse_item_global(Some(m))?;
             (ident, ItemKind::Static(ty, m, expr))
-        } else if let Const::Yes(const_span) = self.parse_constness() {
+        } else if let Const::Yes(const_span) = self.parse_constness(Case::Sensitive) {
             // CONST ITEM
             if self.token.is_keyword(kw::Impl) {
                 // recover from `const impl`, suggest `impl const`
-                self.recover_const_impl(const_span, attrs, def())?
+                self.recover_const_impl(const_span, attrs, def_())?
             } else {
                 self.recover_const_mut(const_span);
                 let (ident, ty, expr) = self.parse_item_global(None)?;
-                (ident, ItemKind::Const(def(), ty, expr))
+                (ident, ItemKind::Const(def_(), ty, expr))
             }
         } else if self.check_keyword(kw::Trait) || self.check_auto_or_unsafe_trait_item() {
             // TRAIT ITEM
@@ -251,7 +260,7 @@ fn parse_item_kind(
             || self.check_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Impl])
         {
             // IMPL ITEM
-            self.parse_item_impl(attrs, def())?
+            self.parse_item_impl(attrs, def_())?
         } else if self.check_keyword(kw::Mod)
             || self.check_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Mod])
         {
@@ -259,7 +268,7 @@ fn parse_item_kind(
             self.parse_item_mod(attrs)?
         } else if self.eat_keyword(kw::Type) {
             // TYPE ITEM
-            self.parse_type_alias(def())?
+            self.parse_type_alias(def_())?
         } else if self.eat_keyword(kw::Enum) {
             // ENUM ITEM
             self.parse_item_enum()?
@@ -286,6 +295,19 @@ fn parse_item_kind(
         } else if self.isnt_macro_invocation() && vis.kind.is_pub() {
             self.recover_missing_kw_before_item()?;
             return Ok(None);
+        } else if self.isnt_macro_invocation() && case == Case::Sensitive {
+            _ = def_;
+
+            // Recover wrong cased keywords
+            return self.parse_item_kind(
+                attrs,
+                macros_allowed,
+                lo,
+                vis,
+                def,
+                fn_parse_mode,
+                Case::Insensitive,
+            );
         } else if macros_allowed && self.check_path() {
             // MACRO INVOCATION ITEM
             (Ident::empty(), ItemKind::MacCall(P(self.parse_item_macro(vis)?)))
@@ -538,7 +560,7 @@ fn parse_item_impl(
         attrs: &mut AttrVec,
         defaultness: Defaultness,
     ) -> PResult<'a, ItemInfo> {
-        let unsafety = self.parse_unsafety();
+        let unsafety = self.parse_unsafety(Case::Sensitive);
         self.expect_keyword(kw::Impl)?;
 
         // First, parse generic parameters if necessary.
@@ -552,7 +574,7 @@ fn parse_item_impl(
             generics
         };
 
-        let constness = self.parse_constness();
+        let constness = self.parse_constness(Case::Sensitive);
         if let Const::Yes(span) = constness {
             self.sess.gated_spans.gate(sym::const_trait_impl, span);
         }
@@ -796,7 +818,7 @@ fn check_auto_or_unsafe_trait_item(&mut self) -> bool {
 
     /// Parses `unsafe? auto? trait Foo { ... }` or `trait Foo = Bar;`.
     fn parse_item_trait(&mut self, attrs: &mut AttrVec, lo: Span) -> PResult<'a, ItemInfo> {
-        let unsafety = self.parse_unsafety();
+        let unsafety = self.parse_unsafety(Case::Sensitive);
         // Parse optional `auto` prefix.
         let is_auto = if self.eat_keyword(kw::Auto) { IsAuto::Yes } else { IsAuto::No };
 
@@ -971,6 +993,23 @@ fn parse_use_tree(&mut self) -> PResult<'a, UseTree> {
             if self.eat(&token::ModSep) {
                 self.parse_use_tree_glob_or_nested()?
             } else {
+                // Recover from using a colon as path separator.
+                while self.eat_noexpect(&token::Colon) {
+                    self.struct_span_err(self.prev_token.span, "expected `::`, found `:`")
+                        .span_suggestion_short(
+                            self.prev_token.span,
+                            "use double colon",
+                            "::",
+                            Applicability::MachineApplicable,
+                        )
+                        .note_once("import paths are delimited using `::`")
+                        .emit();
+
+                    // We parse the rest of the path and append it to the original prefix.
+                    self.parse_path_segments(&mut prefix.segments, PathStyle::Mod, None)?;
+                    prefix.span = lo.to(self.prev_token.span);
+                }
+
                 UseTreeKind::Simple(self.parse_rename()?, DUMMY_NODE_ID, DUMMY_NODE_ID)
             }
         };
@@ -1745,7 +1784,7 @@ fn parse_field_ident(&mut self, adt_ty: &str, lo: Span) -> PResult<'a, Ident> {
         let (ident, is_raw) = self.ident_or_err()?;
         if !is_raw && ident.is_reserved() {
             let snapshot = self.create_snapshot_for_diagnostic();
-            let err = if self.check_fn_front_matter(false) {
+            let err = if self.check_fn_front_matter(false, Case::Sensitive) {
                 let inherited_vis = Visibility {
                     span: rustc_span::DUMMY_SP,
                     kind: VisibilityKind::Inherited,
@@ -2155,7 +2194,7 @@ fn parse_fn_body(
     ///
     /// `check_pub` adds additional `pub` to the checks in case users place it
     /// wrongly, can be used to ensure `pub` never comes after `default`.
-    pub(super) fn check_fn_front_matter(&mut self, check_pub: bool) -> bool {
+    pub(super) fn check_fn_front_matter(&mut self, check_pub: bool, case: Case) -> bool {
         // We use an over-approximation here.
         // `const const`, `fn const` won't parse, but we're not stepping over other syntax either.
         // `pub` is added in case users got confused with the ordering like `async pub fn`,
@@ -2165,23 +2204,30 @@ pub(super) fn check_fn_front_matter(&mut self, check_pub: bool) -> bool {
         } else {
             &[kw::Const, kw::Async, kw::Unsafe, kw::Extern]
         };
-        self.check_keyword(kw::Fn) // Definitely an `fn`.
+        self.check_keyword_case(kw::Fn, case) // Definitely an `fn`.
             // `$qual fn` or `$qual $qual`:
-            || quals.iter().any(|&kw| self.check_keyword(kw))
+            || quals.iter().any(|&kw| self.check_keyword_case(kw, case))
                 && self.look_ahead(1, |t| {
                     // `$qual fn`, e.g. `const fn` or `async fn`.
-                    t.is_keyword(kw::Fn)
+                    t.is_keyword_case(kw::Fn, case)
                     // Two qualifiers `$qual $qual` is enough, e.g. `async unsafe`.
-                    || t.is_non_raw_ident_where(|i| quals.contains(&i.name)
-                        // Rule out 2015 `const async: T = val`.
-                        && i.is_reserved()
+                    || (
+                        (
+                            t.is_non_raw_ident_where(|i|
+                                quals.contains(&i.name)
+                                    // Rule out 2015 `const async: T = val`.
+                                    && i.is_reserved()
+                            )
+                            || case == Case::Insensitive
+                                && t.is_non_raw_ident_where(|i| quals.iter().any(|qual| qual.as_str() == i.name.as_str().to_lowercase()))
+                        )
                         // Rule out unsafe extern block.
                         && !self.is_unsafe_foreign_mod())
                 })
             // `extern ABI fn`
-            || self.check_keyword(kw::Extern)
+            || self.check_keyword_case(kw::Extern, case)
                 && self.look_ahead(1, |t| t.can_begin_literal_maybe_minus())
-                && self.look_ahead(2, |t| t.is_keyword(kw::Fn))
+                && self.look_ahead(2, |t| t.is_keyword_case(kw::Fn, case))
     }
 
     /// Parses all the "front matter" (or "qualifiers") for a `fn` declaration,
@@ -2197,22 +2243,22 @@ pub(super) fn check_fn_front_matter(&mut self, check_pub: bool) -> bool {
     /// `Visibility::Inherited` when no visibility is known.
     pub(super) fn parse_fn_front_matter(&mut self, orig_vis: &Visibility) -> PResult<'a, FnHeader> {
         let sp_start = self.token.span;
-        let constness = self.parse_constness();
+        let constness = self.parse_constness(Case::Insensitive);
 
         let async_start_sp = self.token.span;
-        let asyncness = self.parse_asyncness();
+        let asyncness = self.parse_asyncness(Case::Insensitive);
 
         let unsafe_start_sp = self.token.span;
-        let unsafety = self.parse_unsafety();
+        let unsafety = self.parse_unsafety(Case::Insensitive);
 
         let ext_start_sp = self.token.span;
-        let ext = self.parse_extern();
+        let ext = self.parse_extern(Case::Insensitive);
 
         if let Async::Yes { span, .. } = asyncness {
             self.ban_async_in_2015(span);
         }
 
-        if !self.eat_keyword(kw::Fn) {
+        if !self.eat_keyword_case(kw::Fn, Case::Insensitive) {
             // It is possible for `expect_one_of` to recover given the contents of
             // `self.expected_tokens`, therefore, do not use `self.unexpected()` which doesn't
             // account for this.
index 2e59c005e315ae21e5bfa0510fe11545a20cfa6f..14dc490fb0232615d377f4ef975264648a3bca8f 100644 (file)
@@ -22,6 +22,7 @@
 use rustc_ast::tokenstream::AttributesData;
 use rustc_ast::tokenstream::{self, DelimSpan, Spacing};
 use rustc_ast::tokenstream::{TokenStream, TokenTree};
+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, Extern};
@@ -636,6 +637,20 @@ fn check_keyword(&mut self, kw: Symbol) -> bool {
         self.token.is_keyword(kw)
     }
 
+    fn check_keyword_case(&mut self, kw: Symbol, case: Case) -> bool {
+        if self.check_keyword(kw) {
+            return true;
+        }
+
+        if case == Case::Insensitive
+        && let Some((ident, /* is_raw */ false)) = self.token.ident()
+        && ident.as_str().to_lowercase() == kw.as_str().to_lowercase() {
+            true
+        } else {
+            false
+        }
+    }
+
     /// If the next token is the given keyword, eats it and returns `true`.
     /// Otherwise, returns `false`. An expectation is also added for diagnostics purposes.
     // Public for rustfmt usage.
@@ -648,6 +663,33 @@ pub fn eat_keyword(&mut self, kw: Symbol) -> bool {
         }
     }
 
+    /// Eats a keyword, optionally ignoring the case.
+    /// If the case differs (and is ignored) an error is issued.
+    /// This is useful for recovery.
+    fn eat_keyword_case(&mut self, kw: Symbol, case: Case) -> bool {
+        if self.eat_keyword(kw) {
+            return true;
+        }
+
+        if case == Case::Insensitive
+        && let Some((ident, /* is_raw */ false)) = self.token.ident()
+        && ident.as_str().to_lowercase() == kw.as_str().to_lowercase() {
+            self
+                .struct_span_err(ident.span, format!("keyword `{kw}` is written in a wrong case"))
+                .span_suggestion(
+                    ident.span,
+                    "write it in the correct case",
+                    kw,
+                    Applicability::MachineApplicable
+                ).emit();
+
+            self.bump();
+            return true;
+        }
+
+        false
+    }
+
     fn eat_keyword_noexpect(&mut self, kw: Symbol) -> bool {
         if self.token.is_keyword(kw) {
             self.bump();
@@ -1127,8 +1169,8 @@ fn is_keyword_ahead(&self, dist: usize, kws: &[Symbol]) -> bool {
     }
 
     /// Parses asyncness: `async` or nothing.
-    fn parse_asyncness(&mut self) -> Async {
-        if self.eat_keyword(kw::Async) {
+    fn parse_asyncness(&mut self, case: Case) -> Async {
+        if self.eat_keyword_case(kw::Async, case) {
             let span = self.prev_token.uninterpolated_span();
             Async::Yes { span, closure_id: DUMMY_NODE_ID, return_impl_trait_id: DUMMY_NODE_ID }
         } else {
@@ -1137,8 +1179,8 @@ fn parse_asyncness(&mut self) -> Async {
     }
 
     /// Parses unsafety: `unsafe` or nothing.
-    fn parse_unsafety(&mut self) -> Unsafe {
-        if self.eat_keyword(kw::Unsafe) {
+    fn parse_unsafety(&mut self, case: Case) -> Unsafe {
+        if self.eat_keyword_case(kw::Unsafe, case) {
             Unsafe::Yes(self.prev_token.uninterpolated_span())
         } else {
             Unsafe::No
@@ -1146,10 +1188,10 @@ fn parse_unsafety(&mut self) -> Unsafe {
     }
 
     /// Parses constness: `const` or nothing.
-    fn parse_constness(&mut self) -> Const {
+    fn parse_constness(&mut self, case: Case) -> Const {
         // Avoid const blocks to be parsed as const items
         if self.look_ahead(1, |t| t != &token::OpenDelim(Delimiter::Brace))
-            && self.eat_keyword(kw::Const)
+            && self.eat_keyword_case(kw::Const, case)
         {
             Const::Yes(self.prev_token.uninterpolated_span())
         } else {
@@ -1404,8 +1446,8 @@ fn recover_incorrect_vis_restriction(&mut self) -> PResult<'a, ()> {
     }
 
     /// Parses `extern string_literal?`.
-    fn parse_extern(&mut self) -> Extern {
-        if self.eat_keyword(kw::Extern) {
+    fn parse_extern(&mut self, case: Case) -> Extern {
+        if self.eat_keyword_case(kw::Extern, case) {
             let mut extern_span = self.prev_token.span;
             let abi = self.parse_abi();
             if let Some(abi) = abi {
index fdc1af27f82e4206e3e7d95eec13f6ffb59a4a92..d46565dea893119d48736a56d5ac8190ac79285a 100644 (file)
@@ -631,7 +631,9 @@ fn parse_assoc_equality_term(
     /// - A single-segment path.
     pub(super) fn expr_is_valid_const_arg(&self, expr: &P<rustc_ast::Expr>) -> bool {
         match &expr.kind {
-            ast::ExprKind::Block(_, _) | ast::ExprKind::Lit(_) => true,
+            ast::ExprKind::Block(_, _)
+            | ast::ExprKind::Lit(_)
+            | ast::ExprKind::IncludedBytes(..) => true,
             ast::ExprKind::Unary(ast::UnOp::Neg, expr) => {
                 matches!(expr.kind, ast::ExprKind::Lit(_))
             }
index 12753c6785c9aa5ecb2c5a9a78946c3b382cec47..9684145ad99482cf16b0e0b39485f63b8e37be7d 100644 (file)
@@ -19,7 +19,7 @@
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Delimiter, TokenKind};
 use rustc_ast::util::classify;
-use rustc_ast::{AttrStyle, AttrVec, Attribute, LocalKind, MacCall, MacCallStmt, MacStmtStyle};
+use rustc_ast::{AttrStyle, AttrVec, LocalKind, MacCall, MacCallStmt, MacStmtStyle};
 use rustc_ast::{Block, BlockCheckMode, Expr, ExprKind, HasAttrs, Local, Stmt};
 use rustc_ast::{StmtKind, DUMMY_NODE_ID};
 use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult};
@@ -101,7 +101,7 @@ pub(crate) fn parse_stmt_without_recovery(
             self.mk_stmt(lo.to(item.span), StmtKind::Item(P(item)))
         } else if self.eat(&token::Semi) {
             // Do not attempt to parse an expression if we're done here.
-            self.error_outer_attrs(&attrs.take_for_recovery());
+            self.error_outer_attrs(attrs);
             self.mk_stmt(lo, StmtKind::Empty)
         } else if self.token != token::CloseDelim(Delimiter::Brace) {
             // Remainder are line-expr stmts.
@@ -120,7 +120,7 @@ pub(crate) fn parse_stmt_without_recovery(
             }
             self.mk_stmt(lo.to(e.span), StmtKind::Expr(e))
         } else {
-            self.error_outer_attrs(&attrs.take_for_recovery());
+            self.error_outer_attrs(attrs);
             return Ok(None);
         }))
     }
@@ -199,8 +199,10 @@ fn parse_stmt_mac(&mut self, lo: Span, attrs: AttrVec, path: ast::Path) -> PResu
 
     /// Error on outer attributes in this context.
     /// Also error if the previous token was a doc comment.
-    fn error_outer_attrs(&self, attrs: &[Attribute]) {
-        if let [.., last] = attrs {
+    fn error_outer_attrs(&self, attrs: AttrWrapper) {
+        if !attrs.is_empty()
+        && let attrs = attrs.take_for_recovery(self.sess)
+        && let attrs @ [.., last] = &*attrs {
             if last.is_doc_comment() {
                 self.sess.emit_err(DocCommentDoesNotDocumentAnything {
                     span: last.span,
index 2a8512acf8cfac886ada546e0b01a72c387e99fb..4d78c5bd0e2734916f614aabb3527197e478c338 100644 (file)
@@ -4,6 +4,7 @@
 
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Delimiter, Token, TokenKind};
+use rustc_ast::util::case::Case;
 use rustc_ast::{
     self as ast, BareFnTy, FnRetTy, GenericBound, GenericBounds, GenericParam, Generics, Lifetime,
     MacCall, MutTy, Mutability, PolyTraitRef, TraitBoundModifier, TraitObjectSyntax, Ty, TyKind,
@@ -267,7 +268,7 @@ fn parse_ty_common(
         } else if self.eat_keyword(kw::Underscore) {
             // A type to be inferred `_`
             TyKind::Infer
-        } else if self.check_fn_front_matter(false) {
+        } else if self.check_fn_front_matter(false, Case::Sensitive) {
             // Function pointer type
             self.parse_ty_bare_fn(lo, Vec::new(), recover_return_sign)?
         } else if self.check_keyword(kw::For) {
@@ -275,7 +276,7 @@ fn parse_ty_common(
             //   `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T`
             //   `for<'lt> Trait1<'lt> + Trait2 + 'a`
             let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
-            if self.check_fn_front_matter(false) {
+            if self.check_fn_front_matter(false, Case::Sensitive) {
                 self.parse_ty_bare_fn(lo, lifetime_defs, recover_return_sign)?
             } else {
                 let path = self.parse_path(PathStyle::Type)?;
@@ -401,7 +402,7 @@ fn parse_ty_ptr(&mut self) -> PResult<'a, TyKind> {
                 .span_suggestions(
                     span.shrink_to_hi(),
                     "add `mut` or `const` here",
-                    ["mut ".to_string(), "const ".to_string()].into_iter(),
+                    ["mut ".to_string(), "const ".to_string()],
                     Applicability::HasPlaceholders,
                 )
                 .emit();
index 1394993abade94013f6e66849f9ba00aa6aff02d..54bf4d1d6b7381469d276d77b0ee66afa1663963 100644 (file)
@@ -819,19 +819,19 @@ fn find_skips_from_snippet(
     };
 
     fn find_skips(snippet: &str, is_raw: bool) -> Vec<usize> {
-        let mut s = snippet.char_indices().peekable();
+        let mut s = snippet.char_indices();
         let mut skips = vec![];
         while let Some((pos, c)) = s.next() {
-            match (c, s.peek()) {
+            match (c, s.clone().next()) {
                 // skip whitespace and empty lines ending in '\\'
                 ('\\', Some((next_pos, '\n'))) if !is_raw => {
                     skips.push(pos);
-                    skips.push(*next_pos);
+                    skips.push(next_pos);
                     let _ = s.next();
 
-                    while let Some((pos, c)) = s.peek() {
+                    while let Some((pos, c)) = s.clone().next() {
                         if matches!(c, ' ' | '\n' | '\t') {
-                            skips.push(*pos);
+                            skips.push(pos);
                             let _ = s.next();
                         } else {
                             break;
@@ -839,7 +839,7 @@ fn find_skips(snippet: &str, is_raw: bool) -> Vec<usize> {
                     }
                 }
                 ('\\', Some((next_pos, 'n' | 't' | 'r' | '0' | '\\' | '\'' | '\"'))) => {
-                    skips.push(*next_pos);
+                    skips.push(next_pos);
                     let _ = s.next();
                 }
                 ('\\', Some((_, 'x'))) if !is_raw => {
@@ -858,19 +858,30 @@ fn find_skips(snippet: &str, is_raw: bool) -> Vec<usize> {
                     }
                     if let Some((next_pos, next_c)) = s.next() {
                         if next_c == '{' {
-                            skips.push(next_pos);
-                            let mut i = 0; // consume up to 6 hexanumeric chars + closing `}`
-                            while let (Some((next_pos, c)), true) = (s.next(), i < 7) {
-                                if c.is_digit(16) {
-                                    skips.push(next_pos);
-                                } else if c == '}' {
-                                    skips.push(next_pos);
-                                    break;
-                                } else {
-                                    break;
-                                }
-                                i += 1;
+                            // consume up to 6 hexanumeric chars
+                            let digits_len =
+                                s.clone().take(6).take_while(|(_, c)| c.is_digit(16)).count();
+
+                            let len_utf8 = s
+                                .as_str()
+                                .get(..digits_len)
+                                .and_then(|digits| u32::from_str_radix(digits, 16).ok())
+                                .and_then(char::from_u32)
+                                .map_or(1, char::len_utf8);
+
+                            // Skip the digits, for chars that encode to more than 1 utf-8 byte
+                            // exclude as many digits as it is greater than 1 byte
+                            //
+                            // So for a 3 byte character, exclude 2 digits
+                            let required_skips =
+                                digits_len.saturating_sub(len_utf8.saturating_sub(1));
+
+                            // skip '{' and '}' also
+                            for pos in (next_pos..).take(required_skips + 2) {
+                                skips.push(pos)
                             }
+
+                            s.nth(digits_len);
                         } else if next_c.is_digit(16) {
                             skips.push(next_pos);
                             // We suggest adding `{` and `}` when appropriate, accept it here as if
index 27a57adf964a30765ee67a9801b18e88d38e9ec6..2b6ff0a5cb9d38ce25a35bbbd871e27dc904cbfc 100644 (file)
@@ -119,13 +119,13 @@ fn check_attributes(
                 }
                 sym::naked => self.check_naked(hir_id, attr, span, target),
                 sym::rustc_legacy_const_generics => {
-                    self.check_rustc_legacy_const_generics(&attr, span, target, item)
+                    self.check_rustc_legacy_const_generics(hir_id, &attr, span, target, item)
                 }
                 sym::rustc_lint_query_instability => {
-                    self.check_rustc_lint_query_instability(&attr, span, target)
+                    self.check_rustc_lint_query_instability(hir_id, &attr, span, target)
                 }
                 sym::rustc_lint_diagnostics => {
-                    self.check_rustc_lint_diagnostics(&attr, span, target)
+                    self.check_rustc_lint_diagnostics(hir_id, &attr, span, target)
                 }
                 sym::rustc_lint_opt_ty => self.check_rustc_lint_opt_ty(&attr, span, target),
                 sym::rustc_lint_opt_deny_field_access => {
@@ -135,11 +135,13 @@ fn check_attributes(
                 | sym::rustc_dirty
                 | sym::rustc_if_this_changed
                 | sym::rustc_then_this_would_need => self.check_rustc_dirty_clean(&attr),
-                sym::cmse_nonsecure_entry => self.check_cmse_nonsecure_entry(attr, span, target),
+                sym::cmse_nonsecure_entry => {
+                    self.check_cmse_nonsecure_entry(hir_id, attr, span, target)
+                }
                 sym::collapse_debuginfo => self.check_collapse_debuginfo(attr, span, target),
                 sym::const_trait => self.check_const_trait(attr, span, target),
                 sym::must_not_suspend => self.check_must_not_suspend(&attr, span, target),
-                sym::must_use => self.check_must_use(hir_id, &attr, span, target),
+                sym::must_use => self.check_must_use(hir_id, &attr, target),
                 sym::rustc_pass_by_value => self.check_pass_by_value(&attr, span, target),
                 sym::rustc_allow_incoherent_impl => {
                     self.check_allow_incoherent_impl(&attr, span, target)
@@ -386,6 +388,7 @@ fn check_naked(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Targe
                 self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToFn {
                     attr_span: attr.span,
                     defn_span: span,
+                    on_crate: hir_id == CRATE_HIR_ID,
                 });
                 false
             }
@@ -393,7 +396,13 @@ fn check_naked(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Targe
     }
 
     /// Checks if `#[cmse_nonsecure_entry]` is applied to a function definition.
-    fn check_cmse_nonsecure_entry(&self, attr: &Attribute, span: Span, target: Target) -> bool {
+    fn check_cmse_nonsecure_entry(
+        &self,
+        hir_id: HirId,
+        attr: &Attribute,
+        span: Span,
+        target: Target,
+    ) -> bool {
         match target {
             Target::Fn
             | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true,
@@ -401,6 +410,7 @@ fn check_cmse_nonsecure_entry(&self, attr: &Attribute, span: Span, target: Targe
                 self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToFn {
                     attr_span: attr.span,
                     defn_span: span,
+                    on_crate: hir_id == CRATE_HIR_ID,
                 });
                 false
             }
@@ -465,9 +475,11 @@ fn check_track_caller(
                 true
             }
             _ => {
-                self.tcx
-                    .sess
-                    .emit_err(errors::TrackedCallerWrongLocation { attr_span, defn_span: span });
+                self.tcx.sess.emit_err(errors::TrackedCallerWrongLocation {
+                    attr_span,
+                    defn_span: span,
+                    on_crate: hir_id == CRATE_HIR_ID,
+                });
                 false
             }
         }
@@ -576,6 +588,7 @@ fn check_target_feature(
                 self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToFn {
                     attr_span: attr.span,
                     defn_span: span,
+                    on_crate: hir_id == CRATE_HIR_ID,
                 });
                 false
             }
@@ -1163,17 +1176,7 @@ fn check_has_incoherent_inherent_impls(
     }
 
     /// Warns against some misuses of `#[must_use]`
-    fn check_must_use(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool {
-        let node = self.tcx.hir().get(hir_id);
-        if let Some(kind) = node.fn_kind() && let rustc_hir::IsAsync::Async = kind.asyncness() {
-            self.tcx.emit_spanned_lint(
-                UNUSED_ATTRIBUTES,
-                hir_id,
-                attr.span,
-                errors::MustUseAsync { span }
-            );
-        }
-
+    fn check_must_use(&self, hir_id: HirId, attr: &Attribute, target: Target) -> bool {
         if !matches!(
             target,
             Target::Fn
@@ -1240,7 +1243,7 @@ fn check_cold(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target
                     UNUSED_ATTRIBUTES,
                     hir_id,
                     attr.span,
-                    errors::Cold { span },
+                    errors::Cold { span, on_crate: hir_id == CRATE_HIR_ID },
                 );
             }
         }
@@ -1376,6 +1379,7 @@ fn check_rustc_layout_scalar_valid_range(
     /// Checks if `#[rustc_legacy_const_generics]` is applied to a function and has a valid argument.
     fn check_rustc_legacy_const_generics(
         &self,
+        hir_id: HirId,
         attr: &Attribute,
         span: Span,
         target: Target,
@@ -1386,6 +1390,7 @@ fn check_rustc_legacy_const_generics(
             self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToFn {
                 attr_span: attr.span,
                 defn_span: span,
+                on_crate: hir_id == CRATE_HIR_ID,
             });
             return false;
         }
@@ -1450,12 +1455,19 @@ fn check_rustc_legacy_const_generics(
 
     /// Helper function for checking that the provided attribute is only applied to a function or
     /// method.
-    fn check_applied_to_fn_or_method(&self, attr: &Attribute, span: Span, target: Target) -> bool {
+    fn check_applied_to_fn_or_method(
+        &self,
+        hir_id: HirId,
+        attr: &Attribute,
+        span: Span,
+        target: Target,
+    ) -> bool {
         let is_function = matches!(target, Target::Fn | Target::Method(..));
         if !is_function {
             self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToFn {
                 attr_span: attr.span,
                 defn_span: span,
+                on_crate: hir_id == CRATE_HIR_ID,
             });
             false
         } else {
@@ -1467,17 +1479,24 @@ fn check_applied_to_fn_or_method(&self, attr: &Attribute, span: Span, target: Ta
     /// or method.
     fn check_rustc_lint_query_instability(
         &self,
+        hir_id: HirId,
         attr: &Attribute,
         span: Span,
         target: Target,
     ) -> bool {
-        self.check_applied_to_fn_or_method(attr, span, target)
+        self.check_applied_to_fn_or_method(hir_id, attr, span, target)
     }
 
     /// Checks that the `#[rustc_lint_diagnostics]` attribute is only applied to a function or
     /// method.
-    fn check_rustc_lint_diagnostics(&self, attr: &Attribute, span: Span, target: Target) -> bool {
-        self.check_applied_to_fn_or_method(attr, span, target)
+    fn check_rustc_lint_diagnostics(
+        &self,
+        hir_id: HirId,
+        attr: &Attribute,
+        span: Span,
+        target: Target,
+    ) -> bool {
+        self.check_applied_to_fn_or_method(hir_id, attr, span, target)
     }
 
     /// Checks that the `#[rustc_lint_opt_ty]` attribute is only applied to a struct.
index 1dbf0d642e2afdbbea56d0d49801ace8fb040199..c6cd69add28a04837c20fa0640419cee5ccb7af7 100644 (file)
@@ -81,6 +81,7 @@ pub struct AttrShouldBeAppliedToFn {
     pub attr_span: Span,
     #[label]
     pub defn_span: Span,
+    pub on_crate: bool,
 }
 
 #[derive(Diagnostic)]
@@ -97,6 +98,7 @@ pub struct TrackedCallerWrongLocation {
     pub attr_span: Span,
     #[label]
     pub defn_span: Span,
+    pub on_crate: bool,
 }
 
 #[derive(Diagnostic)]
@@ -367,6 +369,7 @@ pub struct MustNotSuspend {
 pub struct Cold {
     #[label]
     pub span: Span,
+    pub on_crate: bool,
 }
 
 #[derive(LintDiagnostic)]
index 33220fd2b395dd0c32de941878104d5728d91f50..140f02c046a66c3b48d82f9a3f28acc42b3e24a5 100644 (file)
@@ -560,13 +560,14 @@ fn visit_pat(&mut self, p: &'v ast::Pat) {
     }
 
     fn visit_expr(&mut self, e: &'v ast::Expr) {
+        #[rustfmt::skip]
         record_variants!(
             (self, e, e.kind, Id::None, ast, Expr, ExprKind),
             [
                 Box, Array, ConstBlock, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type, Let,
                 If, While, ForLoop, Loop, Match, Closure, Block, Async, Await, TryBlock, Assign,
                 AssignOp, Field, Index, Range, Underscore, Path, AddrOf, Break, Continue, Ret,
-                InlineAsm, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet, Err
+                InlineAsm, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet, IncludedBytes, Err
             ]
         );
         ast_visit::walk_expr(self, e)
index c6fe40f72fc634c4994661be8952e24018b7e4eb..c181de48a9ad8fb9b0053e1a38347f06c8104aa4 100644 (file)
@@ -87,6 +87,7 @@
 use rustc_ast::InlineAsmOptions;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::Applicability;
+use rustc_errors::Diagnostic;
 use rustc_hir as hir;
 use rustc_hir::def::*;
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -1690,7 +1691,7 @@ fn has_added_lit_match_name_span(
         &self,
         name: &str,
         opt_body: Option<&hir::Body<'_>>,
-        err: &mut rustc_errors::DiagnosticBuilder<'_, ()>,
+        err: &mut Diagnostic,
     ) -> bool {
         let mut has_litstring = false;
         let Some(opt_body) = opt_body else {return false;};
index 78afa2f25f8e10c97b265ece1540c7876ec28e43..af49d438a22cb7918e9fde85d1f9b42dca2dfe6f 100644 (file)
@@ -536,6 +536,14 @@ fn check_missing_const_stability(&self, def_id: LocalDefId, span: Span) {
             return;
         }
 
+        // if the const impl is derived using the `derive_const` attribute,
+        // then it would be "stable" at least for the impl.
+        // We gate usages of it using `feature(const_trait_impl)` anyways
+        // so there is no unstable leakage
+        if self.tcx.is_builtin_derive(def_id.to_def_id()) {
+            return;
+        }
+
         let is_const = self.tcx.is_const_fn(def_id.to_def_id())
             || self.tcx.is_const_trait_impl_raw(def_id.to_def_id());
         let is_stable = self
index 865d6306bd349953271cc3788ed6948da6a859ac..e17f85c1aae0f14920eb49f14b32ecaa3bbfb281 100644 (file)
@@ -959,6 +959,10 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                 for variant in def.variants.iter() {
                     let variant_id = self.tcx.hir().local_def_id(variant.id);
                     self.effective_visibility_diagnostic(variant_id);
+                    if let Some(ctor_hir_id) = variant.data.ctor_hir_id() {
+                        let ctor_def_id = self.tcx.hir().local_def_id(ctor_hir_id);
+                        self.effective_visibility_diagnostic(ctor_def_id);
+                    }
                     for field in variant.data.fields() {
                         let def_id = self.tcx.hir().local_def_id(field.hir_id);
                         self.effective_visibility_diagnostic(def_id);
@@ -966,6 +970,10 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                 }
             }
             hir::ItemKind::Struct(ref def, _) | hir::ItemKind::Union(ref def, _) => {
+                if let Some(ctor_hir_id) = def.ctor_hir_id() {
+                    let ctor_def_id = self.tcx.hir().local_def_id(ctor_hir_id);
+                    self.effective_visibility_diagnostic(ctor_def_id);
+                }
                 for field in def.fields() {
                     let def_id = self.tcx.hir().local_def_id(field.hir_id);
                     self.effective_visibility_diagnostic(def_id);
@@ -2131,6 +2139,7 @@ fn effective_visibilities(tcx: TyCtxt<'_>, (): ()) -> &EffectiveVisibilities {
         changed: false,
     };
 
+    visitor.effective_visibilities.check_invariants(tcx, true);
     loop {
         tcx.hir().walk_toplevel_module(&mut visitor);
         if visitor.changed {
@@ -2139,6 +2148,7 @@ fn effective_visibilities(tcx: TyCtxt<'_>, (): ()) -> &EffectiveVisibilities {
             break;
         }
     }
+    visitor.effective_visibilities.check_invariants(tcx, false);
 
     let mut check_visitor =
         TestReachabilityVisitor { tcx, effective_visibilities: &visitor.effective_visibilities };
index a6cb8f7bd5532705b929242b7e3cd24c193c8c78..eaed9aeb85020c9be8e4261c12c5b693e77e7ae6 100644 (file)
@@ -119,12 +119,11 @@ struct Footer {
 struct SourceFileIndex(u32);
 
 #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Encodable, Decodable)]
-pub struct AbsoluteBytePos(u32);
+pub struct AbsoluteBytePos(u64);
 
 impl AbsoluteBytePos {
     fn new(pos: usize) -> AbsoluteBytePos {
-        debug_assert!(pos <= u32::MAX as usize);
-        AbsoluteBytePos(pos as u32)
+        AbsoluteBytePos(pos.try_into().expect("Incremental cache file size overflowed u64."))
     }
 
     fn to_usize(self) -> usize {
index 2cc311d48c8f63e661d011ce100189f8d616238a..81114f2cd82c326dbe9a98aefb7b402b986ded0f 100644 (file)
@@ -19,18 +19,18 @@ fn new() -> QueryKeyStringCache {
     }
 }
 
-struct QueryKeyStringBuilder<'p, 'c, 'tcx> {
+struct QueryKeyStringBuilder<'p, 'tcx> {
     profiler: &'p SelfProfiler,
     tcx: TyCtxt<'tcx>,
-    string_cache: &'c mut QueryKeyStringCache,
+    string_cache: &'p mut QueryKeyStringCache,
 }
 
-impl<'p, 'c, 'tcx> QueryKeyStringBuilder<'p, 'c, 'tcx> {
+impl<'p, 'tcx> QueryKeyStringBuilder<'p, 'tcx> {
     fn new(
         profiler: &'p SelfProfiler,
         tcx: TyCtxt<'tcx>,
-        string_cache: &'c mut QueryKeyStringCache,
-    ) -> QueryKeyStringBuilder<'p, 'c, 'tcx> {
+        string_cache: &'p mut QueryKeyStringCache,
+    ) -> QueryKeyStringBuilder<'p, 'tcx> {
         QueryKeyStringBuilder { profiler, tcx, string_cache }
     }
 
@@ -99,7 +99,7 @@ fn def_id_to_string_id(&mut self, def_id: DefId) -> StringId {
 }
 
 trait IntoSelfProfilingString {
-    fn to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_, '_>) -> StringId;
+    fn to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId;
 }
 
 // The default implementation of `IntoSelfProfilingString` just uses `Debug`
@@ -109,7 +109,7 @@ trait IntoSelfProfilingString {
 impl<T: Debug> IntoSelfProfilingString for T {
     default fn to_self_profile_string(
         &self,
-        builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
+        builder: &mut QueryKeyStringBuilder<'_, '_>,
     ) -> StringId {
         let s = format!("{:?}", self);
         builder.profiler.alloc_string(&s[..])
@@ -117,60 +117,42 @@ impl<T: Debug> IntoSelfProfilingString for T {
 }
 
 impl<T: SpecIntoSelfProfilingString> IntoSelfProfilingString for T {
-    fn to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_, '_>) -> StringId {
+    fn to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId {
         self.spec_to_self_profile_string(builder)
     }
 }
 
 #[rustc_specialization_trait]
 trait SpecIntoSelfProfilingString: Debug {
-    fn spec_to_self_profile_string(
-        &self,
-        builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
-    ) -> StringId;
+    fn spec_to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId;
 }
 
 impl SpecIntoSelfProfilingString for DefId {
-    fn spec_to_self_profile_string(
-        &self,
-        builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
-    ) -> StringId {
+    fn spec_to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId {
         builder.def_id_to_string_id(*self)
     }
 }
 
 impl SpecIntoSelfProfilingString for CrateNum {
-    fn spec_to_self_profile_string(
-        &self,
-        builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
-    ) -> StringId {
+    fn spec_to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId {
         builder.def_id_to_string_id(self.as_def_id())
     }
 }
 
 impl SpecIntoSelfProfilingString for DefIndex {
-    fn spec_to_self_profile_string(
-        &self,
-        builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
-    ) -> StringId {
+    fn spec_to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId {
         builder.def_id_to_string_id(DefId { krate: LOCAL_CRATE, index: *self })
     }
 }
 
 impl SpecIntoSelfProfilingString for LocalDefId {
-    fn spec_to_self_profile_string(
-        &self,
-        builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
-    ) -> StringId {
+    fn spec_to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId {
         builder.def_id_to_string_id(DefId { krate: LOCAL_CRATE, index: self.local_def_index })
     }
 }
 
 impl<T: SpecIntoSelfProfilingString> SpecIntoSelfProfilingString for WithOptConstParam<T> {
-    fn spec_to_self_profile_string(
-        &self,
-        builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
-    ) -> StringId {
+    fn spec_to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId {
         // We print `WithOptConstParam` values as tuples to make them shorter
         // and more readable, without losing information:
         //
@@ -205,10 +187,7 @@ impl<T0, T1> SpecIntoSelfProfilingString for (T0, T1)
     T0: SpecIntoSelfProfilingString,
     T1: SpecIntoSelfProfilingString,
 {
-    fn spec_to_self_profile_string(
-        &self,
-        builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
-    ) -> StringId {
+    fn spec_to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId {
         let val0 = self.0.to_self_profile_string(builder);
         let val1 = self.1.to_self_profile_string(builder);
 
index d592812f79b6b8f333e2e6e12092abf75760aeb1..7cc885be2ba6a6319b51e783e1d03efc97f344a1 100644 (file)
@@ -26,7 +26,7 @@ pub fn clear(&self) {
 }
 
 impl<Key: Eq + Hash, Value: Clone> Cache<Key, Value> {
-    pub fn get<CTX: DepContext>(&self, key: &Key, tcx: CTX) -> Option<Value> {
+    pub fn get<Tcx: DepContext>(&self, key: &Key, tcx: Tcx) -> Option<Value> {
         Some(self.hashmap.borrow().get(key)?.get(tcx))
     }
 
@@ -46,7 +46,7 @@ pub fn new(dep_node: DepNodeIndex, cached_value: T) -> Self {
         WithDepNode { dep_node, cached_value }
     }
 
-    pub fn get<CTX: DepContext>(&self, tcx: CTX) -> T {
+    pub fn get<Tcx: DepContext>(&self, tcx: Tcx) -> T {
         tcx.dep_graph().read_index(self.dep_node);
         self.cached_value.clone()
     }
index 5c6ce0556eb8a4b22b744dbfd5592fbc1cb6e6a6..d79c5816a9c40bb1fc0d3aab18113ae01af46ea8 100644 (file)
@@ -61,18 +61,18 @@ impl<K: DepKind> DepNode<K> {
     /// Creates a new, parameterless DepNode. This method will assert
     /// that the DepNode corresponding to the given DepKind actually
     /// does not require any parameters.
-    pub fn new_no_params<Ctxt>(tcx: Ctxt, kind: K) -> DepNode<K>
+    pub fn new_no_params<Tcx>(tcx: Tcx, kind: K) -> DepNode<K>
     where
-        Ctxt: super::DepContext<DepKind = K>,
+        Tcx: super::DepContext<DepKind = K>,
     {
         debug_assert_eq!(tcx.fingerprint_style(kind), FingerprintStyle::Unit);
         DepNode { kind, hash: Fingerprint::ZERO.into() }
     }
 
-    pub fn construct<Ctxt, Key>(tcx: Ctxt, kind: K, arg: &Key) -> DepNode<K>
+    pub fn construct<Tcx, Key>(tcx: Tcx, kind: K, arg: &Key) -> DepNode<K>
     where
-        Ctxt: super::DepContext<DepKind = K>,
-        Key: DepNodeParams<Ctxt>,
+        Tcx: super::DepContext<DepKind = K>,
+        Key: DepNodeParams<Tcx>,
     {
         let hash = arg.to_fingerprint(tcx);
         let dep_node = DepNode { kind, hash: hash.into() };
@@ -93,9 +93,9 @@ pub fn construct<Ctxt, Key>(tcx: Ctxt, kind: K, arg: &Key) -> DepNode<K>
     /// Construct a DepNode from the given DepKind and DefPathHash. This
     /// method will assert that the given DepKind actually requires a
     /// single DefId/DefPathHash parameter.
-    pub fn from_def_path_hash<Ctxt>(tcx: Ctxt, def_path_hash: DefPathHash, kind: K) -> Self
+    pub fn from_def_path_hash<Tcx>(tcx: Tcx, def_path_hash: DefPathHash, kind: K) -> Self
     where
-        Ctxt: super::DepContext<DepKind = K>,
+        Tcx: super::DepContext<DepKind = K>,
     {
         debug_assert!(tcx.fingerprint_style(kind) == FingerprintStyle::DefPathHash);
         DepNode { kind, hash: def_path_hash.0.into() }
@@ -108,18 +108,18 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
-pub trait DepNodeParams<Ctxt: DepContext>: fmt::Debug + Sized {
+pub trait DepNodeParams<Tcx: DepContext>: fmt::Debug + Sized {
     fn fingerprint_style() -> FingerprintStyle;
 
     /// This method turns the parameters of a DepNodeConstructor into an opaque
     /// Fingerprint to be used in DepNode.
     /// Not all DepNodeParams support being turned into a Fingerprint (they
     /// don't need to if the corresponding DepNode is anonymous).
-    fn to_fingerprint(&self, _: Ctxt) -> Fingerprint {
+    fn to_fingerprint(&self, _: Tcx) -> Fingerprint {
         panic!("Not implemented. Accidentally called on anonymous node?")
     }
 
-    fn to_debug_str(&self, _: Ctxt) -> String {
+    fn to_debug_str(&self, _: Tcx) -> String {
         format!("{:?}", self)
     }
 
@@ -129,10 +129,10 @@ fn to_debug_str(&self, _: Ctxt) -> String {
     /// `fingerprint_style()` is not `FingerprintStyle::Opaque`.
     /// It is always valid to return `None` here, in which case incremental
     /// compilation will treat the query as having changed instead of forcing it.
-    fn recover(tcx: Ctxt, dep_node: &DepNode<Ctxt::DepKind>) -> Option<Self>;
+    fn recover(tcx: Tcx, dep_node: &DepNode<Tcx::DepKind>) -> Option<Self>;
 }
 
-impl<Ctxt: DepContext, T> DepNodeParams<Ctxt> for T
+impl<Tcx: DepContext, T> DepNodeParams<Tcx> for T
 where
     T: for<'a> HashStable<StableHashingContext<'a>> + fmt::Debug,
 {
@@ -142,7 +142,7 @@ impl<Ctxt: DepContext, T> DepNodeParams<Ctxt> for T
     }
 
     #[inline(always)]
-    default fn to_fingerprint(&self, tcx: Ctxt) -> Fingerprint {
+    default fn to_fingerprint(&self, tcx: Tcx) -> Fingerprint {
         tcx.with_stable_hashing_context(|mut hcx| {
             let mut hasher = StableHasher::new();
             self.hash_stable(&mut hcx, &mut hasher);
@@ -151,12 +151,12 @@ impl<Ctxt: DepContext, T> DepNodeParams<Ctxt> for T
     }
 
     #[inline(always)]
-    default fn to_debug_str(&self, _: Ctxt) -> String {
+    default fn to_debug_str(&self, _: Tcx) -> String {
         format!("{:?}", *self)
     }
 
     #[inline(always)]
-    default fn recover(_: Ctxt, _: &DepNode<Ctxt::DepKind>) -> Option<Self> {
+    default fn recover(_: Tcx, _: &DepNode<Tcx::DepKind>) -> Option<Self> {
         None
     }
 }
@@ -166,7 +166,7 @@ impl<Ctxt: DepContext, T> DepNodeParams<Ctxt> for T
 /// Information is retrieved by indexing the `DEP_KINDS` array using the integer value
 /// of the `DepKind`. Overall, this allows to implement `DepContext` using this manual
 /// jump table instead of large matches.
-pub struct DepKindStruct<CTX: DepContext> {
+pub struct DepKindStruct<Tcx: DepContext> {
     /// Anonymous queries cannot be replayed from one compiler invocation to the next.
     /// When their result is needed, it is recomputed. They are useful for fine-grained
     /// dependency tracking, and caching within one compiler invocation.
@@ -216,10 +216,10 @@ pub struct DepKindStruct<CTX: DepContext> {
     /// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode`
     /// is actually a `DefPathHash`, and can therefore just look up the corresponding
     /// `DefId` in `tcx.def_path_hash_to_def_id`.
-    pub force_from_dep_node: Option<fn(tcx: CTX, dep_node: DepNode<CTX::DepKind>) -> bool>,
+    pub force_from_dep_node: Option<fn(tcx: Tcx, dep_node: DepNode<Tcx::DepKind>) -> bool>,
 
     /// Invoke a query to put the on-disk cached value in memory.
-    pub try_load_from_on_disk_cache: Option<fn(CTX, DepNode<CTX::DepKind>)>,
+    pub try_load_from_on_disk_cache: Option<fn(Tcx, DepNode<Tcx::DepKind>)>,
 }
 
 /// A "work product" corresponds to a `.o` (or other) file that we
index 8ff56132749df71f5d08249cede4c2d36134ce51..d86c0bebdcdf4d2166cabe7918dca9dd925b5fba 100644 (file)
@@ -377,9 +377,9 @@ fn with_task_impl<Ctxt: HasDepContext<DepKind = K>, A: Debug, R>(
 
     /// Executes something within an "anonymous" task, that is, a task the
     /// `DepNode` of which is determined by the list of inputs it read from.
-    pub fn with_anon_task<Ctxt: DepContext<DepKind = K>, OP, R>(
+    pub fn with_anon_task<Tcx: DepContext<DepKind = K>, OP, R>(
         &self,
-        cx: Ctxt,
+        cx: Tcx,
         dep_kind: K,
         op: OP,
     ) -> (R, DepNodeIndex)
@@ -571,12 +571,12 @@ fn node_color(&self, dep_node: &DepNode<K>) -> Option<DepNodeColor> {
     /// A node will have an index, when it's already been marked green, or when we can mark it
     /// green. This function will mark the current task as a reader of the specified node, when
     /// a node index can be found for that node.
-    pub fn try_mark_green<Ctxt: QueryContext<DepKind = K>>(
+    pub fn try_mark_green<Qcx: QueryContext<DepKind = K>>(
         &self,
-        tcx: Ctxt,
+        qcx: Qcx,
         dep_node: &DepNode<K>,
     ) -> Option<(SerializedDepNodeIndex, DepNodeIndex)> {
-        debug_assert!(!tcx.dep_context().is_eval_always(dep_node.kind));
+        debug_assert!(!qcx.dep_context().is_eval_always(dep_node.kind));
 
         // Return None if the dep graph is disabled
         let data = self.data.as_ref()?;
@@ -592,15 +592,16 @@ pub fn try_mark_green<Ctxt: QueryContext<DepKind = K>>(
                 // in the previous compilation session too, so we can try to
                 // mark it as green by recursively marking all of its
                 // dependencies green.
-                self.try_mark_previous_green(tcx, data, prev_index, &dep_node)
+                self.try_mark_previous_green(qcx, data, prev_index, &dep_node)
                     .map(|dep_node_index| (prev_index, dep_node_index))
             }
         }
     }
 
-    fn try_mark_parent_green<Ctxt: QueryContext<DepKind = K>>(
+    #[instrument(skip(self, qcx, data, parent_dep_node_index), level = "debug")]
+    fn try_mark_parent_green<Qcx: QueryContext<DepKind = K>>(
         &self,
-        tcx: Ctxt,
+        qcx: Qcx,
         data: &DepGraphData<K>,
         parent_dep_node_index: SerializedDepNodeIndex,
         dep_node: &DepNode<K>,
@@ -613,11 +614,7 @@ fn try_mark_parent_green<Ctxt: QueryContext<DepKind = K>>(
                 // This dependency has been marked as green before, we are
                 // still fine and can continue with checking the other
                 // dependencies.
-                debug!(
-                    "try_mark_previous_green({:?}) --- found dependency {:?} to \
-                            be immediately green",
-                    dep_node, dep_dep_node,
-                );
+                debug!("dependency {dep_dep_node:?} was immediately green");
                 return Some(());
             }
             Some(DepNodeColor::Red) => {
@@ -625,10 +622,7 @@ fn try_mark_parent_green<Ctxt: QueryContext<DepKind = K>>(
                 // compared to the previous compilation session. We cannot
                 // mark the DepNode as green and also don't need to bother
                 // with checking any of the other dependencies.
-                debug!(
-                    "try_mark_previous_green({:?}) - END - dependency {:?} was immediately red",
-                    dep_node, dep_dep_node,
-                );
+                debug!("dependency {dep_dep_node:?} was immediately red");
                 return None;
             }
             None => {}
@@ -636,35 +630,26 @@ fn try_mark_parent_green<Ctxt: QueryContext<DepKind = K>>(
 
         // We don't know the state of this dependency. If it isn't
         // an eval_always node, let's try to mark it green recursively.
-        if !tcx.dep_context().is_eval_always(dep_dep_node.kind) {
+        if !qcx.dep_context().is_eval_always(dep_dep_node.kind) {
             debug!(
-                "try_mark_previous_green({:?}) --- state of dependency {:?} ({}) \
-                                 is unknown, trying to mark it green",
-                dep_node, dep_dep_node, dep_dep_node.hash,
+                "state of dependency {:?} ({}) is unknown, trying to mark it green",
+                dep_dep_node, dep_dep_node.hash,
             );
 
             let node_index =
-                self.try_mark_previous_green(tcx, data, parent_dep_node_index, dep_dep_node);
+                self.try_mark_previous_green(qcx, data, parent_dep_node_index, dep_dep_node);
+
             if node_index.is_some() {
-                debug!(
-                    "try_mark_previous_green({:?}) --- managed to MARK dependency {:?} as green",
-                    dep_node, dep_dep_node
-                );
+                debug!("managed to MARK dependency {dep_dep_node:?} as green",);
                 return Some(());
             }
         }
 
         // We failed to mark it green, so we try to force the query.
-        debug!(
-            "try_mark_previous_green({:?}) --- trying to force dependency {:?}",
-            dep_node, dep_dep_node
-        );
-        if !tcx.dep_context().try_force_from_dep_node(*dep_dep_node) {
+        debug!("trying to force dependency {dep_dep_node:?}");
+        if !qcx.dep_context().try_force_from_dep_node(*dep_dep_node) {
             // The DepNode could not be forced.
-            debug!(
-                "try_mark_previous_green({:?}) - END - dependency {:?} could not be forced",
-                dep_node, dep_dep_node
-            );
+            debug!("dependency {dep_dep_node:?} could not be forced");
             return None;
         }
 
@@ -672,23 +657,17 @@ fn try_mark_parent_green<Ctxt: QueryContext<DepKind = K>>(
 
         match dep_dep_node_color {
             Some(DepNodeColor::Green(_)) => {
-                debug!(
-                    "try_mark_previous_green({:?}) --- managed to FORCE dependency {:?} to green",
-                    dep_node, dep_dep_node
-                );
+                debug!("managed to FORCE dependency {dep_dep_node:?} to green");
                 return Some(());
             }
             Some(DepNodeColor::Red) => {
-                debug!(
-                    "try_mark_previous_green({:?}) - END - dependency {:?} was red after forcing",
-                    dep_node, dep_dep_node
-                );
+                debug!("dependency {dep_dep_node:?} was red after forcing",);
                 return None;
             }
             None => {}
         }
 
-        if !tcx.dep_context().sess().has_errors_or_delayed_span_bugs() {
+        if !qcx.dep_context().sess().has_errors_or_delayed_span_bugs() {
             panic!("try_mark_previous_green() - Forcing the DepNode should have set its color")
         }
 
@@ -702,23 +681,19 @@ fn try_mark_parent_green<Ctxt: QueryContext<DepKind = K>>(
         // invalid state will not be persisted to the
         // incremental compilation cache because of
         // compilation errors being present.
-        debug!(
-            "try_mark_previous_green({:?}) - END - dependency {:?} resulted in compilation error",
-            dep_node, dep_dep_node
-        );
+        debug!("dependency {dep_dep_node:?} resulted in compilation error",);
         return None;
     }
 
     /// Try to mark a dep-node which existed in the previous compilation session as green.
-    fn try_mark_previous_green<Ctxt: QueryContext<DepKind = K>>(
+    #[instrument(skip(self, qcx, data, prev_dep_node_index), level = "debug")]
+    fn try_mark_previous_green<Qcx: QueryContext<DepKind = K>>(
         &self,
-        tcx: Ctxt,
+        qcx: Qcx,
         data: &DepGraphData<K>,
         prev_dep_node_index: SerializedDepNodeIndex,
         dep_node: &DepNode<K>,
     ) -> Option<DepNodeIndex> {
-        debug!("try_mark_previous_green({:?}) - BEGIN", dep_node);
-
         #[cfg(not(parallel_compiler))]
         {
             debug_assert!(!self.dep_node_exists(dep_node));
@@ -726,14 +701,14 @@ fn try_mark_previous_green<Ctxt: QueryContext<DepKind = K>>(
         }
 
         // We never try to mark eval_always nodes as green
-        debug_assert!(!tcx.dep_context().is_eval_always(dep_node.kind));
+        debug_assert!(!qcx.dep_context().is_eval_always(dep_node.kind));
 
         debug_assert_eq!(data.previous.index_to_node(prev_dep_node_index), *dep_node);
 
         let prev_deps = data.previous.edge_targets_from(prev_dep_node_index);
 
         for &dep_dep_node_index in prev_deps {
-            self.try_mark_parent_green(tcx, data, dep_dep_node_index, dep_node)?
+            self.try_mark_parent_green(qcx, data, dep_dep_node_index, dep_node)?
         }
 
         // If we got here without hitting a `return` that means that all
@@ -745,7 +720,7 @@ fn try_mark_previous_green<Ctxt: QueryContext<DepKind = K>>(
         // We allocating an entry for the node in the current dependency graph and
         // adding all the appropriate edges imported from the previous graph
         let dep_node_index = data.current.promote_node_and_deps_to_current(
-            tcx.dep_context().profiler(),
+            qcx.dep_context().profiler(),
             &data.previous,
             prev_dep_node_index,
         );
@@ -754,7 +729,7 @@ fn try_mark_previous_green<Ctxt: QueryContext<DepKind = K>>(
 
         // FIXME: Store the fact that a node has diagnostics in a bit in the dep graph somewhere
         // Maybe store a list on disk and encode this fact in the DepNodeState
-        let side_effects = tcx.load_side_effects(prev_dep_node_index);
+        let side_effects = qcx.load_side_effects(prev_dep_node_index);
 
         #[cfg(not(parallel_compiler))]
         debug_assert!(
@@ -765,14 +740,14 @@ fn try_mark_previous_green<Ctxt: QueryContext<DepKind = K>>(
         );
 
         if !side_effects.is_empty() {
-            self.emit_side_effects(tcx, data, dep_node_index, side_effects);
+            self.emit_side_effects(qcx, data, dep_node_index, side_effects);
         }
 
         // ... and finally storing a "Green" entry in the color map.
         // Multiple threads can all write the same color here
         data.colors.insert(prev_dep_node_index, DepNodeColor::Green(dep_node_index));
 
-        debug!("try_mark_previous_green({:?}) - END - successfully marked as green", dep_node);
+        debug!("successfully marked {dep_node:?} as green");
         Some(dep_node_index)
     }
 
@@ -780,9 +755,9 @@ fn try_mark_previous_green<Ctxt: QueryContext<DepKind = K>>(
     /// This may be called concurrently on multiple threads for the same dep node.
     #[cold]
     #[inline(never)]
-    fn emit_side_effects<Ctxt: QueryContext<DepKind = K>>(
+    fn emit_side_effects<Qcx: QueryContext<DepKind = K>>(
         &self,
-        tcx: Ctxt,
+        qcx: Qcx,
         data: &DepGraphData<K>,
         dep_node_index: DepNodeIndex,
         side_effects: QuerySideEffects,
@@ -794,9 +769,9 @@ fn emit_side_effects<Ctxt: QueryContext<DepKind = K>>(
             // must process side effects
 
             // Promote the previous diagnostics to the current session.
-            tcx.store_side_effects(dep_node_index, side_effects.clone());
+            qcx.store_side_effects(dep_node_index, side_effects.clone());
 
-            let handle = tcx.dep_context().sess().diagnostic();
+            let handle = qcx.dep_context().sess().diagnostic();
 
             for mut diagnostic in side_effects.diagnostics {
                 handle.emit_diagnostic(&mut diagnostic);
@@ -824,7 +799,7 @@ pub fn is_green(&self, dep_node: &DepNode<K>) -> bool {
     //
     // This method will only load queries that will end up in the disk cache.
     // Other queries will not be executed.
-    pub fn exec_cache_promotions<Ctxt: DepContext<DepKind = K>>(&self, tcx: Ctxt) {
+    pub fn exec_cache_promotions<Tcx: DepContext<DepKind = K>>(&self, tcx: Tcx) {
         let _prof_timer = tcx.profiler().generic_activity("incr_comp_query_cache_promotion");
 
         let data = self.data.as_ref().unwrap();
index da2075fd5aadae209ba29832740a59cceefad10d..e370c6990a41353d9accc9cf09a48f20595cf0b6 100644 (file)
@@ -52,9 +52,8 @@ fn is_eval_always(&self, kind: Self::DepKind) -> bool {
     }
 
     /// Try to force a dep node to execute and see if it's green.
+    #[instrument(skip(self), level = "debug")]
     fn try_force_from_dep_node(self, dep_node: DepNode<Self::DepKind>) -> bool {
-        debug!("try_force_from_dep_node({:?}) --- trying to force", dep_node);
-
         let cb = self.dep_kind_info(dep_node.kind);
         if let Some(f) = cb.force_from_dep_node {
             f(self, dep_node);
index 148eabb38e2303692f687517d1cc22df43bcaaa1..6378ec10875d038e087236d195810b573ff6c48b 100644 (file)
@@ -49,15 +49,13 @@ pub(super) enum BodyResolver<'tcx> {
 
 impl<'a> StableHashingContext<'a> {
     #[inline]
-    fn new_with_or_without_spans(
+    pub fn new(
         sess: &'a Session,
         definitions: &'a Definitions,
         cstore: &'a dyn CrateStore,
         source_span: &'a IndexVec<LocalDefId, Span>,
-        always_ignore_spans: bool,
     ) -> Self {
-        let hash_spans_initial =
-            !always_ignore_spans && !sess.opts.unstable_opts.incremental_ignore_spans;
+        let hash_spans_initial = !sess.opts.unstable_opts.incremental_ignore_spans;
 
         StableHashingContext {
             body_resolver: BodyResolver::Forbidden,
@@ -71,33 +69,6 @@ fn new_with_or_without_spans(
         }
     }
 
-    #[inline]
-    pub fn new(
-        sess: &'a Session,
-        definitions: &'a Definitions,
-        cstore: &'a dyn CrateStore,
-        source_span: &'a IndexVec<LocalDefId, Span>,
-    ) -> Self {
-        Self::new_with_or_without_spans(
-            sess,
-            definitions,
-            cstore,
-            source_span,
-            /*always_ignore_spans=*/ false,
-        )
-    }
-
-    #[inline]
-    pub fn ignore_spans(
-        sess: &'a Session,
-        definitions: &'a Definitions,
-        cstore: &'a dyn CrateStore,
-        source_span: &'a IndexVec<LocalDefId, Span>,
-    ) -> Self {
-        let always_ignore_spans = true;
-        Self::new_with_or_without_spans(sess, definitions, cstore, source_span, always_ignore_spans)
-    }
-
     #[inline]
     pub fn without_hir_bodies(&mut self, f: impl FnOnce(&mut StableHashingContext<'_>)) {
         f(&mut StableHashingContext { body_resolver: BodyResolver::Ignore, ..self.clone() });
@@ -202,10 +173,4 @@ fn hashing_controls(&self) -> HashingControls {
     }
 }
 
-impl<'a> rustc_data_structures::intern::InternedHashingContext for StableHashingContext<'a> {
-    fn with_def_path_and_no_spans(&mut self, f: impl FnOnce(&mut Self)) {
-        self.while_hashing_spans(false, f);
-    }
-}
-
 impl<'a> rustc_session::HashStableContext for StableHashingContext<'a> {}
index db3ae559ad15d6a92bd2bc1c86c2b316b3530666..f40e174b7e79bf3a885843cd7d462fc29fa8f368 100644 (file)
@@ -11,7 +11,7 @@
 use std::fmt::Debug;
 use std::hash::Hash;
 
-pub trait QueryConfig<CTX: QueryContext> {
+pub trait QueryConfig<Qcx: QueryContext> {
     const NAME: &'static str;
 
     type Key: Eq + Hash + Clone + Debug;
@@ -21,47 +21,47 @@ pub trait QueryConfig<CTX: QueryContext> {
     type Cache: QueryCache<Key = Self::Key, Stored = Self::Stored, Value = Self::Value>;
 
     // Don't use this method to access query results, instead use the methods on TyCtxt
-    fn query_state<'a>(tcx: CTX) -> &'a QueryState<Self::Key>
+    fn query_state<'a>(tcx: Qcx) -> &'a QueryState<Self::Key>
     where
-        CTX: 'a;
+        Qcx: 'a;
 
     // Don't use this method to access query results, instead use the methods on TyCtxt
-    fn query_cache<'a>(tcx: CTX) -> &'a Self::Cache
+    fn query_cache<'a>(tcx: Qcx) -> &'a Self::Cache
     where
-        CTX: 'a;
+        Qcx: 'a;
 
     // Don't use this method to compute query results, instead use the methods on TyCtxt
-    fn make_vtable(tcx: CTX, key: &Self::Key) -> QueryVTable<CTX, Self::Key, Self::Value>;
+    fn make_vtable(tcx: Qcx, key: &Self::Key) -> QueryVTable<Qcx, Self::Key, Self::Value>;
 
-    fn cache_on_disk(tcx: CTX::DepContext, key: &Self::Key) -> bool;
+    fn cache_on_disk(tcx: Qcx::DepContext, key: &Self::Key) -> bool;
 
     // Don't use this method to compute query results, instead use the methods on TyCtxt
-    fn execute_query(tcx: CTX::DepContext, k: Self::Key) -> Self::Stored;
+    fn execute_query(tcx: Qcx::DepContext, k: Self::Key) -> Self::Stored;
 }
 
 #[derive(Copy, Clone)]
-pub struct QueryVTable<CTX: QueryContext, K, V> {
+pub struct QueryVTable<Qcx: QueryContext, K, V> {
     pub anon: bool,
-    pub dep_kind: CTX::DepKind,
+    pub dep_kind: Qcx::DepKind,
     pub eval_always: bool,
     pub depth_limit: bool,
 
-    pub compute: fn(CTX::DepContext, K) -> V,
+    pub compute: fn(Qcx::DepContext, K) -> V,
     pub hash_result: Option<fn(&mut StableHashingContext<'_>, &V) -> Fingerprint>,
     pub handle_cycle_error: HandleCycleError,
     // NOTE: this is also `None` if `cache_on_disk()` returns false, not just if it's unsupported by the query
-    pub try_load_from_disk: Option<fn(CTX, SerializedDepNodeIndex) -> Option<V>>,
+    pub try_load_from_disk: Option<fn(Qcx, SerializedDepNodeIndex) -> Option<V>>,
 }
 
-impl<CTX: QueryContext, K, V> QueryVTable<CTX, K, V> {
-    pub(crate) fn to_dep_node(&self, tcx: CTX::DepContext, key: &K) -> DepNode<CTX::DepKind>
+impl<Qcx: QueryContext, K, V> QueryVTable<Qcx, K, V> {
+    pub(crate) fn to_dep_node(&self, tcx: Qcx::DepContext, key: &K) -> DepNode<Qcx::DepKind>
     where
-        K: crate::dep_graph::DepNodeParams<CTX::DepContext>,
+        K: crate::dep_graph::DepNodeParams<Qcx::DepContext>,
     {
         DepNode::construct(tcx, self.dep_kind, key)
     }
 
-    pub(crate) fn compute(&self, tcx: CTX::DepContext, key: K) -> V {
+    pub(crate) fn compute(&self, tcx: Qcx::DepContext, key: K) -> V {
         (self.compute)(tcx, key)
     }
 }
index ed65393f57e4da59cd1c37d7b85536adbc41a553..49bbcf57804596623ed30642d0d837d5ba1ca8af 100644 (file)
@@ -596,8 +596,8 @@ pub(crate) fn report_cycle<'a>(
     cycle_diag.into_diagnostic(&sess.parse_sess.span_diagnostic)
 }
 
-pub fn print_query_stack<CTX: QueryContext>(
-    tcx: CTX,
+pub fn print_query_stack<Qcx: QueryContext>(
+    qcx: Qcx,
     mut current_query: Option<QueryJobId>,
     handler: &Handler,
     num_frames: Option<usize>,
@@ -606,7 +606,7 @@ pub fn print_query_stack<CTX: QueryContext>(
     // a panic hook, which means that the global `Handler` may be in a weird
     // state if it was responsible for triggering the panic.
     let mut i = 0;
-    let query_map = tcx.try_collect_active_jobs();
+    let query_map = qcx.try_collect_active_jobs();
 
     while let Some(query) = current_query {
         if Some(i) == num_frames {
index 0f7abe84231b6fd68124f2dc75617476d08e18a7..f8d93a27d1c2bbbb3ceff184ae2702235eef9387 100644 (file)
@@ -62,10 +62,10 @@ pub fn all_inactive(&self) -> bool {
         }
     }
 
-    pub fn try_collect_active_jobs<CTX: Copy>(
+    pub fn try_collect_active_jobs<Qcx: Copy>(
         &self,
-        tcx: CTX,
-        make_query: fn(CTX, K) -> QueryStackFrame,
+        qcx: Qcx,
+        make_query: fn(Qcx, K) -> QueryStackFrame,
         jobs: &mut QueryMap,
     ) -> Option<()> {
         #[cfg(parallel_compiler)]
@@ -76,7 +76,7 @@ pub fn try_collect_active_jobs<CTX: Copy>(
             for shard in shards.iter() {
                 for (k, v) in shard.iter() {
                     if let QueryResult::Started(ref job) = *v {
-                        let query = make_query(tcx, k.clone());
+                        let query = make_query(qcx, k.clone());
                         jobs.insert(job.id, QueryJobInfo { query, job: job.clone() });
                     }
                 }
@@ -90,7 +90,7 @@ pub fn try_collect_active_jobs<CTX: Copy>(
             // really hurt much.)
             for (k, v) in self.active.try_lock()?.iter() {
                 if let QueryResult::Started(ref job) = *v {
-                    let query = make_query(tcx, k.clone());
+                    let query = make_query(qcx, k.clone());
                     jobs.insert(job.id, QueryJobInfo { query, job: job.clone() });
                 }
             }
@@ -119,31 +119,31 @@ struct JobOwner<'tcx, K>
 
 #[cold]
 #[inline(never)]
-fn mk_cycle<CTX, V, R>(
-    tcx: CTX,
+fn mk_cycle<Qcx, V, R>(
+    qcx: Qcx,
     cycle_error: CycleError,
     handler: HandleCycleError,
     cache: &dyn crate::query::QueryStorage<Value = V, Stored = R>,
 ) -> R
 where
-    CTX: QueryContext,
-    V: std::fmt::Debug + Value<CTX::DepContext>,
+    Qcx: QueryContext,
+    V: std::fmt::Debug + Value<Qcx::DepContext>,
     R: Clone,
 {
-    let error = report_cycle(tcx.dep_context().sess(), &cycle_error);
-    let value = handle_cycle_error(*tcx.dep_context(), &cycle_error, error, handler);
+    let error = report_cycle(qcx.dep_context().sess(), &cycle_error);
+    let value = handle_cycle_error(*qcx.dep_context(), &cycle_error, error, handler);
     cache.store_nocache(value)
 }
 
-fn handle_cycle_error<CTX, V>(
-    tcx: CTX,
+fn handle_cycle_error<Tcx, V>(
+    tcx: Tcx,
     cycle_error: &CycleError,
     mut error: DiagnosticBuilder<'_, ErrorGuaranteed>,
     handler: HandleCycleError,
 ) -> V
 where
-    CTX: DepContext,
-    V: Value<CTX>,
+    Tcx: DepContext,
+    V: Value<Tcx>,
 {
     use HandleCycleError::*;
     match handler {
@@ -176,14 +176,14 @@ impl<'tcx, K> JobOwner<'tcx, K>
     /// This function is inlined because that results in a noticeable speed-up
     /// for some compile-time benchmarks.
     #[inline(always)]
-    fn try_start<'b, CTX>(
-        tcx: &'b CTX,
+    fn try_start<'b, Qcx>(
+        qcx: &'b Qcx,
         state: &'b QueryState<K>,
         span: Span,
         key: K,
     ) -> TryGetJob<'b, K>
     where
-        CTX: QueryContext,
+        Qcx: QueryContext,
     {
         #[cfg(parallel_compiler)]
         let mut state_lock = state.active.get_shard_by_value(&key).lock();
@@ -193,8 +193,8 @@ fn try_start<'b, CTX>(
 
         match lock.entry(key) {
             Entry::Vacant(entry) => {
-                let id = tcx.next_job_id();
-                let job = tcx.current_query_job();
+                let id = qcx.next_job_id();
+                let job = qcx.current_query_job();
                 let job = QueryJob::new(id, span, job);
 
                 let key = entry.key().clone();
@@ -213,8 +213,8 @@ fn try_start<'b, CTX>(
                         // If we are single-threaded we know that we have cycle error,
                         // so we just return the error.
                         return TryGetJob::Cycle(id.find_cycle_in_stack(
-                            tcx.try_collect_active_jobs().unwrap(),
-                            &tcx.current_query_job(),
+                            qcx.try_collect_active_jobs().unwrap(),
+                            &qcx.current_query_job(),
                             span,
                         ));
                     }
@@ -223,7 +223,7 @@ fn try_start<'b, CTX>(
                         // For parallel queries, we'll block and wait until the query running
                         // in another thread has completed. Record how long we wait in the
                         // self-profiler.
-                        let query_blocked_prof_timer = tcx.dep_context().profiler().query_blocked();
+                        let query_blocked_prof_timer = qcx.dep_context().profiler().query_blocked();
 
                         // Get the latch out
                         let latch = job.latch();
@@ -232,7 +232,7 @@ fn try_start<'b, CTX>(
 
                         // With parallel queries we might just have to wait on some other
                         // thread.
-                        let result = latch.wait_on(tcx.current_query_job(), span);
+                        let result = latch.wait_on(qcx.current_query_job(), span);
 
                         match result {
                             Ok(()) => TryGetJob::JobCompleted(query_blocked_prof_timer),
@@ -335,8 +335,8 @@ enum TryGetJob<'tcx, K>
 /// which will be used if the query is not in the cache and we need
 /// to compute it.
 #[inline]
-pub fn try_get_cached<'a, CTX, C, R, OnHit>(
-    tcx: CTX,
+pub fn try_get_cached<'a, Tcx, C, R, OnHit>(
+    tcx: Tcx,
     cache: &'a C,
     key: &C::Key,
     // `on_hit` can be called while holding a lock to the query cache
@@ -344,7 +344,7 @@ pub fn try_get_cached<'a, CTX, C, R, OnHit>(
 ) -> Result<R, ()>
 where
     C: QueryCache,
-    CTX: DepContext,
+    Tcx: DepContext,
     OnHit: FnOnce(&C::Stored) -> R,
 {
     cache.lookup(&key, |value, index| {
@@ -356,29 +356,29 @@ pub fn try_get_cached<'a, CTX, C, R, OnHit>(
     })
 }
 
-fn try_execute_query<CTX, C>(
-    tcx: CTX,
+fn try_execute_query<Qcx, C>(
+    qcx: Qcx,
     state: &QueryState<C::Key>,
     cache: &C,
     span: Span,
     key: C::Key,
-    dep_node: Option<DepNode<CTX::DepKind>>,
-    query: &QueryVTable<CTX, C::Key, C::Value>,
+    dep_node: Option<DepNode<Qcx::DepKind>>,
+    query: &QueryVTable<Qcx, C::Key, C::Value>,
 ) -> (C::Stored, Option<DepNodeIndex>)
 where
     C: QueryCache,
-    C::Key: Clone + DepNodeParams<CTX::DepContext>,
-    C::Value: Value<CTX::DepContext>,
-    CTX: QueryContext,
+    C::Key: Clone + DepNodeParams<Qcx::DepContext>,
+    C::Value: Value<Qcx::DepContext>,
+    Qcx: QueryContext,
 {
-    match JobOwner::<'_, C::Key>::try_start(&tcx, state, span, key.clone()) {
+    match JobOwner::<'_, C::Key>::try_start(&qcx, state, span, key.clone()) {
         TryGetJob::NotYetStarted(job) => {
-            let (result, dep_node_index) = execute_job(tcx, key, dep_node, query, job.id);
+            let (result, dep_node_index) = execute_job(qcx, key, dep_node, query, job.id);
             let result = job.complete(cache, result, dep_node_index);
             (result, Some(dep_node_index))
         }
         TryGetJob::Cycle(error) => {
-            let result = mk_cycle(tcx, error, query.handle_cycle_error, cache);
+            let result = mk_cycle(qcx, error, query.handle_cycle_error, cache);
             (result, None)
         }
         #[cfg(parallel_compiler)]
@@ -387,8 +387,8 @@ fn try_execute_query<CTX, C>(
                 .lookup(&key, |value, index| (value.clone(), index))
                 .unwrap_or_else(|_| panic!("value must be in cache after waiting"));
 
-            if std::intrinsics::unlikely(tcx.dep_context().profiler().enabled()) {
-                tcx.dep_context().profiler().query_cache_hit(index.into());
+            if std::intrinsics::unlikely(qcx.dep_context().profiler().enabled()) {
+                qcx.dep_context().profiler().query_cache_hit(index.into());
             }
             query_blocked_prof_timer.finish_with_query_invocation_id(index.into());
 
@@ -397,25 +397,25 @@ fn try_execute_query<CTX, C>(
     }
 }
 
-fn execute_job<CTX, K, V>(
-    tcx: CTX,
+fn execute_job<Qcx, K, V>(
+    qcx: Qcx,
     key: K,
-    mut dep_node_opt: Option<DepNode<CTX::DepKind>>,
-    query: &QueryVTable<CTX, K, V>,
+    mut dep_node_opt: Option<DepNode<Qcx::DepKind>>,
+    query: &QueryVTable<Qcx, K, V>,
     job_id: QueryJobId,
 ) -> (V, DepNodeIndex)
 where
-    K: Clone + DepNodeParams<CTX::DepContext>,
+    K: Clone + DepNodeParams<Qcx::DepContext>,
     V: Debug,
-    CTX: QueryContext,
+    Qcx: QueryContext,
 {
-    let dep_graph = tcx.dep_context().dep_graph();
+    let dep_graph = qcx.dep_context().dep_graph();
 
     // Fast path for when incr. comp. is off.
     if !dep_graph.is_fully_enabled() {
-        let prof_timer = tcx.dep_context().profiler().query_provider();
-        let result = tcx.start_query(job_id, query.depth_limit, None, || {
-            query.compute(*tcx.dep_context(), key)
+        let prof_timer = qcx.dep_context().profiler().query_provider();
+        let result = qcx.start_query(job_id, query.depth_limit, None, || {
+            query.compute(*qcx.dep_context(), key)
         });
         let dep_node_index = dep_graph.next_virtual_depnode_index();
         prof_timer.finish_with_query_invocation_id(dep_node_index.into());
@@ -425,33 +425,33 @@ fn execute_job<CTX, K, V>(
     if !query.anon && !query.eval_always {
         // `to_dep_node` is expensive for some `DepKind`s.
         let dep_node =
-            dep_node_opt.get_or_insert_with(|| query.to_dep_node(*tcx.dep_context(), &key));
+            dep_node_opt.get_or_insert_with(|| query.to_dep_node(*qcx.dep_context(), &key));
 
         // The diagnostics for this query will be promoted to the current session during
         // `try_mark_green()`, so we can ignore them here.
-        if let Some(ret) = tcx.start_query(job_id, false, None, || {
-            try_load_from_disk_and_cache_in_memory(tcx, &key, &dep_node, query)
+        if let Some(ret) = qcx.start_query(job_id, false, None, || {
+            try_load_from_disk_and_cache_in_memory(qcx, &key, &dep_node, query)
         }) {
             return ret;
         }
     }
 
-    let prof_timer = tcx.dep_context().profiler().query_provider();
+    let prof_timer = qcx.dep_context().profiler().query_provider();
     let diagnostics = Lock::new(ThinVec::new());
 
     let (result, dep_node_index) =
-        tcx.start_query(job_id, query.depth_limit, Some(&diagnostics), || {
+        qcx.start_query(job_id, query.depth_limit, Some(&diagnostics), || {
             if query.anon {
-                return dep_graph.with_anon_task(*tcx.dep_context(), query.dep_kind, || {
-                    query.compute(*tcx.dep_context(), key)
+                return dep_graph.with_anon_task(*qcx.dep_context(), query.dep_kind, || {
+                    query.compute(*qcx.dep_context(), key)
                 });
             }
 
             // `to_dep_node` is expensive for some `DepKind`s.
             let dep_node =
-                dep_node_opt.unwrap_or_else(|| query.to_dep_node(*tcx.dep_context(), &key));
+                dep_node_opt.unwrap_or_else(|| query.to_dep_node(*qcx.dep_context(), &key));
 
-            dep_graph.with_task(dep_node, *tcx.dep_context(), key, query.compute, query.hash_result)
+            dep_graph.with_task(dep_node, *qcx.dep_context(), key, query.compute, query.hash_result)
         });
 
     prof_timer.finish_with_query_invocation_id(dep_node_index.into());
@@ -461,55 +461,55 @@ fn execute_job<CTX, K, V>(
 
     if std::intrinsics::unlikely(!side_effects.is_empty()) {
         if query.anon {
-            tcx.store_side_effects_for_anon_node(dep_node_index, side_effects);
+            qcx.store_side_effects_for_anon_node(dep_node_index, side_effects);
         } else {
-            tcx.store_side_effects(dep_node_index, side_effects);
+            qcx.store_side_effects(dep_node_index, side_effects);
         }
     }
 
     (result, dep_node_index)
 }
 
-fn try_load_from_disk_and_cache_in_memory<CTX, K, V>(
-    tcx: CTX,
+fn try_load_from_disk_and_cache_in_memory<Qcx, K, V>(
+    qcx: Qcx,
     key: &K,
-    dep_node: &DepNode<CTX::DepKind>,
-    query: &QueryVTable<CTX, K, V>,
+    dep_node: &DepNode<Qcx::DepKind>,
+    query: &QueryVTable<Qcx, K, V>,
 ) -> Option<(V, DepNodeIndex)>
 where
     K: Clone,
-    CTX: QueryContext,
+    Qcx: QueryContext,
     V: Debug,
 {
     // Note this function can be called concurrently from the same query
     // We must ensure that this is handled correctly.
 
-    let dep_graph = tcx.dep_context().dep_graph();
-    let (prev_dep_node_index, dep_node_index) = dep_graph.try_mark_green(tcx, &dep_node)?;
+    let dep_graph = qcx.dep_context().dep_graph();
+    let (prev_dep_node_index, dep_node_index) = dep_graph.try_mark_green(qcx, &dep_node)?;
 
     debug_assert!(dep_graph.is_green(dep_node));
 
     // First we try to load the result from the on-disk cache.
     // Some things are never cached on disk.
     if let Some(try_load_from_disk) = query.try_load_from_disk {
-        let prof_timer = tcx.dep_context().profiler().incr_cache_loading();
+        let prof_timer = qcx.dep_context().profiler().incr_cache_loading();
 
         // The call to `with_query_deserialization` enforces that no new `DepNodes`
         // are created during deserialization. See the docs of that method for more
         // details.
         let result =
-            dep_graph.with_query_deserialization(|| try_load_from_disk(tcx, prev_dep_node_index));
+            dep_graph.with_query_deserialization(|| try_load_from_disk(qcx, prev_dep_node_index));
 
         prof_timer.finish_with_query_invocation_id(dep_node_index.into());
 
         if let Some(result) = result {
             if std::intrinsics::unlikely(
-                tcx.dep_context().sess().opts.unstable_opts.query_dep_graph,
+                qcx.dep_context().sess().opts.unstable_opts.query_dep_graph,
             ) {
                 dep_graph.mark_debug_loaded_from_disk(*dep_node)
             }
 
-            let prev_fingerprint = tcx
+            let prev_fingerprint = qcx
                 .dep_context()
                 .dep_graph()
                 .prev_fingerprint_of(dep_node)
@@ -523,9 +523,9 @@ fn try_load_from_disk_and_cache_in_memory<CTX, K, V>(
             // give us some coverage of potential bugs though.
             let try_verify = prev_fingerprint.as_value().1 % 32 == 0;
             if std::intrinsics::unlikely(
-                try_verify || tcx.dep_context().sess().opts.unstable_opts.incremental_verify_ich,
+                try_verify || qcx.dep_context().sess().opts.unstable_opts.incremental_verify_ich,
             ) {
-                incremental_verify_ich(*tcx.dep_context(), &result, dep_node, query);
+                incremental_verify_ich(*qcx.dep_context(), &result, dep_node, query);
             }
 
             return Some((result, dep_node_index));
@@ -534,7 +534,7 @@ fn try_load_from_disk_and_cache_in_memory<CTX, K, V>(
         // We always expect to find a cached result for things that
         // can be forced from `DepNode`.
         debug_assert!(
-            !tcx.dep_context().fingerprint_style(dep_node.kind).reconstructible(),
+            !qcx.dep_context().fingerprint_style(dep_node.kind).reconstructible(),
             "missing on-disk cache entry for {:?}",
             dep_node
         );
@@ -542,10 +542,10 @@ fn try_load_from_disk_and_cache_in_memory<CTX, K, V>(
 
     // We could not load a result from the on-disk cache, so
     // recompute.
-    let prof_timer = tcx.dep_context().profiler().query_provider();
+    let prof_timer = qcx.dep_context().profiler().query_provider();
 
     // The dep-graph for this computation is already in-place.
-    let result = dep_graph.with_ignore(|| query.compute(*tcx.dep_context(), key.clone()));
+    let result = dep_graph.with_ignore(|| query.compute(*qcx.dep_context(), key.clone()));
 
     prof_timer.finish_with_query_invocation_id(dep_node_index.into());
 
@@ -558,34 +558,38 @@ fn try_load_from_disk_and_cache_in_memory<CTX, K, V>(
     //
     // See issue #82920 for an example of a miscompilation that would get turned into
     // an ICE by this check
-    incremental_verify_ich(*tcx.dep_context(), &result, dep_node, query);
+    incremental_verify_ich(*qcx.dep_context(), &result, dep_node, query);
 
     Some((result, dep_node_index))
 }
 
-fn incremental_verify_ich<CTX, K, V: Debug>(
-    tcx: CTX::DepContext,
+#[instrument(skip(qcx, result, query), level = "debug")]
+fn incremental_verify_ich<Qcx, K, V: Debug>(
+    qcx: Qcx::DepContext,
     result: &V,
-    dep_node: &DepNode<CTX::DepKind>,
-    query: &QueryVTable<CTX, K, V>,
+    dep_node: &DepNode<Qcx::DepKind>,
+    query: &QueryVTable<Qcx, K, V>,
 ) where
-    CTX: QueryContext,
+    Qcx: QueryContext,
 {
     assert!(
-        tcx.dep_graph().is_green(dep_node),
+        qcx.dep_graph().is_green(dep_node),
         "fingerprint for green query instance not loaded from cache: {:?}",
         dep_node,
     );
 
-    debug!("BEGIN verify_ich({:?})", dep_node);
     let new_hash = query.hash_result.map_or(Fingerprint::ZERO, |f| {
-        tcx.with_stable_hashing_context(|mut hcx| f(&mut hcx, result))
+        qcx.with_stable_hashing_context(|mut hcx| f(&mut hcx, result))
     });
-    let old_hash = tcx.dep_graph().prev_fingerprint_of(dep_node);
-    debug!("END verify_ich({:?})", dep_node);
+
+    let old_hash = qcx.dep_graph().prev_fingerprint_of(dep_node);
 
     if Some(new_hash) != old_hash {
-        incremental_verify_ich_cold(tcx.sess(), DebugArg::from(&dep_node), DebugArg::from(&result));
+        incremental_verify_ich_failed(
+            qcx.sess(),
+            DebugArg::from(&dep_node),
+            DebugArg::from(&result),
+        );
     }
 }
 
@@ -631,13 +635,7 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 // different implementations for LLVM to chew on (and filling up the final
 // binary, too).
 #[cold]
-fn incremental_verify_ich_cold(sess: &Session, dep_node: DebugArg<'_>, result: DebugArg<'_>) {
-    let run_cmd = if let Some(crate_name) = &sess.opts.crate_name {
-        format!("`cargo clean -p {}` or `cargo clean`", crate_name)
-    } else {
-        "`cargo clean`".to_string()
-    };
-
+fn incremental_verify_ich_failed(sess: &Session, dep_node: DebugArg<'_>, result: DebugArg<'_>) {
     // When we emit an error message and panic, we try to debug-print the `DepNode`
     // and query result. Unfortunately, this can cause us to run additional queries,
     // which may result in another fingerprint mismatch while we're in the middle
@@ -653,6 +651,12 @@ fn incremental_verify_ich_cold(sess: &Session, dep_node: DebugArg<'_>, result: D
     if old_in_panic {
         sess.emit_err(crate::error::Reentrant);
     } else {
+        let run_cmd = if let Some(crate_name) = &sess.opts.crate_name {
+            format!("`cargo clean -p {}` or `cargo clean`", crate_name)
+        } else {
+            "`cargo clean`".to_string()
+        };
+
         sess.emit_err(crate::error::IncrementCompilation {
             run_cmd,
             dep_node: format!("{:?}", dep_node),
@@ -672,14 +676,14 @@ fn incremental_verify_ich_cold(sess: &Session, dep_node: DebugArg<'_>, result: D
 ///
 /// Note: The optimization is only available during incr. comp.
 #[inline(never)]
-fn ensure_must_run<CTX, K, V>(
-    tcx: CTX,
+fn ensure_must_run<Qcx, K, V>(
+    qcx: Qcx,
     key: &K,
-    query: &QueryVTable<CTX, K, V>,
-) -> (bool, Option<DepNode<CTX::DepKind>>)
+    query: &QueryVTable<Qcx, K, V>,
+) -> (bool, Option<DepNode<Qcx::DepKind>>)
 where
-    K: crate::dep_graph::DepNodeParams<CTX::DepContext>,
-    CTX: QueryContext,
+    K: crate::dep_graph::DepNodeParams<Qcx::DepContext>,
+    Qcx: QueryContext,
 {
     if query.eval_always {
         return (true, None);
@@ -688,10 +692,10 @@ fn ensure_must_run<CTX, K, V>(
     // Ensuring an anonymous query makes no sense
     assert!(!query.anon);
 
-    let dep_node = query.to_dep_node(*tcx.dep_context(), key);
+    let dep_node = query.to_dep_node(*qcx.dep_context(), key);
 
-    let dep_graph = tcx.dep_context().dep_graph();
-    match dep_graph.try_mark_green(tcx, &dep_node) {
+    let dep_graph = qcx.dep_context().dep_graph();
+    match dep_graph.try_mark_green(qcx, &dep_node) {
         None => {
             // A None return from `try_mark_green` means that this is either
             // a new dep node or that the dep node has already been marked red.
@@ -703,7 +707,7 @@ fn ensure_must_run<CTX, K, V>(
         }
         Some((_, dep_node_index)) => {
             dep_graph.read_index(dep_node_index);
-            tcx.dep_context().profiler().query_cache_hit(dep_node_index.into());
+            qcx.dep_context().profiler().query_cache_hit(dep_node_index.into());
             (false, None)
         }
     }
@@ -715,16 +719,16 @@ pub enum QueryMode {
     Ensure,
 }
 
-pub fn get_query<Q, CTX>(tcx: CTX, span: Span, key: Q::Key, mode: QueryMode) -> Option<Q::Stored>
+pub fn get_query<Q, Qcx>(qcx: Qcx, span: Span, key: Q::Key, mode: QueryMode) -> Option<Q::Stored>
 where
-    Q: QueryConfig<CTX>,
-    Q::Key: DepNodeParams<CTX::DepContext>,
-    Q::Value: Value<CTX::DepContext>,
-    CTX: QueryContext,
+    Q: QueryConfig<Qcx>,
+    Q::Key: DepNodeParams<Qcx::DepContext>,
+    Q::Value: Value<Qcx::DepContext>,
+    Qcx: QueryContext,
 {
-    let query = Q::make_vtable(tcx, &key);
+    let query = Q::make_vtable(qcx, &key);
     let dep_node = if let QueryMode::Ensure = mode {
-        let (must_run, dep_node) = ensure_must_run(tcx, &key, &query);
+        let (must_run, dep_node) = ensure_must_run(qcx, &key, &query);
         if !must_run {
             return None;
         }
@@ -734,33 +738,33 @@ pub fn get_query<Q, CTX>(tcx: CTX, span: Span, key: Q::Key, mode: QueryMode) ->
     };
 
     let (result, dep_node_index) = try_execute_query(
-        tcx,
-        Q::query_state(tcx),
-        Q::query_cache(tcx),
+        qcx,
+        Q::query_state(qcx),
+        Q::query_cache(qcx),
         span,
         key,
         dep_node,
         &query,
     );
     if let Some(dep_node_index) = dep_node_index {
-        tcx.dep_context().dep_graph().read_index(dep_node_index)
+        qcx.dep_context().dep_graph().read_index(dep_node_index)
     }
     Some(result)
 }
 
-pub fn force_query<Q, CTX>(tcx: CTX, key: Q::Key, dep_node: DepNode<CTX::DepKind>)
+pub fn force_query<Q, Qcx>(qcx: Qcx, key: Q::Key, dep_node: DepNode<Qcx::DepKind>)
 where
-    Q: QueryConfig<CTX>,
-    Q::Key: DepNodeParams<CTX::DepContext>,
-    Q::Value: Value<CTX::DepContext>,
-    CTX: QueryContext,
+    Q: QueryConfig<Qcx>,
+    Q::Key: DepNodeParams<Qcx::DepContext>,
+    Q::Value: Value<Qcx::DepContext>,
+    Qcx: QueryContext,
 {
     // We may be concurrently trying both execute and force a query.
     // Ensure that only one of them runs the query.
-    let cache = Q::query_cache(tcx);
+    let cache = Q::query_cache(qcx);
     let cached = cache.lookup(&key, |_, index| {
-        if std::intrinsics::unlikely(tcx.dep_context().profiler().enabled()) {
-            tcx.dep_context().profiler().query_cache_hit(index.into());
+        if std::intrinsics::unlikely(qcx.dep_context().profiler().enabled()) {
+            qcx.dep_context().profiler().query_cache_hit(index.into());
         }
     });
 
@@ -769,9 +773,9 @@ pub fn force_query<Q, CTX>(tcx: CTX, key: Q::Key, dep_node: DepNode<CTX::DepKind
         Err(()) => {}
     }
 
-    let query = Q::make_vtable(tcx, &key);
-    let state = Q::query_state(tcx);
+    let query = Q::make_vtable(qcx, &key);
+    let state = Q::query_state(qcx);
     debug_assert!(!query.anon);
 
-    try_execute_query(tcx, state, cache, DUMMY_SP, key, Some(dep_node), &query);
+    try_execute_query(qcx, state, cache, DUMMY_SP, key, Some(dep_node), &query);
 }
index 67fbf14e6129985d1e7cf346ffdde80f6f5d67ab..214656abed4dfeb3d13c858faeb67eec9db82830 100644 (file)
@@ -1,12 +1,12 @@
 use crate::dep_graph::DepContext;
 use crate::query::QueryInfo;
 
-pub trait Value<CTX: DepContext>: Sized {
-    fn from_cycle_error(tcx: CTX, cycle: &[QueryInfo]) -> Self;
+pub trait Value<Tcx: DepContext>: Sized {
+    fn from_cycle_error(tcx: Tcx, cycle: &[QueryInfo]) -> Self;
 }
 
-impl<CTX: DepContext, T> Value<CTX> for T {
-    default fn from_cycle_error(tcx: CTX, _: &[QueryInfo]) -> T {
+impl<Tcx: DepContext, T> Value<Tcx> for T {
+    default fn from_cycle_error(tcx: Tcx, _: &[QueryInfo]) -> T {
         tcx.sess().abort_if_errors();
         // Ideally we would use `bug!` here. But bug! is only defined in rustc_middle, and it's
         // non-trivial to define it earlier.
index 423c57275333a2c355020942ecfb383816b8f24b..e7e419c9b4238207d0c75fc8fc1931d779395765 100644 (file)
@@ -469,9 +469,11 @@ fn build_reduced_graph_for_use_tree(
                         }
 
                         // Replace `use foo::{ self };` with `use foo;`
+                        let self_span = source.ident.span;
                         source = module_path.pop().unwrap();
                         if rename.is_none() {
-                            ident = source.ident;
+                            // Keep the span of `self`, but the name of `foo`
+                            ident = Ident { name: source.ident.name, span: self_span };
                         }
                     }
                 } else {
index 7961e3f1194e1ab7743fc31d70ddec84dc2f36e3..a12918b2979906021789ef8f5936bc59eb42c02c 100644 (file)
@@ -241,10 +241,12 @@ pub(crate) fn report_conflict<'b>(
         ));
 
         err.span_label(span, format!("`{}` re{} here", name, new_participle));
-        err.span_label(
-            self.session.source_map().guess_head_span(old_binding.span),
-            format!("previous {} of the {} `{}` here", old_noun, old_kind, name),
-        );
+        if !old_binding.span.is_dummy() && old_binding.span != span {
+            err.span_label(
+                self.session.source_map().guess_head_span(old_binding.span),
+                format!("previous {} of the {} `{}` here", old_noun, old_kind, name),
+            );
+        }
 
         // See https://github.com/rust-lang/rust/issues/32354
         use NameBindingKind::Import;
index 17ce854cb4388fa88a41aa87a9b8027730a98eee..fa6d34be0cc37c00a794031984ab513bb54d67f0 100644 (file)
@@ -1,16 +1,38 @@
-use crate::{ImportKind, NameBindingKind, Resolver};
+use crate::{ImportKind, NameBinding, NameBindingKind, Resolver, ResolverTree};
 use rustc_ast::ast;
 use rustc_ast::visit;
 use rustc_ast::visit::Visitor;
 use rustc_ast::Crate;
 use rustc_ast::EnumDef;
+use rustc_data_structures::intern::Interned;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::def_id::CRATE_DEF_ID;
-use rustc_middle::middle::privacy::Level;
-use rustc_middle::ty::{DefIdTree, Visibility};
+use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility, Level};
+use rustc_middle::ty::Visibility;
+
+type ImportId<'a> = Interned<'a, NameBinding<'a>>;
+
+#[derive(Clone, Copy)]
+enum ParentId<'a> {
+    Def(LocalDefId),
+    Import(ImportId<'a>),
+}
+
+impl ParentId<'_> {
+    fn level(self) -> Level {
+        match self {
+            ParentId::Def(_) => Level::Direct,
+            ParentId::Import(_) => Level::Reexported,
+        }
+    }
+}
 
 pub struct EffectiveVisibilitiesVisitor<'r, 'a> {
     r: &'r mut Resolver<'a>,
+    /// While walking import chains we need to track effective visibilities per-binding, and def id
+    /// keys in `Resolver::effective_visibilities` are not enough for that, because multiple
+    /// bindings can correspond to a single def id in imports. So we keep a separate table.
+    import_effective_visibilities: EffectiveVisibilities<ImportId<'a>>,
     changed: bool,
 }
 
@@ -19,21 +41,57 @@ impl<'r, 'a> EffectiveVisibilitiesVisitor<'r, 'a> {
     /// For now, this doesn't resolve macros (FIXME) and cannot resolve Impl, as we
     /// need access to a TyCtxt for that.
     pub fn compute_effective_visibilities<'c>(r: &'r mut Resolver<'a>, krate: &'c Crate) {
-        let mut visitor = EffectiveVisibilitiesVisitor { r, changed: false };
+        let mut visitor = EffectiveVisibilitiesVisitor {
+            r,
+            import_effective_visibilities: Default::default(),
+            changed: false,
+        };
 
-        visitor.update(CRATE_DEF_ID, Visibility::Public, CRATE_DEF_ID, Level::Direct);
+        visitor.update(CRATE_DEF_ID, CRATE_DEF_ID);
         visitor.set_bindings_effective_visibilities(CRATE_DEF_ID);
 
         while visitor.changed {
-            visitor.reset();
+            visitor.changed = false;
             visit::walk_crate(&mut visitor, krate);
         }
 
+        // Update visibilities for import def ids. These are not used during the
+        // `EffectiveVisibilitiesVisitor` pass, because we have more detailed binding-based
+        // information, but are used by later passes. Effective visibility of an import def id
+        // is the maximum value among visibilities of bindings corresponding to that def id.
+        for (binding, eff_vis) in visitor.import_effective_visibilities.iter() {
+            let NameBindingKind::Import { import, .. } = binding.kind else { unreachable!() };
+            if let Some(node_id) = import.id() {
+                let mut update = |node_id| {
+                    r.effective_visibilities.update_eff_vis(
+                        r.local_def_id(node_id),
+                        eff_vis,
+                        ResolverTree(&r.definitions, &r.crate_loader),
+                    )
+                };
+                update(node_id);
+                if let ImportKind::Single { additional_ids: (id1, id2), .. } = import.kind {
+                    // In theory all the single import IDs have individual visibilities and
+                    // effective visibilities, but in practice these IDs go straigth to HIR
+                    // where all their few uses assume that their (effective) visibility
+                    // applies to the whole syntactic `use` item. So they all get the same
+                    // value which is the maximum of all bindings. Maybe HIR for imports
+                    // shouldn't use three IDs at all.
+                    if id1 != ast::DUMMY_NODE_ID {
+                        update(id1);
+                    }
+                    if id2 != ast::DUMMY_NODE_ID {
+                        update(id2);
+                    }
+                }
+            }
+        }
+
         info!("resolve::effective_visibilities: {:#?}", r.effective_visibilities);
     }
 
-    fn reset(&mut self) {
-        self.changed = false;
+    fn nearest_normal_mod(&mut self, def_id: LocalDefId) -> LocalDefId {
+        self.r.get_nearest_non_block_module(def_id.to_def_id()).nearest_parent_mod().expect_local()
     }
 
     /// Update effective visibilities of bindings in the given module,
@@ -48,92 +106,83 @@ fn set_bindings_effective_visibilities(&mut self, module_id: LocalDefId) {
                 // Set the given effective visibility level to `Level::Direct` and
                 // sets the rest of the `use` chain to `Level::Reexported` until
                 // we hit the actual exported item.
+                let mut parent_id = ParentId::Def(module_id);
+                while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind {
+                    let binding_id = ImportId::new_unchecked(binding);
+                    self.update_import(binding_id, parent_id);
 
-                // FIXME: tag and is_public() condition should be removed, but assertions occur.
-                let tag = if binding.is_import() { Level::Reexported } else { Level::Direct };
-                if binding.vis.is_public() {
-                    let mut prev_parent_id = module_id;
-                    let mut level = Level::Direct;
-                    while let NameBindingKind::Import { binding: nested_binding, import, .. } =
-                        binding.kind
-                    {
-                        let mut update = |node_id| {
-                            self.update(
-                                self.r.local_def_id(node_id),
-                                binding.vis.expect_local(),
-                                prev_parent_id,
-                                level,
-                            )
-                        };
-                        match import.kind {
-                            ImportKind::Single { id, additional_ids, .. } => {
-                                // In theory all the import IDs have individual visibilities and
-                                // effective visibilities, but in practice these IDs go straigth to
-                                // HIR where all their few uses assume that their (effective)
-                                // visibility applies to the whole syntactic `use` item. So we
-                                // update them all to the maximum value among the potential
-                                // individual effective visibilities. Maybe HIR for imports
-                                // shouldn't use three IDs at all.
-                                update(id);
-                                update(additional_ids.0);
-                                update(additional_ids.1);
-                                prev_parent_id = self.r.local_def_id(id);
-                            }
-                            ImportKind::Glob { id, .. } | ImportKind::ExternCrate { id, .. } => {
-                                update(id);
-                                prev_parent_id = self.r.local_def_id(id);
-                            }
-                            ImportKind::MacroUse => {
-                                // In theory we should reset the parent id to something private
-                                // here, but `macro_use` imports always refer to external items,
-                                // so it doesn't matter and we can just do nothing.
-                            }
-                            ImportKind::MacroExport => {
-                                // In theory we should reset the parent id to something public
-                                // here, but it has the same effect as leaving the previous parent,
-                                // so we can just do nothing.
-                            }
-                        }
-
-                        level = Level::Reexported;
-                        binding = nested_binding;
-                    }
+                    parent_id = ParentId::Import(binding_id);
+                    binding = nested_binding;
                 }
 
                 if let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local()) {
-                    self.update(def_id, binding.vis.expect_local(), module_id, tag);
+                    self.update_def(def_id, binding.vis.expect_local(), parent_id);
                 }
             }
         }
     }
 
-    fn update(
-        &mut self,
-        def_id: LocalDefId,
+    fn effective_vis(&self, parent_id: ParentId<'a>) -> Option<EffectiveVisibility> {
+        match parent_id {
+            ParentId::Def(def_id) => self.r.effective_visibilities.effective_vis(def_id),
+            ParentId::Import(binding) => self.import_effective_visibilities.effective_vis(binding),
+        }
+        .copied()
+    }
+
+    /// The update is guaranteed to not change the table and we can skip it.
+    fn is_noop_update(
+        &self,
+        parent_id: ParentId<'a>,
         nominal_vis: Visibility,
-        parent_id: LocalDefId,
-        tag: Level,
-    ) {
-        let module_id = self
-            .r
-            .get_nearest_non_block_module(def_id.to_def_id())
-            .nearest_parent_mod()
-            .expect_local();
-        if nominal_vis == Visibility::Restricted(module_id)
-            || self.r.visibilities[&parent_id] == Visibility::Restricted(module_id)
-        {
+        default_vis: Visibility,
+    ) -> bool {
+        nominal_vis == default_vis
+            || match parent_id {
+                ParentId::Def(def_id) => self.r.visibilities[&def_id],
+                ParentId::Import(binding) => binding.vis.expect_local(),
+            } == default_vis
+    }
+
+    fn update_import(&mut self, binding: ImportId<'a>, parent_id: ParentId<'a>) {
+        let NameBindingKind::Import { import, .. } = binding.kind else { unreachable!() };
+        let nominal_vis = binding.vis.expect_local();
+        let default_vis = Visibility::Restricted(
+            import
+                .id()
+                .map(|id| self.nearest_normal_mod(self.r.local_def_id(id)))
+                .unwrap_or(CRATE_DEF_ID),
+        );
+        if self.is_noop_update(parent_id, nominal_vis, default_vis) {
             return;
         }
-        let mut effective_visibilities = std::mem::take(&mut self.r.effective_visibilities);
-        self.changed |= effective_visibilities.update(
+        self.changed |= self.import_effective_visibilities.update(
+            binding,
+            nominal_vis,
+            default_vis,
+            self.effective_vis(parent_id),
+            parent_id.level(),
+            ResolverTree(&self.r.definitions, &self.r.crate_loader),
+        );
+    }
+
+    fn update_def(&mut self, def_id: LocalDefId, nominal_vis: Visibility, parent_id: ParentId<'a>) {
+        let default_vis = Visibility::Restricted(self.nearest_normal_mod(def_id));
+        if self.is_noop_update(parent_id, nominal_vis, default_vis) {
+            return;
+        }
+        self.changed |= self.r.effective_visibilities.update(
             def_id,
             nominal_vis,
-            || Visibility::Restricted(module_id),
-            parent_id,
-            tag,
-            &*self.r,
+            if def_id == CRATE_DEF_ID { Visibility::Public } else { default_vis },
+            self.effective_vis(parent_id),
+            parent_id.level(),
+            ResolverTree(&self.r.definitions, &self.r.crate_loader),
         );
-        self.r.effective_visibilities = effective_visibilities;
+    }
+
+    fn update(&mut self, def_id: LocalDefId, parent_id: LocalDefId) {
+        self.update_def(def_id, self.r.visibilities[&def_id], ParentId::Def(parent_id));
     }
 }
 
@@ -151,12 +200,6 @@ fn visit_item(&mut self, item: &'ast ast::Item) {
                 "ast::ItemKind::MacCall encountered, this should not anymore appear at this stage"
             ),
 
-            // Foreign modules inherit level from parents.
-            ast::ItemKind::ForeignMod(..) => {
-                let parent_id = self.r.local_parent(def_id);
-                self.update(def_id, Visibility::Public, parent_id, Level::Direct);
-            }
-
             ast::ItemKind::Mod(..) => {
                 self.set_bindings_effective_visibilities(def_id);
                 visit::walk_item(self, item);
@@ -167,18 +210,14 @@ fn visit_item(&mut self, item: &'ast ast::Item) {
                 for variant in variants {
                     let variant_def_id = self.r.local_def_id(variant.id);
                     for field in variant.data.fields() {
-                        let field_def_id = self.r.local_def_id(field.id);
-                        let vis = self.r.visibilities[&field_def_id];
-                        self.update(field_def_id, vis, variant_def_id, Level::Direct);
+                        self.update(self.r.local_def_id(field.id), variant_def_id);
                     }
                 }
             }
 
             ast::ItemKind::Struct(ref def, _) | ast::ItemKind::Union(ref def, _) => {
                 for field in def.fields() {
-                    let field_def_id = self.r.local_def_id(field.id);
-                    let vis = self.r.visibilities[&field_def_id];
-                    self.update(field_def_id, vis, def_id, Level::Direct);
+                    self.update(self.r.local_def_id(field.id), def_id);
                 }
             }
 
@@ -194,6 +233,7 @@ fn visit_item(&mut self, item: &'ast ast::Item) {
             | ast::ItemKind::TyAlias(..)
             | ast::ItemKind::TraitAlias(..)
             | ast::ItemKind::MacroDef(..)
+            | ast::ItemKind::ForeignMod(..)
             | ast::ItemKind::Fn(..) => return,
         }
     }
index 6d2ee25df320dd0898115e07c70b9cdb7c73a8fd..ede67813883d6b2643464e886c8f769156b6c7e8 100644 (file)
@@ -527,6 +527,7 @@ struct DiagnosticMetadata<'ast> {
 
     /// Used to detect possible new binding written without `let` and to provide structured suggestion.
     in_assignment: Option<&'ast Expr>,
+    is_assign_rhs: bool,
 
     /// If we are currently in a trait object definition. Used to point at the bounds when
     /// encountering a struct or enum.
@@ -3963,10 +3964,15 @@ fn resolve_expr(&mut self, expr: &'ast Expr, parent: Option<&'ast Expr>) {
                 self.resolve_expr(elem, Some(expr));
                 self.visit_expr(idx);
             }
-            ExprKind::Assign(..) => {
-                let old = self.diagnostic_metadata.in_assignment.replace(expr);
-                visit::walk_expr(self, expr);
-                self.diagnostic_metadata.in_assignment = old;
+            ExprKind::Assign(ref lhs, ref rhs, _) => {
+                if !self.diagnostic_metadata.is_assign_rhs {
+                    self.diagnostic_metadata.in_assignment = Some(expr);
+                }
+                self.visit_expr(lhs);
+                self.diagnostic_metadata.is_assign_rhs = true;
+                self.diagnostic_metadata.in_assignment = None;
+                self.visit_expr(rhs);
+                self.diagnostic_metadata.is_assign_rhs = false;
             }
             _ => {
                 visit::walk_expr(self, expr);
index a1338dcd4771bc8379af7b14c6805585b75fa11c..95eff92ef5e2471775f13aa5fa13cd2e84eb5532 100644 (file)
@@ -219,26 +219,26 @@ fn make_base_error(
             let (mod_prefix, mod_str, suggestion) = if path.len() == 1 {
                 debug!(?self.diagnostic_metadata.current_impl_items);
                 debug!(?self.diagnostic_metadata.current_function);
-                let suggestion = if let Some(items) = self.diagnostic_metadata.current_impl_items
+                let suggestion = if self.current_trait_ref.is_none()
                     && let Some((fn_kind, _)) = self.diagnostic_metadata.current_function
-                    && self.current_trait_ref.is_none()
                     && let Some(FnCtxt::Assoc(_)) = fn_kind.ctxt()
+                    && let Some(items) = self.diagnostic_metadata.current_impl_items
                     && let Some(item) = items.iter().find(|i| {
-                        if let AssocItemKind::Fn(fn_) = &i.kind
-                            && !fn_.sig.decl.has_self()
-                            && i.ident.name == item_str.name
+                        if let AssocItemKind::Fn(_) = &i.kind && i.ident.name == item_str.name
                         {
                             debug!(?item_str.name);
-                            debug!(?fn_.sig.decl.inputs);
                             return true
                         }
                         false
                     })
+                    && let AssocItemKind::Fn(fn_) = &item.kind
                 {
+                    debug!(?fn_);
+                    let self_sugg = if fn_.sig.decl.has_self() { "self." } else { "Self::" };
                     Some((
-                        item_span,
+                        item_span.shrink_to_lo(),
                         "consider using the associated function",
-                        format!("Self::{}", item.ident)
+                        self_sugg.to_string()
                     ))
                 } else {
                     None
@@ -396,11 +396,13 @@ fn detect_assoct_type_constraint_meant_as_path(
     }
 
     fn suggest_self_or_self_ref(&mut self, err: &mut Diagnostic, path: &[Segment], span: Span) {
-        let is_assoc_fn = self.self_type_is_available();
+        if !self.self_type_is_available() {
+            return;
+        }
         let Some(path_last_segment) = path.last() else { return };
         let item_str = path_last_segment.ident;
         // Emit help message for fake-self from other languages (e.g., `this` in Javascript).
-        if ["this", "my"].contains(&item_str.as_str()) && is_assoc_fn {
+        if ["this", "my"].contains(&item_str.as_str()) {
             err.span_suggestion_short(
                 span,
                 "you might have meant to use `self` here instead",
@@ -437,7 +439,7 @@ fn suggest_self_or_self_ref(&mut self, err: &mut Diagnostic, path: &[Segment], s
 
     fn try_lookup_name_relaxed(
         &mut self,
-        err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
+        err: &mut Diagnostic,
         source: PathSource<'_>,
         path: &[Segment],
         span: Span,
@@ -451,7 +453,6 @@ fn try_lookup_name_relaxed(
         let is_enum_variant = &|res| matches!(res, Res::Def(DefKind::Variant, _));
         let path_str = Segment::names_to_string(path);
         let ident_span = path.last().map_or(span, |ident| ident.ident.span);
-
         let mut candidates = self
             .r
             .lookup_import_candidates(ident, ns, &self.parent_scope, is_expected)
@@ -497,7 +498,7 @@ fn try_lookup_name_relaxed(
                         .contains(span)
                     {
                         // Already reported this issue on the lhs of the type ascription.
-                        err.delay_as_bug();
+                        err.downgrade_to_delayed_bug();
                         return (true, candidates);
                     }
                 }
@@ -616,7 +617,7 @@ fn try_lookup_name_relaxed(
 
     fn suggest_trait_and_bounds(
         &mut self,
-        err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
+        err: &mut Diagnostic,
         source: PathSource<'_>,
         res: Option<Res>,
         span: Span,
@@ -691,7 +692,7 @@ fn suggest_trait_and_bounds(
 
     fn suggest_typo(
         &mut self,
-        err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
+        err: &mut Diagnostic,
         source: PathSource<'_>,
         path: &[Segment],
         span: Span,
@@ -750,7 +751,7 @@ fn suggest_typo(
 
     fn err_code_special_cases(
         &mut self,
-        err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
+        err: &mut Diagnostic,
         source: PathSource<'_>,
         path: &[Segment],
         span: Span,
@@ -806,14 +807,16 @@ fn suggest_self_ty(
         err.code(rustc_errors::error_code!(E0411));
         err.span_label(span, "`Self` is only available in impls, traits, and type definitions");
         if let Some(item_kind) = self.diagnostic_metadata.current_item {
-            err.span_label(
-                item_kind.ident.span,
-                format!(
-                    "`Self` not allowed in {} {}",
-                    item_kind.kind.article(),
-                    item_kind.kind.descr()
-                ),
-            );
+            if !item_kind.ident.span.is_dummy() {
+                err.span_label(
+                    item_kind.ident.span,
+                    format!(
+                        "`Self` not allowed in {} {}",
+                        item_kind.kind.article(),
+                        item_kind.kind.descr()
+                    ),
+                );
+            }
         }
         true
     }
@@ -1542,7 +1545,6 @@ fn extract_node_id(t: &Ty) -> Option<NodeId> {
                 _ => None,
             }
         }
-
         // Fields are generally expected in the same contexts as locals.
         if filter_fn(Res::Local(ast::DUMMY_NODE_ID)) {
             if let Some(node_id) =
@@ -1810,29 +1812,22 @@ fn type_ascription_suggestion(&self, err: &mut Diagnostic, base_span: Span) -> b
         false
     }
 
-    fn let_binding_suggestion(&self, err: &mut Diagnostic, ident_span: Span) -> bool {
-        // try to give a suggestion for this pattern: `name = 1`, which is common in other languages
-        let mut added_suggestion = false;
-        if let Some(Expr { kind: ExprKind::Assign(lhs, _rhs, _), .. }) = self.diagnostic_metadata.in_assignment &&
+    // try to give a suggestion for this pattern: `name = blah`, which is common in other languages
+    // suggest `let name = blah` to introduce a new binding
+    fn let_binding_suggestion(&mut self, err: &mut Diagnostic, ident_span: Span) -> bool {
+        if let Some(Expr { kind: ExprKind::Assign(lhs, .. ), .. }) = self.diagnostic_metadata.in_assignment &&
             let ast::ExprKind::Path(None, _) = lhs.kind {
-                let sm = self.r.session.source_map();
-                let line_span = sm.span_extend_to_line(ident_span);
-                let ident_name = sm.span_to_snippet(ident_span).unwrap();
-                // HACK(chenyukang): make sure ident_name is at the starting of the line to protect against macros
-                if sm
-                    .span_to_snippet(line_span)
-                    .map_or(false, |s| s.trim().starts_with(&ident_name))
-                {
+                if !ident_span.from_expansion() {
                     err.span_suggestion_verbose(
                         ident_span.shrink_to_lo(),
                         "you might have meant to introduce a new binding",
                         "let ".to_string(),
                         Applicability::MaybeIncorrect,
                     );
-                    added_suggestion = true;
+                    return true;
                 }
             }
-        added_suggestion
+        false
     }
 
     fn find_module(&mut self, def_id: DefId) -> Option<(Module<'a>, ImportSuggestion)> {
@@ -1941,7 +1936,7 @@ fn suggest_using_enum_variant(
                 err.span_suggestions(
                     span,
                     &msg,
-                    suggestable_variants.into_iter(),
+                    suggestable_variants,
                     Applicability::MaybeIncorrect,
                 );
             }
@@ -1995,7 +1990,7 @@ fn suggest_using_enum_variant(
                 err.span_suggestions(
                     span,
                     msg,
-                    suggestable_variants.into_iter(),
+                    suggestable_variants,
                     Applicability::MaybeIncorrect,
                 );
             }
@@ -2025,7 +2020,7 @@ fn suggest_using_enum_variant(
                 err.span_suggestions(
                     span,
                     msg,
-                    suggestable_variants_with_placeholders.into_iter(),
+                    suggestable_variants_with_placeholders,
                     Applicability::HasPlaceholders,
                 );
             }
index ee1c97d5ad2b7925875e30bf0f3a74fb16094417..a1ff477c6fefbf99859477c43bc3181b61559fc2 100644 (file)
@@ -1106,17 +1106,30 @@ fn as_mut(&mut self) -> &mut Resolver<'a> {
     }
 }
 
-impl<'a, 'b> DefIdTree for &'a Resolver<'b> {
+/// A minimal subset of resolver that can implemenent `DefIdTree`, sometimes
+/// required to satisfy borrow checker by avoiding borrowing the whole resolver.
+#[derive(Clone, Copy)]
+struct ResolverTree<'a, 'b>(&'a Definitions, &'a CrateLoader<'b>);
+
+impl DefIdTree for ResolverTree<'_, '_> {
     #[inline]
     fn opt_parent(self, id: DefId) -> Option<DefId> {
+        let ResolverTree(definitions, crate_loader) = self;
         match id.as_local() {
-            Some(id) => self.definitions.def_key(id).parent,
-            None => self.cstore().def_key(id).parent,
+            Some(id) => definitions.def_key(id).parent,
+            None => crate_loader.cstore().def_key(id).parent,
         }
         .map(|index| DefId { index, ..id })
     }
 }
 
+impl<'a, 'b> DefIdTree for &'a Resolver<'b> {
+    #[inline]
+    fn opt_parent(self, id: DefId) -> Option<DefId> {
+        ResolverTree(&self.definitions, &self.crate_loader).opt_parent(id)
+    }
+}
+
 impl Resolver<'_> {
     fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> {
         self.node_id_to_def_id.get(&node).copied()
index 9526296f9511530119db79663bd07f0f61099300..8c7972f8eebb92f09698ad625382f0a49f4bfd91 100644 (file)
@@ -356,7 +356,7 @@ fn resolve_derives(
             has_derive_copy: false,
         });
         let parent_scope = self.invocation_parent_scopes[&expn_id];
-        for (i, (path, _, opt_ext)) in entry.resolutions.iter_mut().enumerate() {
+        for (i, (path, _, opt_ext, _)) in entry.resolutions.iter_mut().enumerate() {
             if opt_ext.is_none() {
                 *opt_ext = Some(
                     match self.resolve_macro_path(
index aece29ca0cbf6197f509e73e7596fc191c684ea7..be084adb7b724c831ce3ec882180147ae431a53b 100644 (file)
@@ -548,6 +548,7 @@ pub enum PrintRequest {
     NativeStaticLibs,
     StackProtectorStrategies,
     LinkArgs,
+    SplitDebuginfo,
 }
 
 pub enum Input {
@@ -1806,6 +1807,7 @@ fn collect_print_requests(
         ("stack-protector-strategies", PrintRequest::StackProtectorStrategies),
         ("target-spec-json", PrintRequest::TargetSpec),
         ("link-args", PrintRequest::LinkArgs),
+        ("split-debuginfo", PrintRequest::SplitDebuginfo),
     ];
 
     prints.extend(matches.opt_strs("print").into_iter().map(|req| {
index f9566eeee9465949b17e4c133a7b7f3d5d31e1ff..7ea028b12efc41f40fe19250c427ddd5608e68bf 100644 (file)
@@ -753,6 +753,50 @@ pub fn span_until_char(&self, sp: Span, c: char) -> Span {
         }
     }
 
+    /// Given a 'Span', tries to tell if the next character is '>'
+    /// and the previous charactoer is '<' after skipping white space
+    /// return true if wrapped by '<>'
+    pub fn span_wrapped_by_angle_bracket(&self, span: Span) -> bool {
+        self.span_to_source(span, |src, start_index, end_index| {
+            if src.get(start_index..end_index).is_none() {
+                return Ok(false);
+            }
+            // test the right side to match '>' after skipping white space
+            let end_src = &src[end_index..];
+            let mut i = 0;
+            while let Some(cc) = end_src.chars().nth(i) {
+                if cc == ' ' {
+                    i = i + 1;
+                } else if cc == '>' {
+                    // found > in the right;
+                    break;
+                } else {
+                    // failed to find '>' return false immediately
+                    return Ok(false);
+                }
+            }
+            // test the left side to match '<' after skipping white space
+            i = start_index;
+            let start_src = &src[0..start_index];
+            while let Some(cc) = start_src.chars().nth(i) {
+                if cc == ' ' {
+                    if i == 0 {
+                        return Ok(false);
+                    }
+                    i = i - 1;
+                } else if cc == '<' {
+                    // found < in the left
+                    break;
+                } else {
+                    // failed to find '<' return false immediately
+                    return Ok(false);
+                }
+            }
+            return Ok(true);
+        })
+        .map_or(false, |is_accessible| is_accessible)
+    }
+
     /// Given a `Span`, tries to get a shorter span ending just after the first occurrence of `char`
     /// `c`.
     pub fn span_through_char(&self, sp: Span, c: char) -> Span {
@@ -855,7 +899,8 @@ pub fn end_point(&self, sp: Span) -> Span {
     /// Returns a new span representing the next character after the end-point of this span.
     /// Special cases:
     /// - if span is a dummy one, returns the same span
-    /// - if next_point reached the end of source, return span with lo = hi
+    /// - if next_point reached the end of source, return a span exceeding the end of source,
+    ///   which means sm.span_to_snippet(next_point) will get `Err`
     /// - respect multi-byte characters
     pub fn next_point(&self, sp: Span) -> Span {
         if sp.is_dummy() {
@@ -864,9 +909,6 @@ pub fn next_point(&self, sp: Span) -> Span {
         let start_of_next_point = sp.hi().0;
 
         let width = self.find_width_of_character_at_span(sp, true);
-        if width == 0 {
-            return Span::new(sp.hi(), sp.hi(), sp.ctxt(), None);
-        }
         // If the width is 1, then the next span should only contain the next char besides current ending.
         // However, in the case of a multibyte character, where the width != 1, the next span should
         // span multiple bytes to include the whole character.
@@ -938,7 +980,7 @@ fn find_width_of_character_at_span(&self, sp: Span, forwards: bool) -> u32 {
         // Ensure indexes are also not malformed.
         if start_index > end_index || end_index > source_len - 1 {
             debug!("find_width_of_character_at_span: source indexes are malformed");
-            return 0;
+            return 1;
         }
 
         let src = local_begin.sf.external_src.borrow();
index 1fd81018fa05c2f99442867621df3020050f36b4..3cab59e8dbe6cf6166b90d65ad62889e852782a7 100644 (file)
@@ -511,16 +511,17 @@ fn test_next_point() {
     assert_eq!(span.lo().0, 4);
     assert_eq!(span.hi().0, 5);
 
-    // A non-empty span at the last byte should advance to create an empty
-    // span pointing at the end of the file.
+    // Reaching to the end of file, return a span that will get error with `span_to_snippet`
     let span = Span::with_root_ctxt(BytePos(4), BytePos(5));
     let span = sm.next_point(span);
     assert_eq!(span.lo().0, 5);
-    assert_eq!(span.hi().0, 5);
+    assert_eq!(span.hi().0, 6);
+    assert!(sm.span_to_snippet(span).is_err());
 
-    // Empty span pointing just past the last byte.
+    // Reaching to the end of file, return a span that will get error with `span_to_snippet`
     let span = Span::with_root_ctxt(BytePos(5), BytePos(5));
     let span = sm.next_point(span);
     assert_eq!(span.lo().0, 5);
-    assert_eq!(span.hi().0, 5);
+    assert_eq!(span.hi().0, 6);
+    assert!(sm.span_to_snippet(span).is_err());
 }
index cccc4897ecca6b35a1454559a2be2228179123f9..b48db73618b0b9278bbc9aad5abd6b399da076d2 100644 (file)
         custom_attribute,
         custom_derive,
         custom_inner_attributes,
+        custom_mir,
         custom_test_frameworks,
         d,
         d32,
         deref_mut,
         deref_target,
         derive,
+        derive_const,
         derive_default_enum,
         destruct,
         destructuring_assignment,
index 2109b3c24962e6b4db7d1d01637decdcdeeb7f7b..e540e2f2a2192397be2a6571d008d4d6aaec3cd4 100644 (file)
@@ -218,7 +218,7 @@ fn in_binder<'a, T>(
         let lifetimes = regions
             .into_iter()
             .map(|br| match br {
-                ty::BrAnon(i) => i,
+                ty::BrAnon(i, _) => i,
                 _ => bug!("symbol_names: non-anonymized region `{:?}` in `{:?}`", br, value),
             })
             .max()
@@ -335,7 +335,7 @@ fn print_region(self, region: ty::Region<'_>) -> Result<Self::Region, Self::Erro
 
             // Late-bound lifetimes use indices starting at 1,
             // see `BinderLevel` for more details.
-            ty::ReLateBound(debruijn, ty::BoundRegion { kind: ty::BrAnon(i), .. }) => {
+            ty::ReLateBound(debruijn, ty::BoundRegion { kind: ty::BrAnon(i, _), .. }) => {
                 let binder = &self.binders[self.binders.len() - 1 - debruijn.index()];
                 let depth = binder.lifetime_depths.start + i;
 
diff --git a/compiler/rustc_target/src/abi/call/loongarch.rs b/compiler/rustc_target/src/abi/call/loongarch.rs
new file mode 100644 (file)
index 0000000..d29b479
--- /dev/null
@@ -0,0 +1,342 @@
+use crate::abi::call::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform};
+use crate::abi::{self, Abi, FieldsShape, HasDataLayout, Size, TyAbiInterface, TyAndLayout};
+use crate::spec::HasTargetSpec;
+
+#[derive(Copy, Clone)]
+enum RegPassKind {
+    Float(Reg),
+    Integer(Reg),
+    Unknown,
+}
+
+#[derive(Copy, Clone)]
+enum FloatConv {
+    FloatPair(Reg, Reg),
+    Float(Reg),
+    MixedPair(Reg, Reg),
+}
+
+#[derive(Copy, Clone)]
+struct CannotUseFpConv;
+
+fn is_loongarch_aggregate<'a, Ty>(arg: &ArgAbi<'a, Ty>) -> bool {
+    match arg.layout.abi {
+        Abi::Vector { .. } => true,
+        _ => arg.layout.is_aggregate(),
+    }
+}
+
+fn should_use_fp_conv_helper<'a, Ty, C>(
+    cx: &C,
+    arg_layout: &TyAndLayout<'a, Ty>,
+    xlen: u64,
+    flen: u64,
+    field1_kind: &mut RegPassKind,
+    field2_kind: &mut RegPassKind,
+) -> Result<(), CannotUseFpConv>
+where
+    Ty: TyAbiInterface<'a, C> + Copy,
+{
+    match arg_layout.abi {
+        Abi::Scalar(scalar) => match scalar.primitive() {
+            abi::Int(..) | abi::Pointer => {
+                if arg_layout.size.bits() > xlen {
+                    return Err(CannotUseFpConv);
+                }
+                match (*field1_kind, *field2_kind) {
+                    (RegPassKind::Unknown, _) => {
+                        *field1_kind = RegPassKind::Integer(Reg {
+                            kind: RegKind::Integer,
+                            size: arg_layout.size,
+                        });
+                    }
+                    (RegPassKind::Float(_), RegPassKind::Unknown) => {
+                        *field2_kind = RegPassKind::Integer(Reg {
+                            kind: RegKind::Integer,
+                            size: arg_layout.size,
+                        });
+                    }
+                    _ => return Err(CannotUseFpConv),
+                }
+            }
+            abi::F32 | abi::F64 => {
+                if arg_layout.size.bits() > flen {
+                    return Err(CannotUseFpConv);
+                }
+                match (*field1_kind, *field2_kind) {
+                    (RegPassKind::Unknown, _) => {
+                        *field1_kind =
+                            RegPassKind::Float(Reg { kind: RegKind::Float, size: arg_layout.size });
+                    }
+                    (_, RegPassKind::Unknown) => {
+                        *field2_kind =
+                            RegPassKind::Float(Reg { kind: RegKind::Float, size: arg_layout.size });
+                    }
+                    _ => return Err(CannotUseFpConv),
+                }
+            }
+        },
+        Abi::Vector { .. } | Abi::Uninhabited => return Err(CannotUseFpConv),
+        Abi::ScalarPair(..) | Abi::Aggregate { .. } => match arg_layout.fields {
+            FieldsShape::Primitive => {
+                unreachable!("aggregates can't have `FieldsShape::Primitive`")
+            }
+            FieldsShape::Union(_) => {
+                if !arg_layout.is_zst() {
+                    return Err(CannotUseFpConv);
+                }
+            }
+            FieldsShape::Array { count, .. } => {
+                for _ in 0..count {
+                    let elem_layout = arg_layout.field(cx, 0);
+                    should_use_fp_conv_helper(
+                        cx,
+                        &elem_layout,
+                        xlen,
+                        flen,
+                        field1_kind,
+                        field2_kind,
+                    )?;
+                }
+            }
+            FieldsShape::Arbitrary { .. } => {
+                match arg_layout.variants {
+                    abi::Variants::Multiple { .. } => return Err(CannotUseFpConv),
+                    abi::Variants::Single { .. } => (),
+                }
+                for i in arg_layout.fields.index_by_increasing_offset() {
+                    let field = arg_layout.field(cx, i);
+                    should_use_fp_conv_helper(cx, &field, xlen, flen, field1_kind, field2_kind)?;
+                }
+            }
+        },
+    }
+    Ok(())
+}
+
+fn should_use_fp_conv<'a, Ty, C>(
+    cx: &C,
+    arg: &TyAndLayout<'a, Ty>,
+    xlen: u64,
+    flen: u64,
+) -> Option<FloatConv>
+where
+    Ty: TyAbiInterface<'a, C> + Copy,
+{
+    let mut field1_kind = RegPassKind::Unknown;
+    let mut field2_kind = RegPassKind::Unknown;
+    if should_use_fp_conv_helper(cx, arg, xlen, flen, &mut field1_kind, &mut field2_kind).is_err() {
+        return None;
+    }
+    match (field1_kind, field2_kind) {
+        (RegPassKind::Integer(l), RegPassKind::Float(r)) => Some(FloatConv::MixedPair(l, r)),
+        (RegPassKind::Float(l), RegPassKind::Integer(r)) => Some(FloatConv::MixedPair(l, r)),
+        (RegPassKind::Float(l), RegPassKind::Float(r)) => Some(FloatConv::FloatPair(l, r)),
+        (RegPassKind::Float(f), RegPassKind::Unknown) => Some(FloatConv::Float(f)),
+        _ => None,
+    }
+}
+
+fn classify_ret<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, xlen: u64, flen: u64) -> bool
+where
+    Ty: TyAbiInterface<'a, C> + Copy,
+{
+    if let Some(conv) = should_use_fp_conv(cx, &arg.layout, xlen, flen) {
+        match conv {
+            FloatConv::Float(f) => {
+                arg.cast_to(f);
+            }
+            FloatConv::FloatPair(l, r) => {
+                arg.cast_to(CastTarget::pair(l, r));
+            }
+            FloatConv::MixedPair(l, r) => {
+                arg.cast_to(CastTarget::pair(l, r));
+            }
+        }
+        return false;
+    }
+
+    let total = arg.layout.size;
+
+    // "Scalars wider than 2✕XLEN are passed by reference and are replaced in
+    // the argument list with the address."
+    // "Aggregates larger than 2✕XLEN bits are passed by reference and are
+    // replaced in the argument list with the address, as are C++ aggregates
+    // with nontrivial copy constructors, destructors, or vtables."
+    if total.bits() > 2 * xlen {
+        // We rely on the LLVM backend lowering code to lower passing a scalar larger than 2*XLEN.
+        if is_loongarch_aggregate(arg) {
+            arg.make_indirect();
+        }
+        return true;
+    }
+
+    let xlen_reg = match xlen {
+        32 => Reg::i32(),
+        64 => Reg::i64(),
+        _ => unreachable!("Unsupported XLEN: {}", xlen),
+    };
+    if is_loongarch_aggregate(arg) {
+        if total.bits() <= xlen {
+            arg.cast_to(xlen_reg);
+        } else {
+            arg.cast_to(Uniform { unit: xlen_reg, total: Size::from_bits(xlen * 2) });
+        }
+        return false;
+    }
+
+    // "When passed in registers, scalars narrower than XLEN bits are widened
+    // according to the sign of their type up to 32 bits, then sign-extended to
+    // XLEN bits."
+    extend_integer_width(arg, xlen);
+    false
+}
+
+fn classify_arg<'a, Ty, C>(
+    cx: &C,
+    arg: &mut ArgAbi<'a, Ty>,
+    xlen: u64,
+    flen: u64,
+    is_vararg: bool,
+    avail_gprs: &mut u64,
+    avail_fprs: &mut u64,
+) where
+    Ty: TyAbiInterface<'a, C> + Copy,
+{
+    if !is_vararg {
+        match should_use_fp_conv(cx, &arg.layout, xlen, flen) {
+            Some(FloatConv::Float(f)) if *avail_fprs >= 1 => {
+                *avail_fprs -= 1;
+                arg.cast_to(f);
+                return;
+            }
+            Some(FloatConv::FloatPair(l, r)) if *avail_fprs >= 2 => {
+                *avail_fprs -= 2;
+                arg.cast_to(CastTarget::pair(l, r));
+                return;
+            }
+            Some(FloatConv::MixedPair(l, r)) if *avail_fprs >= 1 && *avail_gprs >= 1 => {
+                *avail_gprs -= 1;
+                *avail_fprs -= 1;
+                arg.cast_to(CastTarget::pair(l, r));
+                return;
+            }
+            _ => (),
+        }
+    }
+
+    let total = arg.layout.size;
+    let align = arg.layout.align.abi.bits();
+
+    // "Scalars wider than 2✕XLEN are passed by reference and are replaced in
+    // the argument list with the address."
+    // "Aggregates larger than 2✕XLEN bits are passed by reference and are
+    // replaced in the argument list with the address, as are C++ aggregates
+    // with nontrivial copy constructors, destructors, or vtables."
+    if total.bits() > 2 * xlen {
+        // We rely on the LLVM backend lowering code to lower passing a scalar larger than 2*XLEN.
+        if is_loongarch_aggregate(arg) {
+            arg.make_indirect();
+        }
+        if *avail_gprs >= 1 {
+            *avail_gprs -= 1;
+        }
+        return;
+    }
+
+    let double_xlen_reg = match xlen {
+        32 => Reg::i64(),
+        64 => Reg::i128(),
+        _ => unreachable!("Unsupported XLEN: {}", xlen),
+    };
+
+    let xlen_reg = match xlen {
+        32 => Reg::i32(),
+        64 => Reg::i64(),
+        _ => unreachable!("Unsupported XLEN: {}", xlen),
+    };
+
+    if total.bits() > xlen {
+        let align_regs = align > xlen;
+        if is_loongarch_aggregate(arg) {
+            arg.cast_to(Uniform {
+                unit: if align_regs { double_xlen_reg } else { xlen_reg },
+                total: Size::from_bits(xlen * 2),
+            });
+        }
+        if align_regs && is_vararg {
+            *avail_gprs -= *avail_gprs % 2;
+        }
+        if *avail_gprs >= 2 {
+            *avail_gprs -= 2;
+        } else {
+            *avail_gprs = 0;
+        }
+        return;
+    } else if is_loongarch_aggregate(arg) {
+        arg.cast_to(xlen_reg);
+        if *avail_gprs >= 1 {
+            *avail_gprs -= 1;
+        }
+        return;
+    }
+
+    // "When passed in registers, scalars narrower than XLEN bits are widened
+    // according to the sign of their type up to 32 bits, then sign-extended to
+    // XLEN bits."
+    if *avail_gprs >= 1 {
+        extend_integer_width(arg, xlen);
+        *avail_gprs -= 1;
+    }
+}
+
+fn extend_integer_width<'a, Ty>(arg: &mut ArgAbi<'a, Ty>, xlen: u64) {
+    if let Abi::Scalar(scalar) = arg.layout.abi {
+        if let abi::Int(i, _) = scalar.primitive() {
+            // 32-bit integers are always sign-extended
+            if i.size().bits() == 32 && xlen > 32 {
+                if let PassMode::Direct(ref mut attrs) = arg.mode {
+                    attrs.ext(ArgExtension::Sext);
+                    return;
+                }
+            }
+        }
+    }
+
+    arg.extend_integer_width_to(xlen);
+}
+
+pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
+where
+    Ty: TyAbiInterface<'a, C> + Copy,
+    C: HasDataLayout + HasTargetSpec,
+{
+    let xlen = cx.data_layout().pointer_size.bits();
+    let flen = match &cx.target_spec().llvm_abiname[..] {
+        "ilp32f" | "lp64f" => 32,
+        "ilp32d" | "lp64d" => 64,
+        _ => 0,
+    };
+
+    let mut avail_gprs = 8;
+    let mut avail_fprs = 8;
+
+    if !fn_abi.ret.is_ignore() && classify_ret(cx, &mut fn_abi.ret, xlen, flen) {
+        avail_gprs -= 1;
+    }
+
+    for (i, arg) in fn_abi.args.iter_mut().enumerate() {
+        if arg.is_ignore() {
+            continue;
+        }
+        classify_arg(
+            cx,
+            arg,
+            xlen,
+            flen,
+            i >= fn_abi.fixed_count as usize,
+            &mut avail_gprs,
+            &mut avail_fprs,
+        );
+    }
+}
index 9e5f0e4d158b287b77460f68667c43163aac554d..c5a6f9893b6f9ec49a0a49123a2ae974bf3228d2 100644 (file)
@@ -10,6 +10,7 @@
 mod avr;
 mod bpf;
 mod hexagon;
+mod loongarch;
 mod m68k;
 mod mips;
 mod mips64;
@@ -696,6 +697,7 @@ pub fn adjust_for_foreign_abi<C>(
             "amdgpu" => amdgpu::compute_abi_info(cx, self),
             "arm" => arm::compute_abi_info(cx, self),
             "avr" => avr::compute_abi_info(self),
+            "loongarch64" => loongarch::compute_abi_info(cx, self),
             "m68k" => m68k::compute_abi_info(self),
             "mips" => mips::compute_abi_info(cx, self),
             "mips64" => mips64::compute_abi_info(cx, self),
index 7171ca7bf89508cdfb65db31f743e70e01c97376..decbefc2f7c622b8a4d85a95b3b97bb4bdeb7616 100644 (file)
@@ -1083,6 +1083,11 @@ pub fn is_unsized(&self) -> bool {
         }
     }
 
+    #[inline]
+    pub fn is_sized(&self) -> bool {
+        !self.is_unsized()
+    }
+
     /// Returns `true` if this is a single signed integer scalar
     #[inline]
     pub fn is_signed(&self) -> bool {
@@ -1490,6 +1495,11 @@ pub fn is_unsized(&self) -> bool {
         self.abi.is_unsized()
     }
 
+    #[inline]
+    pub fn is_sized(&self) -> bool {
+        self.abi.is_sized()
+    }
+
     /// Returns `true` if the type is a ZST and not unsized.
     pub fn is_zst(&self) -> bool {
         match self.abi {
index 6d919a4c2ad2e1221dd7e0bbf010f7ebfecc066f..0f6bbc323174cfb45dad1ffe4a388d1d323c2234 100644 (file)
@@ -1,26 +1,25 @@
+use super::apple_base::{macos_link_env_remove, macos_llvm_target, opts, Arch};
 use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let arch = "arm64";
-    let mut base = super::apple_base::opts("macos", arch, "");
+    let arch = Arch::Arm64;
+    let mut base = opts("macos", arch);
     base.cpu = "apple-a14".into();
     base.max_atomic_width = Some(128);
 
     // FIXME: The leak sanitizer currently fails the tests, see #88132.
     base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::THREAD;
 
-    base.link_env_remove.to_mut().extend(super::apple_base::macos_link_env_remove());
-
-    // Clang automatically chooses a more specific target based on
-    // MACOSX_DEPLOYMENT_TARGET.  To enable cross-language LTO to work
-    // correctly, we do too.
-    let llvm_target = super::apple_base::macos_llvm_target(arch);
+    base.link_env_remove.to_mut().extend(macos_link_env_remove());
 
     Target {
-        llvm_target: llvm_target.into(),
+        // Clang automatically chooses a more specific target based on
+        // MACOSX_DEPLOYMENT_TARGET.  To enable cross-language LTO to work
+        // correctly, we do too.
+        llvm_target: macos_llvm_target(arch).into(),
         pointer_width: 64,
         data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".into(),
-        arch: "aarch64".into(),
+        arch: arch.target_arch(),
         options: TargetOptions {
             mcount: "\u{1}mcount".into(),
             frame_pointer: FramePointer::NonLeaf,
index beb9042390b7fba1068e53d73ea29cf6120adbf2..b5f9eb1259dace3eaa02136daa9641416dc789aa 100644 (file)
@@ -1,19 +1,17 @@
-use super::apple_sdk_base::{opts, Arch};
+use super::apple_base::{ios_llvm_target, opts, Arch};
 use crate::spec::{FramePointer, Target, TargetOptions};
 
 pub fn target() -> Target {
-    // Clang automatically chooses a more specific target based on
-    // IPHONEOS_DEPLOYMENT_TARGET.
-    // This is required for the target to pick the right
-    // MACH-O commands, so we do too.
-    let arch = "arm64";
-    let llvm_target = super::apple_base::ios_llvm_target(arch);
-
+    let arch = Arch::Arm64;
     Target {
-        llvm_target: llvm_target.into(),
+        // Clang automatically chooses a more specific target based on
+        // IPHONEOS_DEPLOYMENT_TARGET.
+        // This is required for the target to pick the right
+        // MACH-O commands, so we do too.
+        llvm_target: ios_llvm_target(arch).into(),
         pointer_width: 64,
         data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".into(),
-        arch: "aarch64".into(),
+        arch: arch.target_arch(),
         options: TargetOptions {
             features: "+neon,+fp-armv8,+apple-a7".into(),
             max_atomic_width: Some(128),
@@ -30,7 +28,7 @@ pub fn target() -> Target {
                 darwinpcs\0\
                 -Os\0"
                 .into(),
-            ..opts("ios", Arch::Arm64)
+            ..opts("ios", arch)
         },
     }
 }
index 2d2671549cf5196dd6c8fbb1a6d6fa56433ed1e0..0009972cf425693c9134e84e5b1cf5e786d54a06 100644 (file)
@@ -1,17 +1,18 @@
-use super::apple_sdk_base::{opts, Arch};
+use super::apple_base::{opts, Arch};
 use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, Target, TargetOptions};
 
 pub fn target() -> Target {
     let llvm_target = "arm64-apple-ios14.0-macabi";
 
-    let mut base = opts("ios", Arch::Arm64_macabi);
+    let arch = Arch::Arm64_macabi;
+    let mut base = opts("ios", arch);
     base.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-target", llvm_target]);
 
     Target {
         llvm_target: llvm_target.into(),
         pointer_width: 64,
         data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".into(),
-        arch: "aarch64".into(),
+        arch: arch.target_arch(),
         options: TargetOptions {
             features: "+neon,+fp-armv8,+apple-a12".into(),
             max_atomic_width: Some(128),
index b4e135f66e9411e9c0fb348c91124e402ff481b7..3374755e2dd8b9631b622e31428739b995f434b3 100644 (file)
@@ -1,21 +1,17 @@
-use super::apple_sdk_base::{opts, Arch};
+use super::apple_base::{ios_sim_llvm_target, opts, Arch};
 use crate::spec::{FramePointer, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = opts("ios", Arch::Arm64_sim);
-
-    // Clang automatically chooses a more specific target based on
-    // IPHONEOS_DEPLOYMENT_TARGET.
-    // This is required for the simulator target to pick the right
-    // MACH-O commands, so we do too.
-    let arch = "arm64";
-    let llvm_target = super::apple_base::ios_sim_llvm_target(arch);
-
+    let arch = Arch::Arm64_sim;
     Target {
-        llvm_target: llvm_target.into(),
+        // Clang automatically chooses a more specific target based on
+        // IPHONEOS_DEPLOYMENT_TARGET.
+        // This is required for the simulator target to pick the right
+        // MACH-O commands, so we do too.
+        llvm_target: ios_sim_llvm_target(arch).into(),
         pointer_width: 64,
         data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".into(),
-        arch: "aarch64".into(),
+        arch: arch.target_arch(),
         options: TargetOptions {
             features: "+neon,+fp-armv8,+apple-a7".into(),
             max_atomic_width: Some(128),
@@ -32,7 +28,7 @@ pub fn target() -> Target {
                 darwinpcs\0\
                 -Os\0"
                 .into(),
-            ..base
+            ..opts("ios", arch)
         },
     }
 }
index 2e31d16dc76ca0cdc55c4be7cebd330f30325851..bb7c39ff26bdf5eede75e1cddda83cef7cbb8ff5 100644 (file)
@@ -1,18 +1,19 @@
-use super::apple_sdk_base::{opts, Arch};
+use super::apple_base::{opts, Arch};
 use crate::spec::{FramePointer, Target, TargetOptions};
 
 pub fn target() -> Target {
+    let arch = Arch::Arm64;
     Target {
         llvm_target: "arm64-apple-tvos".into(),
         pointer_width: 64,
         data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".into(),
-        arch: "aarch64".into(),
+        arch: arch.target_arch(),
         options: TargetOptions {
             features: "+neon,+fp-armv8,+apple-a7".into(),
             max_atomic_width: Some(128),
             forces_embed_bitcode: true,
             frame_pointer: FramePointer::NonLeaf,
-            ..opts("tvos", Arch::Arm64)
+            ..opts("tvos", arch)
         },
     }
 }
index 3059f42140be4178bbc63b7d561c39a22eb2529e..e4af4127c2223114f98a2442942e4eac3fab40b8 100644 (file)
@@ -1,21 +1,17 @@
-use super::apple_sdk_base::{opts, Arch};
+use super::apple_base::{opts, watchos_sim_llvm_target, Arch};
 use crate::spec::{FramePointer, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = opts("watchos", Arch::Arm64_sim);
-
-    // Clang automatically chooses a more specific target based on
-    // WATCHOS_DEPLOYMENT_TARGET.
-    // This is required for the simulator target to pick the right
-    // MACH-O commands, so we do too.
-    let arch = "arm64";
-    let llvm_target = super::apple_base::watchos_sim_llvm_target(arch);
-
+    let arch = Arch::Arm64_sim;
     Target {
-        llvm_target: llvm_target.into(),
+        // Clang automatically chooses a more specific target based on
+        // WATCHOS_DEPLOYMENT_TARGET.
+        // This is required for the simulator target to pick the right
+        // MACH-O commands, so we do too.
+        llvm_target: watchos_sim_llvm_target(arch).into(),
         pointer_width: 64,
         data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".into(),
-        arch: "aarch64".into(),
+        arch: arch.target_arch(),
         options: TargetOptions {
             features: "+neon,+fp-armv8,+apple-a7".into(),
             max_atomic_width: Some(128),
@@ -32,7 +28,7 @@ pub fn target() -> Target {
                 darwinpcs\0\
                 -Os\0"
                 .into(),
-            ..base
+            ..opts("watchos", arch)
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_nto_qnx_710.rs b/compiler/rustc_target/src/spec/aarch64_unknown_nto_qnx_710.rs
new file mode 100644 (file)
index 0000000..916b613
--- /dev/null
@@ -0,0 +1,28 @@
+use super::nto_qnx_base;
+use crate::spec::{Cc, LinkerFlavor, Lld, Target, TargetOptions};
+
+pub fn target() -> Target {
+    Target {
+        llvm_target: "aarch64-unknown-unknown".into(),
+        pointer_width: 64,
+        // from: https://llvm.org/docs/LangRef.html#data-layout
+        // e         = little endian
+        // m:e       = ELF mangling: Private symbols get a .L prefix
+        // i8:8:32   = 8-bit-integer, minimum_alignment=8, preferred_alignment=32
+        // i16:16:32 = 16-bit-integer, minimum_alignment=16, preferred_alignment=32
+        // i64:64    = 64-bit-integer, minimum_alignment=64, preferred_alignment=64
+        // i128:128  = 128-bit-integer, minimum_alignment=128, preferred_alignment=128
+        // n32:64    = 32 and 64 are native integer widths; Elements of this set are considered to support most general arithmetic operations efficiently.
+        // S128      = 128 bits are the natural alignment of the stack in bits.
+        data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(),
+        arch: "aarch64".into(),
+        options: TargetOptions {
+            max_atomic_width: Some(128),
+            pre_link_args: TargetOptions::link_args(
+                LinkerFlavor::Gnu(Cc::Yes, Lld::No),
+                &["-Vgcc_ntoaarch64le_cxx"],
+            ),
+            ..nto_qnx_base::opts()
+        },
+    }
+}
index 40bc59ca145e5f0d72eb467dcc46da0b192c552f..23c826cb1bda2922558bc2859845a16ec52c26cf 100644 (file)
@@ -3,7 +3,88 @@
 use crate::spec::{cvs, Cc, DebuginfoKind, FramePointer, LinkArgs};
 use crate::spec::{LinkerFlavor, Lld, SplitDebuginfo, StaticCow, TargetOptions};
 
-fn pre_link_args(os: &'static str, arch: &'static str, abi: &'static str) -> LinkArgs {
+#[cfg(test)]
+#[path = "apple/tests.rs"]
+mod tests;
+
+use Arch::*;
+#[allow(non_camel_case_types)]
+#[derive(Copy, Clone)]
+pub enum Arch {
+    Armv7,
+    Armv7k,
+    Armv7s,
+    Arm64,
+    Arm64_32,
+    I386,
+    I686,
+    X86_64,
+    X86_64_sim,
+    X86_64_macabi,
+    Arm64_macabi,
+    Arm64_sim,
+}
+
+impl Arch {
+    pub fn target_name(self) -> &'static str {
+        match self {
+            Armv7 => "armv7",
+            Armv7k => "armv7k",
+            Armv7s => "armv7s",
+            Arm64 | Arm64_macabi | Arm64_sim => "arm64",
+            Arm64_32 => "arm64_32",
+            I386 => "i386",
+            I686 => "i686",
+            X86_64 | X86_64_sim | X86_64_macabi => "x86_64",
+        }
+    }
+
+    pub fn target_arch(self) -> Cow<'static, str> {
+        Cow::Borrowed(match self {
+            Armv7 | Armv7k | Armv7s => "arm",
+            Arm64 | Arm64_32 | Arm64_macabi | Arm64_sim => "aarch64",
+            I386 | I686 => "x86",
+            X86_64 | X86_64_sim | X86_64_macabi => "x86_64",
+        })
+    }
+
+    fn target_abi(self) -> &'static str {
+        match self {
+            Armv7 | Armv7k | Armv7s | Arm64 | Arm64_32 | I386 | I686 | X86_64 => "",
+            X86_64_macabi | Arm64_macabi => "macabi",
+            // x86_64-apple-ios is a simulator target, even though it isn't
+            // declared that way in the target like the other ones...
+            Arm64_sim | X86_64_sim => "sim",
+        }
+    }
+
+    fn target_cpu(self) -> &'static str {
+        match self {
+            Armv7 => "cortex-a8", // iOS7 is supported on iPhone 4 and higher
+            Armv7k => "cortex-a8",
+            Armv7s => "cortex-a9",
+            Arm64 => "apple-a7",
+            Arm64_32 => "apple-s4",
+            I386 | I686 => "yonah",
+            X86_64 | X86_64_sim => "core2",
+            X86_64_macabi => "core2",
+            Arm64_macabi => "apple-a12",
+            Arm64_sim => "apple-a12",
+        }
+    }
+
+    fn link_env_remove(self) -> StaticCow<[StaticCow<str>]> {
+        match self {
+            Armv7 | Armv7k | Armv7s | Arm64 | Arm64_32 | I386 | I686 | X86_64 | X86_64_sim
+            | Arm64_sim => {
+                cvs!["MACOSX_DEPLOYMENT_TARGET"]
+            }
+            X86_64_macabi | Arm64_macabi => cvs!["IPHONEOS_DEPLOYMENT_TARGET"],
+        }
+    }
+}
+
+fn pre_link_args(os: &'static str, arch: Arch, abi: &'static str) -> LinkArgs {
     let platform_name: StaticCow<str> = match abi {
         "sim" => format!("{}-simulator", os).into(),
         "macabi" => "mac-catalyst".into(),
@@ -19,6 +100,8 @@ fn pre_link_args(os: &'static str, arch: &'static str, abi: &'static str) -> Lin
     }
     .into();
 
+    let arch = arch.target_name();
+
     let mut args = TargetOptions::link_args(
         LinkerFlavor::Darwin(Cc::No, Lld::No),
         &["-arch", arch, "-platform_version"],
@@ -35,24 +118,29 @@ fn pre_link_args(os: &'static str, arch: &'static str, abi: &'static str) -> Lin
     args
 }
 
-pub fn opts(os: &'static str, arch: &'static str, abi: &'static str) -> TargetOptions {
-    // ELF TLS is only available in macOS 10.7+. If you try to compile for 10.6
+pub fn opts(os: &'static str, arch: Arch) -> TargetOptions {
+    // Static TLS is only available in macOS 10.7+. If you try to compile for 10.6
     // either the linker will complain if it is used or the binary will end up
     // segfaulting at runtime when run on 10.6. Rust by default supports macOS
     // 10.7+, but there is a standard environment variable,
     // MACOSX_DEPLOYMENT_TARGET, which is used to signal targeting older
     // versions of macOS. For example compiling on 10.10 with
     // MACOSX_DEPLOYMENT_TARGET set to 10.6 will cause the linker to generate
-    // warnings about the usage of ELF TLS.
+    // warnings about the usage of static TLS.
     //
-    // Here we detect what version is being requested, defaulting to 10.7. ELF
+    // Here we detect what version is being requested, defaulting to 10.7. Static
     // TLS is flagged as enabled if it looks to be supported. The architecture
     // only matters for default deployment target which is 11.0 for ARM64 and
     // 10.7 for everything else.
-    let has_thread_local = macos_deployment_target("x86_64") >= (10, 7);
+    let has_thread_local = os == "macos" && macos_deployment_target(Arch::X86_64) >= (10, 7);
+
+    let abi = arch.target_abi();
 
     TargetOptions {
+        abi: abi.into(),
         os: os.into(),
+        cpu: arch.target_cpu().into(),
+        link_env_remove: arch.link_env_remove(),
         vendor: "apple".into(),
         linker_flavor: LinkerFlavor::Darwin(Cc::Yes, Lld::No),
         // macOS has -dead_strip, which doesn't rely on function_sections
@@ -103,23 +191,24 @@ fn deployment_target(var_name: &str) -> Option<(u32, u32)> {
         .and_then(|(a, b)| a.parse::<u32>().and_then(|a| b.parse::<u32>().map(|b| (a, b))).ok())
 }
 
-fn macos_default_deployment_target(arch: &str) -> (u32, u32) {
-    if arch == "arm64" { (11, 0) } else { (10, 7) }
+fn macos_default_deployment_target(arch: Arch) -> (u32, u32) {
+    // Note: Arm64_sim is not included since macOS has no simulator.
+    if matches!(arch, Arm64 | Arm64_macabi) { (11, 0) } else { (10, 7) }
 }
 
-fn macos_deployment_target(arch: &str) -> (u32, u32) {
+fn macos_deployment_target(arch: Arch) -> (u32, u32) {
     deployment_target("MACOSX_DEPLOYMENT_TARGET")
         .unwrap_or_else(|| macos_default_deployment_target(arch))
 }
 
-fn macos_lld_platform_version(arch: &str) -> String {
+fn macos_lld_platform_version(arch: Arch) -> String {
     let (major, minor) = macos_deployment_target(arch);
     format!("{}.{}", major, minor)
 }
 
-pub fn macos_llvm_target(arch: &str) -> String {
+pub fn macos_llvm_target(arch: Arch) -> String {
     let (major, minor) = macos_deployment_target(arch);
-    format!("{}-apple-macosx{}.{}.0", arch, major, minor)
+    format!("{}-apple-macosx{}.{}.0", arch.target_name(), major, minor)
 }
 
 pub fn macos_link_env_remove() -> Vec<StaticCow<str>> {
@@ -142,7 +231,7 @@ fn ios_deployment_target() -> (u32, u32) {
     deployment_target("IPHONEOS_DEPLOYMENT_TARGET").unwrap_or((7, 0))
 }
 
-pub fn ios_llvm_target(arch: &str) -> String {
+pub fn ios_llvm_target(arch: Arch) -> String {
     // Modern iOS tooling extracts information about deployment target
     // from LC_BUILD_VERSION. This load command will only be emitted when
     // we build with a version specific `llvm_target`, with the version
@@ -150,7 +239,7 @@ pub fn ios_llvm_target(arch: &str) -> String {
     // to pick it up (since std and core are still built with the fallback
     // of version 7.0 and hence emit the old LC_IPHONE_MIN_VERSION).
     let (major, minor) = ios_deployment_target();
-    format!("{}-apple-ios{}.{}.0", arch, major, minor)
+    format!("{}-apple-ios{}.{}.0", arch.target_name(), major, minor)
 }
 
 fn ios_lld_platform_version() -> String {
@@ -158,9 +247,9 @@ fn ios_lld_platform_version() -> String {
     format!("{}.{}", major, minor)
 }
 
-pub fn ios_sim_llvm_target(arch: &str) -> String {
+pub fn ios_sim_llvm_target(arch: Arch) -> String {
     let (major, minor) = ios_deployment_target();
-    format!("{}-apple-ios{}.{}.0-simulator", arch, major, minor)
+    format!("{}-apple-ios{}.{}.0-simulator", arch.target_name(), major, minor)
 }
 
 fn tvos_deployment_target() -> (u32, u32) {
@@ -181,7 +270,7 @@ fn watchos_lld_platform_version() -> String {
     format!("{}.{}", major, minor)
 }
 
-pub fn watchos_sim_llvm_target(arch: &str) -> String {
+pub fn watchos_sim_llvm_target(arch: Arch) -> String {
     let (major, minor) = watchos_deployment_target();
-    format!("{}-apple-watchos{}.{}.0-simulator", arch, major, minor)
+    format!("{}-apple-watchos{}.{}.0-simulator", arch.target_name(), major, minor)
 }
diff --git a/compiler/rustc_target/src/spec/apple_sdk_base.rs b/compiler/rustc_target/src/spec/apple_sdk_base.rs
deleted file mode 100644 (file)
index 148031b..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-use crate::spec::{cvs, TargetOptions};
-use std::borrow::Cow;
-
-#[cfg(test)]
-#[path = "apple/tests.rs"]
-mod tests;
-
-use Arch::*;
-#[allow(non_camel_case_types)]
-#[derive(Copy, Clone)]
-pub enum Arch {
-    Armv7,
-    Armv7k,
-    Armv7s,
-    Arm64,
-    Arm64_32,
-    I386,
-    #[allow(dead_code)] // Some targets don't use this enum...
-    X86_64,
-    X86_64_sim,
-    X86_64_macabi,
-    Arm64_macabi,
-    Arm64_sim,
-}
-
-fn target_arch_name(arch: Arch) -> &'static str {
-    match arch {
-        Armv7 => "armv7",
-        Armv7k => "armv7k",
-        Armv7s => "armv7s",
-        Arm64 | Arm64_macabi | Arm64_sim => "arm64",
-        Arm64_32 => "arm64_32",
-        I386 => "i386",
-        X86_64 | X86_64_sim | X86_64_macabi => "x86_64",
-    }
-}
-
-fn target_abi(arch: Arch) -> &'static str {
-    match arch {
-        Armv7 | Armv7k | Armv7s | Arm64 | Arm64_32 | I386 | X86_64 => "",
-        X86_64_macabi | Arm64_macabi => "macabi",
-        // x86_64-apple-ios is a simulator target, even though it isn't
-        // declared that way in the target like the other ones...
-        Arm64_sim | X86_64_sim => "sim",
-    }
-}
-
-fn target_cpu(arch: Arch) -> &'static str {
-    match arch {
-        Armv7 => "cortex-a8", // iOS7 is supported on iPhone 4 and higher
-        Armv7k => "cortex-a8",
-        Armv7s => "cortex-a9",
-        Arm64 => "apple-a7",
-        Arm64_32 => "apple-s4",
-        I386 => "yonah",
-        X86_64 | X86_64_sim => "core2",
-        X86_64_macabi => "core2",
-        Arm64_macabi => "apple-a12",
-        Arm64_sim => "apple-a12",
-    }
-}
-
-fn link_env_remove(arch: Arch) -> Cow<'static, [Cow<'static, str>]> {
-    match arch {
-        Armv7 | Armv7k | Armv7s | Arm64 | Arm64_32 | I386 | X86_64 | X86_64_sim | Arm64_sim => {
-            cvs!["MACOSX_DEPLOYMENT_TARGET"]
-        }
-        X86_64_macabi | Arm64_macabi => cvs!["IPHONEOS_DEPLOYMENT_TARGET"],
-    }
-}
-
-pub fn opts(os: &'static str, arch: Arch) -> TargetOptions {
-    let abi = target_abi(arch);
-    TargetOptions {
-        abi: abi.into(),
-        cpu: target_cpu(arch).into(),
-        link_env_remove: link_env_remove(arch),
-        has_thread_local: false,
-        ..super::apple_base::opts(os, target_arch_name(arch), abi)
-    }
-}
index cb7f5f2a5830bf8b274cc6e8fd2a08816b2f73a0..2cf2cbc7510009dec797f7137eabca3bb741bf4e 100644 (file)
@@ -1,4 +1,4 @@
-use super::apple_sdk_base::{opts, Arch};
+use super::apple_base::{opts, Arch};
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
index 57fd74a36b654501e6d9c78164f07e0ba417c2e9..3259c854791ce1849c465e03dbf691038c6b18f4 100644 (file)
@@ -1,18 +1,21 @@
-use super::apple_sdk_base::{opts, Arch};
+use super::apple_base::{ios_llvm_target, opts, Arch};
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let llvm_target = super::apple_base::ios_llvm_target("armv7");
-
+    let arch = Arch::Armv7;
     Target {
-        llvm_target: llvm_target.into(),
+        // Clang automatically chooses a more specific target based on
+        // IPHONEOS_DEPLOYMENT_TARGET.
+        // This is required for the target to pick the right
+        // MACH-O commands, so we do too.
+        llvm_target: ios_llvm_target(arch).into(),
         pointer_width: 32,
         data_layout: "e-m:o-p:32:32-Fi8-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32".into(),
-        arch: "arm".into(),
+        arch: arch.target_arch(),
         options: TargetOptions {
             features: "+v7,+vfp3,+neon".into(),
             max_atomic_width: Some(64),
-            ..opts("ios", Arch::Armv7)
+            ..opts("ios", arch)
         },
     }
 }
index af5d1c2ff45813f97615783bcf6ae8ee19974762..45ead8d65aba9919c6dc65d742b860c308d30c82 100644 (file)
@@ -1,13 +1,13 @@
-use super::apple_sdk_base::{opts, Arch};
+use super::apple_base::{opts, Arch};
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = opts("watchos", Arch::Armv7k);
+    let arch = Arch::Armv7k;
     Target {
         llvm_target: "armv7k-apple-watchos".into(),
         pointer_width: 32,
         data_layout: "e-m:o-p:32:32-Fi8-i64:64-a:0:32-n32-S128".into(),
-        arch: "arm".into(),
+        arch: arch.target_arch(),
         options: TargetOptions {
             features: "+v7,+vfp4,+neon".into(),
             max_atomic_width: Some(64),
@@ -22,7 +22,7 @@ pub fn target() -> Target {
                 darwinpcs\0\
                 -Os\0"
                 .into(),
-            ..base
+            ..opts("watchos", arch)
         },
     }
 }
index cc17265b2b8db6ce483e08fbed456cd575f3e502..be4bc6758443ec7ee51ea2c1fd67bde666581650 100644 (file)
@@ -1,16 +1,17 @@
-use super::apple_sdk_base::{opts, Arch};
+use super::apple_base::{opts, Arch};
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
+    let arch = Arch::Armv7s;
     Target {
         llvm_target: "armv7s-apple-ios".into(),
         pointer_width: 32,
         data_layout: "e-m:o-p:32:32-Fi8-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32".into(),
-        arch: "arm".into(),
+        arch: arch.target_arch(),
         options: TargetOptions {
             features: "+v7,+vfp4,+neon".into(),
             max_atomic_width: Some(64),
-            ..opts("ios", Arch::Armv7s)
+            ..opts("ios", arch)
         },
     }
 }
index b85214a9c6b4acd84d9627fbba3b45035a1536ce..5819981612e84a8a322ece52007d089f333f7a7d 100644 (file)
@@ -1,21 +1,23 @@
-use super::apple_sdk_base::{opts, Arch};
+use super::apple_base::{ios_sim_llvm_target, opts, Arch};
 use crate::spec::{StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = opts("ios", Arch::I386);
-    let llvm_target = super::apple_base::ios_sim_llvm_target("i386");
-
+    let arch = Arch::I386;
     Target {
-        llvm_target: llvm_target.into(),
+        // Clang automatically chooses a more specific target based on
+        // IPHONEOS_DEPLOYMENT_TARGET.
+        // This is required for the target to pick the right
+        // MACH-O commands, so we do too.
+        llvm_target: ios_sim_llvm_target(arch).into(),
         pointer_width: 32,
         data_layout: "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
             f64:32:64-f80:128-n8:16:32-S128"
             .into(),
-        arch: "x86".into(),
+        arch: arch.target_arch(),
         options: TargetOptions {
             max_atomic_width: Some(64),
             stack_probes: StackProbeType::X86,
-            ..base
+            ..opts("ios", arch)
         },
     }
 }
index 15607c12ea906c54ad95416d84a039caac439bd4..8b968af5eccff330a51e7aef34044de6b6b3ef82 100644 (file)
@@ -1,28 +1,28 @@
+use super::apple_base::{macos_link_env_remove, macos_llvm_target, opts, Arch};
 use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
-    // ld64 only understand i386 and not i686
-    let mut base = super::apple_base::opts("macos", "i386", "");
-    base.cpu = "yonah".into();
+    // ld64 only understands i386 and not i686
+    let arch = Arch::I386;
+    let mut base = opts("macos", arch);
     base.max_atomic_width = Some(64);
     base.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-m32"]);
-    base.link_env_remove.to_mut().extend(super::apple_base::macos_link_env_remove());
+    base.link_env_remove.to_mut().extend(macos_link_env_remove());
     base.stack_probes = StackProbeType::X86;
     base.frame_pointer = FramePointer::Always;
 
-    // Clang automatically chooses a more specific target based on
-    // MACOSX_DEPLOYMENT_TARGET.  To enable cross-language LTO to work
-    // correctly, we do too.
-    let arch = "i686";
-    let llvm_target = super::apple_base::macos_llvm_target(&arch);
-
     Target {
-        llvm_target: llvm_target.into(),
+        // Clang automatically chooses a more specific target based on
+        // MACOSX_DEPLOYMENT_TARGET.  To enable cross-language LTO to work
+        // correctly, we do too.
+        //
+        // While ld64 doesn't understand i686, LLVM does.
+        llvm_target: macos_llvm_target(Arch::I686).into(),
         pointer_width: 32,
         data_layout: "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
             f64:32:64-f80:128-n8:16:32-S128"
             .into(),
-        arch: "x86".into(),
+        arch: arch.target_arch(),
         options: TargetOptions { mcount: "\u{1}mcount".into(), ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/linux_kernel_base.rs b/compiler/rustc_target/src/spec/linux_kernel_base.rs
deleted file mode 100644 (file)
index f41533a..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-use crate::spec::TargetOptions;
-use crate::spec::{FramePointer, PanicStrategy, RelocModel, RelroLevel, StackProbeType};
-
-pub fn opts() -> TargetOptions {
-    TargetOptions {
-        env: "gnu".into(),
-        disable_redzone: true,
-        panic_strategy: PanicStrategy::Abort,
-        stack_probes: StackProbeType::X86,
-        frame_pointer: FramePointer::Always,
-        position_independent_executables: true,
-        needs_plt: true,
-        relro_level: RelroLevel::Full,
-        relocation_model: RelocModel::Static,
-
-        ..Default::default()
-    }
-}
index 72b088d663b1f0bafaf144cfe4a6273f3b71be4d..e809f646860b0b2f55778715e24b8f3775a15496 100644 (file)
@@ -59,7 +59,6 @@
 
 mod android_base;
 mod apple_base;
-mod apple_sdk_base;
 mod avr_gnu_base;
 mod bpf_base;
 mod dragonfly_base;
 mod l4re_base;
 mod linux_base;
 mod linux_gnu_base;
-mod linux_kernel_base;
 mod linux_musl_base;
 mod linux_uclibc_base;
 mod msvc_base;
 mod netbsd_base;
+mod nto_qnx_base;
 mod openbsd_base;
 mod redox_base;
 mod solaris_base;
@@ -1003,7 +1002,7 @@ mod tests {
             $(
                 #[test] // `#[test]`
                 fn $module() {
-                    tests_impl::test_target(super::$module::target(), $triple);
+                    tests_impl::test_target(super::$module::target());
                 }
             )+
         }
@@ -1071,8 +1070,6 @@ fn $module() {
     ("thumbv7neon-linux-androideabi", thumbv7neon_linux_androideabi),
     ("aarch64-linux-android", aarch64_linux_android),
 
-    ("x86_64-unknown-none-linuxkernel", x86_64_unknown_none_linuxkernel),
-
     ("aarch64-unknown-freebsd", aarch64_unknown_freebsd),
     ("armv6-unknown-freebsd", armv6_unknown_freebsd),
     ("armv7-unknown-freebsd", armv7_unknown_freebsd),
@@ -1246,6 +1243,9 @@ fn $module() {
     ("x86_64-unknown-none", x86_64_unknown_none),
 
     ("mips64-openwrt-linux-musl", mips64_openwrt_linux_musl),
+
+    ("aarch64-unknown-nto-qnx7.1.0", aarch64_unknown_nto_qnx_710),
+    ("x86_64-pc-nto-qnx7.1.0", x86_64_pc_nto_qnx710),
 }
 
 /// Cow-Vec-Str: Cow<'static, [Cow<'static, str>]>
@@ -1915,6 +1915,7 @@ pub fn adjust_abi(&self, abi: Abi) -> Abi {
                 Abi::Stdcall { unwind }
             }
             Abi::System { unwind } => Abi::C { unwind },
+            Abi::EfiApi if self.arch == "arm" => Abi::Aapcs { unwind: false },
             Abi::EfiApi if self.arch == "x86_64" => Abi::Win64 { unwind: false },
             Abi::EfiApi => Abi::C { unwind: false },
 
@@ -1941,8 +1942,10 @@ pub fn is_abi_supported(&self, abi: Abi) -> Option<bool> {
             | PlatformIntrinsic
             | Unadjusted
             | Cdecl { .. }
-            | EfiApi
             | RustCold => true,
+            EfiApi => {
+                ["arm", "aarch64", "riscv32", "riscv64", "x86", "x86_64"].contains(&&self.arch[..])
+            }
             X86Interrupt => ["x86", "x86_64"].contains(&&self.arch[..]),
             Aapcs { .. } => "arm" == self.arch,
             CCmseNonSecureCall => ["arm", "aarch64"].contains(&&self.arch[..]),
diff --git a/compiler/rustc_target/src/spec/nto_qnx_base.rs b/compiler/rustc_target/src/spec/nto_qnx_base.rs
new file mode 100644 (file)
index 0000000..6fb581e
--- /dev/null
@@ -0,0 +1,19 @@
+use crate::spec::{cvs, RelroLevel, TargetOptions};
+
+pub fn opts() -> TargetOptions {
+    TargetOptions {
+        crt_static_respected: true,
+        dynamic_linking: true,
+        env: "nto71".into(),
+        executables: true,
+        families: cvs!["unix"],
+        has_rpath: true,
+        has_thread_local: false,
+        linker: Some("qcc".into()),
+        os: "nto".into(),
+        position_independent_executables: true,
+        static_position_independent_executables: true,
+        relro_level: RelroLevel::Full,
+        ..Default::default()
+    }
+}
index 172da0ed5df88d5f5b848981bbdc27e32eabc90c..e0ecf8037c3e59a4086582342b9a18342ae6a67c 100644 (file)
@@ -2,15 +2,15 @@
 use std::assert_matches::assert_matches;
 
 // Test target self-consistency and JSON encoding/decoding roundtrip.
-pub(super) fn test_target(mut target: Target, triple: &str) {
+pub(super) fn test_target(mut target: Target) {
     let recycled_target = Target::from_json(target.to_json()).map(|(j, _)| j);
     target.update_to_cli();
-    target.check_consistency(triple);
+    target.check_consistency();
     assert_eq!(recycled_target, Ok(target));
 }
 
 impl Target {
-    fn check_consistency(&self, triple: &str) {
+    fn check_consistency(&self) {
         assert_eq!(self.is_like_osx, self.vendor == "apple");
         assert_eq!(self.is_like_solaris, self.os == "solaris" || self.os == "illumos");
         assert_eq!(self.is_like_windows, self.os == "windows" || self.os == "uefi");
@@ -129,8 +129,7 @@ fn check_consistency(&self, triple: &str) {
         if self.dynamic_linking && !(self.is_like_wasm && self.os != "emscripten") {
             assert_eq!(self.relocation_model, RelocModel::Pic);
         }
-        // PIEs are supported but not enabled by default with linuxkernel target.
-        if self.position_independent_executables && !triple.ends_with("-linuxkernel") {
+        if self.position_independent_executables {
             assert_eq!(self.relocation_model, RelocModel::Pic);
         }
         // The UEFI targets do not support dynamic linking but still require PIC (#101377).
index 58210c75a3da22364b60e734f4735e1101402f06..cada28652f98a79db8df2ac514a8fac9d22bc13a 100644 (file)
@@ -1,4 +1,5 @@
-use crate::spec::{cvs, Cc, LinkerFlavor, Lld, TargetOptions};
+use crate::spec::{cvs, Cc, DebuginfoKind, LinkerFlavor, Lld, SplitDebuginfo, TargetOptions};
+use std::borrow::Cow;
 
 pub fn opts() -> TargetOptions {
     // We cannot use `-nodefaultlibs` because compiler-rt has to be passed
@@ -36,7 +37,10 @@ pub fn opts() -> TargetOptions {
         eh_frame_header: false,
         no_default_libraries: false,
         has_thread_local: true,
-
+        // FIXME(davidtwco): Support Split DWARF on Windows GNU - may require LLVM changes to
+        // output DWO, despite using DWARF, doesn't use ELF..
+        debuginfo_kind: DebuginfoKind::Pdb,
+        supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]),
         ..Default::default()
     }
 }
index 087be1b957b1425885bc5303efe8cdc05065682a..c053031612ce5369575731e710bdcfd395b76116 100644 (file)
@@ -1,29 +1,27 @@
+use super::apple_base::{macos_link_env_remove, macos_llvm_target, opts, Arch};
 use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, SanitizerSet};
 use crate::spec::{StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let arch = "x86_64";
-    let mut base = super::apple_base::opts("macos", arch, "");
-    base.cpu = "core2".into();
-    base.max_atomic_width = Some(128); // core2 support cmpxchg16b
+    let arch = Arch::X86_64;
+    let mut base = opts("macos", arch);
+    base.max_atomic_width = Some(128); // core2 supports cmpxchg16b
     base.frame_pointer = FramePointer::Always;
     base.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-m64"]);
-    base.link_env_remove.to_mut().extend(super::apple_base::macos_link_env_remove());
+    base.link_env_remove.to_mut().extend(macos_link_env_remove());
     base.stack_probes = StackProbeType::X86;
     base.supported_sanitizers =
         SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::LEAK | SanitizerSet::THREAD;
 
-    // Clang automatically chooses a more specific target based on
-    // MACOSX_DEPLOYMENT_TARGET.  To enable cross-language LTO to work
-    // correctly, we do too.
-    let llvm_target = super::apple_base::macos_llvm_target(&arch);
-
     Target {
-        llvm_target: llvm_target.into(),
+        // Clang automatically chooses a more specific target based on
+        // MACOSX_DEPLOYMENT_TARGET.  To enable cross-language LTO to work
+        // correctly, we do too.
+        llvm_target: macos_llvm_target(arch).into(),
         pointer_width: 64,
         data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .into(),
-        arch: arch.into(),
+        arch: arch.target_arch(),
         options: TargetOptions { mcount: "\u{1}mcount".into(), ..base },
     }
 }
index db23f01c233265c17bf20e27627eefc3402f181b..fbd3ebd4d0431eba64044605b1d8b8a9beba7640 100644 (file)
@@ -1,20 +1,18 @@
-use super::apple_sdk_base::{opts, Arch};
+use super::apple_base::{ios_sim_llvm_target, opts, Arch};
 use crate::spec::{StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = opts("ios", Arch::X86_64_sim);
-    let llvm_target = super::apple_base::ios_sim_llvm_target("x86_64");
-
+    let arch = Arch::X86_64_sim;
     Target {
-        llvm_target: llvm_target.into(),
+        llvm_target: ios_sim_llvm_target(arch).into(),
         pointer_width: 64,
         data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .into(),
-        arch: "x86_64".into(),
+        arch: arch.target_arch(),
         options: TargetOptions {
             max_atomic_width: Some(64),
             stack_probes: StackProbeType::X86,
-            ..base
+            ..opts("ios", arch)
         },
     }
 }
index 13259205ac0f87fd088caf9932e53f8dcf18c85c..0f3f8519963778d172d4ef5b164c100d71da2139 100644 (file)
@@ -1,10 +1,11 @@
-use super::apple_sdk_base::{opts, Arch};
+use super::apple_base::{opts, Arch};
 use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
     let llvm_target = "x86_64-apple-ios13.0-macabi";
 
-    let mut base = opts("ios", Arch::X86_64_macabi);
+    let arch = Arch::X86_64_macabi;
+    let mut base = opts("ios", arch);
     base.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-target", llvm_target]);
 
     Target {
@@ -12,7 +13,7 @@ pub fn target() -> Target {
         pointer_width: 64,
         data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .into(),
-        arch: "x86_64".into(),
+        arch: arch.target_arch(),
         options: TargetOptions {
             max_atomic_width: Some(64),
             stack_probes: StackProbeType::X86,
index c1fd8e1c8b90ac0b212d03e8d81a8ad308932b76..550ce0b9ce577e0584a020d92a42d186ea9d2974 100644 (file)
@@ -1,17 +1,17 @@
-use super::apple_sdk_base::{opts, Arch};
+use super::apple_base::{opts, Arch};
 use crate::spec::{StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = opts("tvos", Arch::X86_64_sim);
+    let arch = Arch::X86_64_sim;
     Target {
         llvm_target: "x86_64-apple-tvos".into(),
         pointer_width: 64,
         data_layout: "e-m:o-i64:64-f80:128-n8:16:32:64-S128".into(),
-        arch: "x86_64".into(),
+        arch: arch.target_arch(),
         options: TargetOptions {
             max_atomic_width: Some(64),
             stack_probes: StackProbeType::X86,
-            ..base
+            ..opts("tvos", arch)
         },
     }
 }
index 550566b2aa754dc48c295e9ac1e673e3e16f4cf9..75ce02cba1de0623be381ab2b4b396860b69b23a 100644 (file)
@@ -1,18 +1,14 @@
-use super::apple_sdk_base::{opts, Arch};
+use super::apple_base::{opts, watchos_sim_llvm_target, Arch};
 use crate::spec::{StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = opts("watchos", Arch::X86_64_sim);
-
-    let arch = "x86_64";
-    let llvm_target = super::apple_base::watchos_sim_llvm_target(arch);
-
+    let arch = Arch::X86_64_sim;
     Target {
-        llvm_target: llvm_target.into(),
+        llvm_target: watchos_sim_llvm_target(arch).into(),
         pointer_width: 64,
         data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .into(),
-        arch: "x86_64".into(),
+        arch: arch.target_arch(),
         options: TargetOptions {
             max_atomic_width: Some(64),
             stack_probes: StackProbeType::X86,
@@ -28,7 +24,7 @@ pub fn target() -> Target {
                 darwinpcs\0\
                 -Os\0"
                 .into(),
-            ..base
+            ..opts("watchos", arch)
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_pc_nto_qnx710.rs b/compiler/rustc_target/src/spec/x86_64_pc_nto_qnx710.rs
new file mode 100644 (file)
index 0000000..e9b3ace
--- /dev/null
@@ -0,0 +1,21 @@
+use super::nto_qnx_base;
+use crate::spec::{Cc, LinkerFlavor, Lld, Target, TargetOptions};
+
+pub fn target() -> Target {
+    Target {
+        llvm_target: "x86_64-pc-unknown".into(),
+        pointer_width: 64,
+        data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+            .into(),
+        arch: "x86_64".into(),
+        options: TargetOptions {
+            cpu: "x86-64".into(),
+            max_atomic_width: Some(64),
+            pre_link_args: TargetOptions::link_args(
+                LinkerFlavor::Gnu(Cc::Yes, Lld::No),
+                &["-Vgcc_ntox86_64_cxx"],
+            ),
+            ..nto_qnx_base::opts()
+        },
+    }
+}
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_none_linuxkernel.rs b/compiler/rustc_target/src/spec/x86_64_unknown_none_linuxkernel.rs
deleted file mode 100644 (file)
index ebd9636..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-// This defines the amd64 target for the Linux Kernel. See the linux-kernel-base module for
-// generic Linux kernel options.
-
-use crate::spec::{Cc, CodeModel, LinkerFlavor, Lld, Target};
-
-pub fn target() -> Target {
-    let mut base = super::linux_kernel_base::opts();
-    base.cpu = "x86-64".into();
-    base.max_atomic_width = Some(64);
-    base.features =
-        "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float".into();
-    base.code_model = Some(CodeModel::Kernel);
-    base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
-
-    Target {
-        // FIXME: Some dispute, the linux-on-clang folks think this should use
-        // "Linux". We disagree because running *on* Linux is nothing like
-        // running *as" linux, and historically the "os" component as has always
-        // been used to mean the "on" part.
-        llvm_target: "x86_64-unknown-none-elf".into(),
-        pointer_width: 64,
-        data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
-            .into(),
-        arch: "x86_64".into(),
-
-        options: base,
-    }
-}
index 61cfeec4bbb6ef5301569304686a760010306df9..54c738d8389759859103ae149b82fe915934ca59 100644 (file)
@@ -1,6 +1,6 @@
 use crate::errors::AutoDerefReachedRecursionLimit;
 use crate::traits::query::evaluate_obligation::InferCtxtExt;
-use crate::traits::{self, TraitEngine};
+use crate::traits::{self, TraitEngine, TraitEngineExt};
 use rustc_hir as hir;
 use rustc_infer::infer::InferCtxt;
 use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt};
@@ -27,7 +27,6 @@ pub struct Autoderef<'a, 'tcx> {
     // Meta infos:
     infcx: &'a InferCtxt<'tcx>,
     span: Span,
-    overloaded_span: Span,
     body_id: hir::HirId,
     param_env: ty::ParamEnv<'tcx>,
 
@@ -99,12 +98,10 @@ pub fn new(
         body_id: hir::HirId,
         span: Span,
         base_ty: Ty<'tcx>,
-        overloaded_span: Span,
     ) -> Autoderef<'a, 'tcx> {
         Autoderef {
             infcx,
             span,
-            overloaded_span,
             body_id,
             param_env,
             state: AutoderefSnapshot {
@@ -142,7 +139,7 @@ fn overloaded_deref_ty(&mut self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
             return None;
         }
 
-        let mut fulfillcx = traits::FulfillmentContext::new_in_snapshot();
+        let mut fulfillcx = <dyn TraitEngine<'tcx>>::new_in_snapshot(tcx);
         let normalized_ty = fulfillcx.normalize_projection_type(
             &self.infcx,
             self.param_env,
@@ -193,10 +190,6 @@ pub fn span(&self) -> Span {
         self.span
     }
 
-    pub fn overloaded_span(&self) -> Span {
-        self.overloaded_span
-    }
-
     pub fn reached_recursion_limit(&self) -> bool {
         self.state.reached_recursion_limit
     }
index 5d52aa07523012329dada901b8e2e2cebf978a0c..2dce18e2d3cad263dc36aeacd3469aa18c1ec9ac 100644 (file)
@@ -10,7 +10,6 @@
 //!
 //! This API is completely unstable and subject to change.
 
-#![allow(rustc::potential_query_instability)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(box_patterns)]
 #![feature(control_flow_enum)]
index ed34ab95ad6c00009e96e4b4b81062525d40d427..188f8bb7e2a58cd9815015a278b35dc4154936e9 100644 (file)
@@ -12,7 +12,7 @@
 use rustc_middle::ty::visit::TypeVisitable;
 use rustc_middle::ty::{PolyTraitRef, Region, RegionVid};
 
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
 
 use std::collections::hash_map::Entry;
 use std::collections::VecDeque;
@@ -27,8 +27,8 @@ pub enum RegionTarget<'tcx> {
 
 #[derive(Default, Debug, Clone)]
 pub struct RegionDeps<'tcx> {
-    larger: FxHashSet<RegionTarget<'tcx>>,
-    smaller: FxHashSet<RegionTarget<'tcx>>,
+    larger: FxIndexSet<RegionTarget<'tcx>>,
+    smaller: FxIndexSet<RegionTarget<'tcx>>,
 }
 
 pub enum AutoTraitResult<A> {
@@ -266,7 +266,7 @@ fn evaluate_predicates(
         }));
 
         let computed_preds = param_env.caller_bounds().iter();
-        let mut user_computed_preds: FxHashSet<_> = user_env.caller_bounds().iter().collect();
+        let mut user_computed_preds: FxIndexSet<_> = user_env.caller_bounds().iter().collect();
 
         let mut new_env = param_env;
         let dummy_cause = ObligationCause::dummy();
@@ -389,7 +389,7 @@ fn evaluate_predicates(
     /// not just one specific lifetime (e.g., `'static`).
     fn add_user_pred(
         &self,
-        user_computed_preds: &mut FxHashSet<ty::Predicate<'tcx>>,
+        user_computed_preds: &mut FxIndexSet<ty::Predicate<'tcx>>,
         new_pred: ty::Predicate<'tcx>,
     ) {
         let mut should_add_new = true;
@@ -585,7 +585,7 @@ fn evaluate_nested_obligations(
         &self,
         ty: Ty<'_>,
         nested: impl Iterator<Item = Obligation<'tcx, ty::Predicate<'tcx>>>,
-        computed_preds: &mut FxHashSet<ty::Predicate<'tcx>>,
+        computed_preds: &mut FxIndexSet<ty::Predicate<'tcx>>,
         fresh_preds: &mut FxHashSet<ty::Predicate<'tcx>>,
         predicates: &mut VecDeque<ty::PolyTraitPredicate<'tcx>>,
         select: &mut SelectionContext<'_, 'tcx>,
index 81e1d64493e14f3e84e497865ad19e9a27b2e725..8f9d5eaac9d1d5ac9e35adb52ef62d7d9dfcc6b3 100644 (file)
@@ -14,15 +14,22 @@ pub struct FulfillmentContext<'tcx> {
     obligations: FxIndexSet<PredicateObligation<'tcx>>,
 
     relationships: FxHashMap<ty::TyVid, ty::FoundRelationships>,
+
+    usable_in_snapshot: bool,
 }
 
 impl FulfillmentContext<'_> {
-    pub(crate) fn new() -> Self {
+    pub(super) fn new() -> Self {
         FulfillmentContext {
             obligations: FxIndexSet::default(),
             relationships: FxHashMap::default(),
+            usable_in_snapshot: false,
         }
     }
+
+    pub(crate) fn new_in_snapshot() -> Self {
+        FulfillmentContext { usable_in_snapshot: true, ..Self::new() }
+    }
 }
 
 impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
@@ -41,7 +48,9 @@ fn register_predicate_obligation(
         infcx: &InferCtxt<'tcx>,
         obligation: PredicateObligation<'tcx>,
     ) {
-        assert!(!infcx.is_in_snapshot());
+        if !self.usable_in_snapshot {
+            assert!(!infcx.is_in_snapshot());
+        }
         let obligation = infcx.resolve_vars_if_possible(obligation);
 
         super::relationships::update(self, infcx, &obligation);
@@ -72,7 +81,9 @@ fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentErr
     }
 
     fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
-        assert!(!infcx.is_in_snapshot());
+        if !self.usable_in_snapshot {
+            assert!(!infcx.is_in_snapshot());
+        }
 
         let mut errors = Vec::new();
         let mut next_round = FxIndexSet::default();
index 21516c93efb53aa8b33e681938a61c1701f54d35..ae29c9f5617911245a6d733ddab8647f1d45204b 100644 (file)
@@ -4,7 +4,7 @@
 use super::TraitEngine;
 use super::{ChalkFulfillmentContext, FulfillmentContext};
 use crate::infer::InferCtxtExt;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_infer::infer::at::ToTrace;
 use rustc_infer::infer::canonical::{
@@ -38,7 +38,7 @@ fn new(tcx: TyCtxt<'tcx>) -> Box<Self> {
 
     fn new_in_snapshot(tcx: TyCtxt<'tcx>) -> Box<Self> {
         if tcx.sess.opts.unstable_opts.chalk {
-            Box::new(ChalkFulfillmentContext::new())
+            Box::new(ChalkFulfillmentContext::new_in_snapshot())
         } else {
             Box::new(FulfillmentContext::new_in_snapshot())
         }
@@ -119,13 +119,10 @@ pub fn eq<T: ToTrace<'tcx>>(
         expected: T,
         actual: T,
     ) -> Result<(), TypeError<'tcx>> {
-        match self.infcx.at(cause, param_env).eq(expected, actual) {
-            Ok(InferOk { obligations, value: () }) => {
-                self.register_obligations(obligations);
-                Ok(())
-            }
-            Err(e) => Err(e),
-        }
+        self.infcx
+            .at(cause, param_env)
+            .eq(expected, actual)
+            .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
     }
 
     pub fn sup<T: ToTrace<'tcx>>(
@@ -144,6 +141,10 @@ pub fn sup<T: ToTrace<'tcx>>(
         }
     }
 
+    pub fn select_where_possible(&self) -> Vec<FulfillmentError<'tcx>> {
+        self.engine.borrow_mut().select_where_possible(self.infcx)
+    }
+
     pub fn select_all_or_error(&self) -> Vec<FulfillmentError<'tcx>> {
         self.engine.borrow_mut().select_all_or_error(self.infcx)
     }
@@ -153,10 +154,10 @@ pub fn assumed_wf_types(
         param_env: ty::ParamEnv<'tcx>,
         span: Span,
         def_id: LocalDefId,
-    ) -> FxHashSet<Ty<'tcx>> {
+    ) -> FxIndexSet<Ty<'tcx>> {
         let tcx = self.infcx.tcx;
         let assumed_wf_types = tcx.assumed_wf_types(def_id);
-        let mut implied_bounds = FxHashSet::default();
+        let mut implied_bounds = FxIndexSet::default();
         let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
         let cause = ObligationCause::misc(span, hir_id);
         for ty in assumed_wf_types {
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs
new file mode 100644 (file)
index 0000000..58da54a
--- /dev/null
@@ -0,0 +1,52 @@
+use rustc_hir::def_id::DefId;
+use rustc_infer::infer::InferCtxt;
+use rustc_infer::traits::{Obligation, ObligationCause, TraitObligation};
+use rustc_span::DUMMY_SP;
+
+use crate::traits::ObligationCtxt;
+
+pub fn recompute_applicable_impls<'tcx>(
+    infcx: &InferCtxt<'tcx>,
+    obligation: &TraitObligation<'tcx>,
+) -> Vec<DefId> {
+    let tcx = infcx.tcx;
+    let param_env = obligation.param_env;
+    let dummy_cause = ObligationCause::dummy();
+    let impl_may_apply = |impl_def_id| {
+        let ocx = ObligationCtxt::new_in_snapshot(infcx);
+        let placeholder_obligation =
+            infcx.replace_bound_vars_with_placeholders(obligation.predicate);
+        let obligation_trait_ref =
+            ocx.normalize(dummy_cause.clone(), param_env, placeholder_obligation.trait_ref);
+
+        let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
+        let impl_trait_ref = tcx.bound_impl_trait_ref(impl_def_id).unwrap().subst(tcx, impl_substs);
+        let impl_trait_ref = ocx.normalize(ObligationCause::dummy(), param_env, impl_trait_ref);
+
+        if let Err(_) = ocx.eq(&dummy_cause, param_env, obligation_trait_ref, impl_trait_ref) {
+            return false;
+        }
+
+        let impl_predicates = tcx.predicates_of(impl_def_id).instantiate(tcx, impl_substs);
+        ocx.register_obligations(
+            impl_predicates
+                .predicates
+                .iter()
+                .map(|&predicate| Obligation::new(dummy_cause.clone(), param_env, predicate)),
+        );
+
+        ocx.select_where_possible().is_empty()
+    };
+
+    let mut impls = Vec::new();
+    tcx.for_each_relevant_impl(
+        obligation.predicate.def_id(),
+        obligation.predicate.skip_binder().trait_ref.self_ty(),
+        |impl_def_id| {
+            if infcx.probe(move |_snapshot| impl_may_apply(impl_def_id)) {
+                impls.push(impl_def_id)
+            }
+        },
+    );
+    impls
+}
index 54281f91205476b0605c4103c80c682bded4ab3c..98c13ffdafb029f12aa273587a287cc7f9c8977d 100644 (file)
@@ -1,17 +1,22 @@
+mod ambiguity;
 pub mod on_unimplemented;
 pub mod suggestions;
 
 use super::{
-    FulfillmentContext, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes,
-    Obligation, ObligationCause, ObligationCauseCode, OnUnimplementedDirective,
-    OnUnimplementedNote, OutputTypeParameterMismatch, Overflow, PredicateObligation,
+    FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes, Obligation, ObligationCause,
+    ObligationCauseCode, OutputTypeParameterMismatch, Overflow, PredicateObligation,
     SelectionContext, SelectionError, TraitNotObjectSafe,
 };
-
 use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode};
 use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use crate::infer::{self, InferCtxt, TyCtxtInferExt};
-use rustc_data_structures::fx::FxHashMap;
+use crate::traits::engine::TraitEngineExt as _;
+use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
+use crate::traits::query::normalize::AtExt as _;
+use crate::traits::specialize::to_pretty_impl_header;
+use on_unimplemented::OnUnimplementedNote;
+use on_unimplemented::TypeErrCtxtExt as _;
+use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_errors::{
     pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
     MultiSpan, Style,
 use std::fmt;
 use std::iter;
 use std::ops::ControlFlow;
-
-use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
-use crate::traits::query::normalize::AtExt as _;
-use crate::traits::specialize::to_pretty_impl_header;
-use on_unimplemented::TypeErrCtxtExt as _;
 use suggestions::TypeErrCtxtExt as _;
 
 pub use rustc_infer::traits::error_reporting::*;
@@ -101,7 +101,6 @@ fn report_fulfillment_errors(
         &self,
         errors: &[FulfillmentError<'tcx>],
         body_id: Option<hir::BodyId>,
-        fallback_has_occurred: bool,
     ) -> ErrorGuaranteed;
 
     fn report_overflow_error<T>(
@@ -124,7 +123,6 @@ fn report_selection_error(
         obligation: PredicateObligation<'tcx>,
         root_obligation: &PredicateObligation<'tcx>,
         error: &SelectionError<'tcx>,
-        fallback_has_occurred: bool,
     );
 }
 
@@ -355,7 +353,7 @@ fn type_implements_fn_trait(
                     })
                     .to_predicate(self.tcx),
                 );
-                let mut fulfill_cx = FulfillmentContext::new_in_snapshot();
+                let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new_in_snapshot(self.tcx);
                 fulfill_cx.register_predicate_obligation(self, obligation);
                 if fulfill_cx.select_all_or_error(self).is_empty() {
                     return Ok((
@@ -375,7 +373,6 @@ fn report_fulfillment_errors(
         &self,
         errors: &[FulfillmentError<'tcx>],
         body_id: Option<hir::BodyId>,
-        fallback_has_occurred: bool,
     ) -> ErrorGuaranteed {
         #[derive(Debug)]
         struct ErrorDescriptor<'tcx> {
@@ -383,7 +380,7 @@ struct ErrorDescriptor<'tcx> {
             index: Option<usize>, // None if this is an old error
         }
 
-        let mut error_map: FxHashMap<_, Vec<_>> = self
+        let mut error_map: FxIndexMap<_, Vec<_>> = self
             .reported_trait_errors
             .borrow()
             .iter()
@@ -452,7 +449,7 @@ struct ErrorDescriptor<'tcx> {
 
         for (error, suppressed) in iter::zip(errors, is_suppressed) {
             if !suppressed {
-                self.report_fulfillment_error(error, body_id, fallback_has_occurred);
+                self.report_fulfillment_error(error, body_id);
             }
         }
 
@@ -534,22 +531,12 @@ fn report_selection_error(
         mut obligation: PredicateObligation<'tcx>,
         root_obligation: &PredicateObligation<'tcx>,
         error: &SelectionError<'tcx>,
-        fallback_has_occurred: bool,
     ) {
         self.set_tainted_by_errors();
         let tcx = self.tcx;
         let mut span = obligation.cause.span;
 
         let mut err = match *error {
-            SelectionError::Ambiguous(ref impls) => {
-                let mut err = self.tcx.sess.struct_span_err(
-                    obligation.cause.span,
-                    &format!("multiple applicable `impl`s for `{}`", obligation.predicate),
-                );
-                self.annotate_source_of_ambiguity(&mut err, impls, obligation.predicate);
-                err.emit();
-                return;
-            }
             SelectionError::Unimplemented => {
                 // If this obligation was generated as a result of well-formedness checking, see if we
                 // can get a better error message by performing HIR-based well-formedness checking.
@@ -1015,7 +1002,7 @@ fn report_selection_error(
                         // variable that used to fallback to `()` now falling back to `!`. Issue a
                         // note informing about the change in behaviour.
                         if trait_predicate.skip_binder().self_ty().is_never()
-                            && fallback_has_occurred
+                            && self.fallback_has_occurred
                         {
                             let predicate = trait_predicate.map_bound(|mut trait_pred| {
                                 trait_pred.trait_ref.substs = self.tcx.mk_substs_trait(
@@ -1381,7 +1368,6 @@ fn report_fulfillment_error(
         &self,
         error: &FulfillmentError<'tcx>,
         body_id: Option<hir::BodyId>,
-        fallback_has_occurred: bool,
     );
 
     fn report_projection_error(
@@ -1531,7 +1517,6 @@ fn report_fulfillment_error(
         &self,
         error: &FulfillmentError<'tcx>,
         body_id: Option<hir::BodyId>,
-        fallback_has_occurred: bool,
     ) {
         match error.code {
             FulfillmentErrorCode::CodeSelectionError(ref selection_error) => {
@@ -1539,7 +1524,6 @@ fn report_fulfillment_error(
                     error.obligation.clone(),
                     &error.root_obligation,
                     selection_error,
-                    fallback_has_occurred,
                 );
             }
             FulfillmentErrorCode::CodeProjectionError(ref e) => {
@@ -2153,12 +2137,25 @@ fn maybe_report_ambiguity(
                     crate::traits::TraitQueryMode::Standard,
                 );
                 match selcx.select_from_obligation(&obligation) {
-                    Err(SelectionError::Ambiguous(impls)) if impls.len() > 1 => {
-                        self.annotate_source_of_ambiguity(&mut err, &impls, predicate);
+                    Ok(None) => {
+                        let impls = ambiguity::recompute_applicable_impls(self.infcx, &obligation);
+                        let has_non_region_infer =
+                            trait_ref.skip_binder().substs.types().any(|t| !t.is_ty_infer());
+                        // It doesn't make sense to talk about applicable impls if there are more
+                        // than a handful of them.
+                        if impls.len() > 1 && impls.len() < 5 && has_non_region_infer {
+                            self.annotate_source_of_ambiguity(&mut err, &impls, predicate);
+                        } else {
+                            if self.is_tainted_by_errors() {
+                                err.delay_as_bug();
+                                return;
+                            }
+                            err.note(&format!("cannot satisfy `{}`", predicate));
+                        }
                     }
                     _ => {
                         if self.is_tainted_by_errors() {
-                            err.cancel();
+                            err.delay_as_bug();
                             return;
                         }
                         err.note(&format!("cannot satisfy `{}`", predicate));
@@ -2450,7 +2447,6 @@ fn annotate_source_of_ambiguity(
                 }
             }
         }
-        let msg = format!("multiple `impl`s satisfying `{}` found", predicate);
         let mut crate_names: Vec<_> = crates.iter().map(|n| format!("`{}`", n)).collect();
         crate_names.sort();
         crate_names.dedup();
@@ -2471,13 +2467,9 @@ fn annotate_source_of_ambiguity(
             err.downgrade_to_delayed_bug();
             return;
         }
-        let post = if post.len() > 4 {
-            format!(
-                ":\n{}\nand {} more",
-                post.iter().map(|p| format!("- {}", p)).take(4).collect::<Vec<_>>().join("\n"),
-                post.len() - 4,
-            )
-        } else if post.len() > 1 || (post.len() == 1 && post[0].contains('\n')) {
+
+        let msg = format!("multiple `impl`s satisfying `{}` found", predicate);
+        let post = if post.len() > 1 || (post.len() == 1 && post[0].contains('\n')) {
             format!(":\n{}", post.iter().map(|p| format!("- {}", p)).collect::<Vec<_>>().join("\n"),)
         } else if post.len() == 1 {
             format!(": `{}`", post[0])
index 5eef54c6330db122111ce99744231c0057f3c883..82f0440b3078bb17efbb8d7406f528986eab5b9f 100644 (file)
@@ -1,14 +1,22 @@
-use super::{
-    ObligationCauseCode, OnUnimplementedDirective, OnUnimplementedNote, PredicateObligation,
-};
+use super::{ObligationCauseCode, PredicateObligation};
 use crate::infer::error_reporting::TypeErrCtxt;
+use rustc_ast::{MetaItem, NestedMetaItem};
+use rustc_attr as attr;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_errors::{struct_span_err, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::SubstsRef;
-use rustc_middle::ty::{self, GenericParamDefKind};
-use rustc_span::symbol::sym;
+use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt};
+use rustc_parse_format::{ParseMode, Parser, Piece, Position};
+use rustc_span::symbol::{kw, sym, Symbol};
+use rustc_span::{Span, DUMMY_SP};
 use std::iter;
 
+use crate::errors::{
+    EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented,
+};
+
 use super::InferCtxtPrivExt;
 
 pub trait TypeErrCtxtExt<'tcx> {
@@ -276,3 +284,383 @@ fn on_unimplemented_note(
         }
     }
 }
+
+#[derive(Clone, Debug)]
+pub struct OnUnimplementedFormatString(Symbol);
+
+#[derive(Debug)]
+pub struct OnUnimplementedDirective {
+    pub condition: Option<MetaItem>,
+    pub subcommands: Vec<OnUnimplementedDirective>,
+    pub message: Option<OnUnimplementedFormatString>,
+    pub label: Option<OnUnimplementedFormatString>,
+    pub note: Option<OnUnimplementedFormatString>,
+    pub parent_label: Option<OnUnimplementedFormatString>,
+    pub append_const_msg: Option<Option<Symbol>>,
+}
+
+/// For the `#[rustc_on_unimplemented]` attribute
+#[derive(Default)]
+pub struct OnUnimplementedNote {
+    pub message: Option<String>,
+    pub label: Option<String>,
+    pub note: Option<String>,
+    pub parent_label: Option<String>,
+    /// Append a message for `~const Trait` errors. `None` means not requested and
+    /// should fallback to a generic message, `Some(None)` suggests using the default
+    /// appended message, `Some(Some(s))` suggests use the `s` message instead of the
+    /// default one..
+    pub append_const_msg: Option<Option<Symbol>>,
+}
+
+impl<'tcx> OnUnimplementedDirective {
+    fn parse(
+        tcx: TyCtxt<'tcx>,
+        item_def_id: DefId,
+        items: &[NestedMetaItem],
+        span: Span,
+        is_root: bool,
+    ) -> Result<Self, ErrorGuaranteed> {
+        let mut errored = None;
+        let mut item_iter = items.iter();
+
+        let parse_value = |value_str| {
+            OnUnimplementedFormatString::try_parse(tcx, item_def_id, value_str, span).map(Some)
+        };
+
+        let condition = if is_root {
+            None
+        } else {
+            let cond = item_iter
+                .next()
+                .ok_or_else(|| tcx.sess.emit_err(EmptyOnClauseInOnUnimplemented { span }))?
+                .meta_item()
+                .ok_or_else(|| tcx.sess.emit_err(InvalidOnClauseInOnUnimplemented { span }))?;
+            attr::eval_condition(cond, &tcx.sess.parse_sess, Some(tcx.features()), &mut |cfg| {
+                if let Some(value) = cfg.value && let Err(guar) = parse_value(value) {
+                    errored = Some(guar);
+                }
+                true
+            });
+            Some(cond.clone())
+        };
+
+        let mut message = None;
+        let mut label = None;
+        let mut note = None;
+        let mut parent_label = None;
+        let mut subcommands = vec![];
+        let mut append_const_msg = None;
+
+        for item in item_iter {
+            if item.has_name(sym::message) && message.is_none() {
+                if let Some(message_) = item.value_str() {
+                    message = parse_value(message_)?;
+                    continue;
+                }
+            } else if item.has_name(sym::label) && label.is_none() {
+                if let Some(label_) = item.value_str() {
+                    label = parse_value(label_)?;
+                    continue;
+                }
+            } else if item.has_name(sym::note) && note.is_none() {
+                if let Some(note_) = item.value_str() {
+                    note = parse_value(note_)?;
+                    continue;
+                }
+            } else if item.has_name(sym::parent_label) && parent_label.is_none() {
+                if let Some(parent_label_) = item.value_str() {
+                    parent_label = parse_value(parent_label_)?;
+                    continue;
+                }
+            } else if item.has_name(sym::on)
+                && is_root
+                && message.is_none()
+                && label.is_none()
+                && note.is_none()
+            {
+                if let Some(items) = item.meta_item_list() {
+                    match Self::parse(tcx, item_def_id, &items, item.span(), false) {
+                        Ok(subcommand) => subcommands.push(subcommand),
+                        Err(reported) => errored = Some(reported),
+                    };
+                    continue;
+                }
+            } else if item.has_name(sym::append_const_msg) && append_const_msg.is_none() {
+                if let Some(msg) = item.value_str() {
+                    append_const_msg = Some(Some(msg));
+                    continue;
+                } else if item.is_word() {
+                    append_const_msg = Some(None);
+                    continue;
+                }
+            }
+
+            // nothing found
+            tcx.sess.emit_err(NoValueInOnUnimplemented { span: item.span() });
+        }
+
+        if let Some(reported) = errored {
+            Err(reported)
+        } else {
+            Ok(OnUnimplementedDirective {
+                condition,
+                subcommands,
+                message,
+                label,
+                note,
+                parent_label,
+                append_const_msg,
+            })
+        }
+    }
+
+    pub fn of_item(tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result<Option<Self>, ErrorGuaranteed> {
+        let Some(attr) = tcx.get_attr(item_def_id, sym::rustc_on_unimplemented) else {
+            return Ok(None);
+        };
+
+        let result = if let Some(items) = attr.meta_item_list() {
+            Self::parse(tcx, item_def_id, &items, attr.span, true).map(Some)
+        } else if let Some(value) = attr.value_str() {
+            Ok(Some(OnUnimplementedDirective {
+                condition: None,
+                message: None,
+                subcommands: vec![],
+                label: Some(OnUnimplementedFormatString::try_parse(
+                    tcx,
+                    item_def_id,
+                    value,
+                    attr.span,
+                )?),
+                note: None,
+                parent_label: None,
+                append_const_msg: None,
+            }))
+        } else {
+            let reported =
+                tcx.sess.delay_span_bug(DUMMY_SP, "of_item: neither meta_item_list nor value_str");
+            return Err(reported);
+        };
+        debug!("of_item({:?}) = {:?}", item_def_id, result);
+        result
+    }
+
+    pub fn evaluate(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        trait_ref: ty::TraitRef<'tcx>,
+        options: &[(Symbol, Option<String>)],
+    ) -> OnUnimplementedNote {
+        let mut message = None;
+        let mut label = None;
+        let mut note = None;
+        let mut parent_label = None;
+        let mut append_const_msg = None;
+        info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options);
+
+        let options_map: FxHashMap<Symbol, String> =
+            options.iter().filter_map(|(k, v)| v.as_ref().map(|v| (*k, v.to_owned()))).collect();
+
+        for command in self.subcommands.iter().chain(Some(self)).rev() {
+            if let Some(ref condition) = command.condition && !attr::eval_condition(
+                condition,
+                &tcx.sess.parse_sess,
+                Some(tcx.features()),
+                &mut |cfg| {
+                    let value = cfg.value.map(|v| {
+                        OnUnimplementedFormatString(v).format(tcx, trait_ref, &options_map)
+                    });
+
+                    options.contains(&(cfg.name, value))
+                },
+            ) {
+                debug!("evaluate: skipping {:?} due to condition", command);
+                continue;
+            }
+            debug!("evaluate: {:?} succeeded", command);
+            if let Some(ref message_) = command.message {
+                message = Some(message_.clone());
+            }
+
+            if let Some(ref label_) = command.label {
+                label = Some(label_.clone());
+            }
+
+            if let Some(ref note_) = command.note {
+                note = Some(note_.clone());
+            }
+
+            if let Some(ref parent_label_) = command.parent_label {
+                parent_label = Some(parent_label_.clone());
+            }
+
+            append_const_msg = command.append_const_msg;
+        }
+
+        OnUnimplementedNote {
+            label: label.map(|l| l.format(tcx, trait_ref, &options_map)),
+            message: message.map(|m| m.format(tcx, trait_ref, &options_map)),
+            note: note.map(|n| n.format(tcx, trait_ref, &options_map)),
+            parent_label: parent_label.map(|e_s| e_s.format(tcx, trait_ref, &options_map)),
+            append_const_msg,
+        }
+    }
+}
+
+impl<'tcx> OnUnimplementedFormatString {
+    fn try_parse(
+        tcx: TyCtxt<'tcx>,
+        item_def_id: DefId,
+        from: Symbol,
+        err_sp: Span,
+    ) -> Result<Self, ErrorGuaranteed> {
+        let result = OnUnimplementedFormatString(from);
+        result.verify(tcx, item_def_id, err_sp)?;
+        Ok(result)
+    }
+
+    fn verify(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        item_def_id: DefId,
+        span: Span,
+    ) -> Result<(), ErrorGuaranteed> {
+        let trait_def_id = if tcx.is_trait(item_def_id) {
+            item_def_id
+        } else {
+            tcx.trait_id_of_impl(item_def_id)
+                .expect("expected `on_unimplemented` to correspond to a trait")
+        };
+        let trait_name = tcx.item_name(trait_def_id);
+        let generics = tcx.generics_of(item_def_id);
+        let s = self.0.as_str();
+        let parser = Parser::new(s, None, None, false, ParseMode::Format);
+        let mut result = Ok(());
+        for token in parser {
+            match token {
+                Piece::String(_) => (), // Normal string, no need to check it
+                Piece::NextArgument(a) => match a.position {
+                    Position::ArgumentNamed(s) => {
+                        match Symbol::intern(s) {
+                            // `{Self}` is allowed
+                            kw::SelfUpper => (),
+                            // `{ThisTraitsName}` is allowed
+                            s if s == trait_name => (),
+                            // `{from_method}` is allowed
+                            sym::from_method => (),
+                            // `{from_desugaring}` is allowed
+                            sym::from_desugaring => (),
+                            // `{ItemContext}` is allowed
+                            sym::ItemContext => (),
+                            // `{integral}` and `{integer}` and `{float}` are allowed
+                            sym::integral | sym::integer_ | sym::float => (),
+                            // So is `{A}` if A is a type parameter
+                            s => match generics.params.iter().find(|param| param.name == s) {
+                                Some(_) => (),
+                                None => {
+                                    let reported = struct_span_err!(
+                                        tcx.sess,
+                                        span,
+                                        E0230,
+                                        "there is no parameter `{}` on {}",
+                                        s,
+                                        if trait_def_id == item_def_id {
+                                            format!("trait `{}`", trait_name)
+                                        } else {
+                                            "impl".to_string()
+                                        }
+                                    )
+                                    .emit();
+                                    result = Err(reported);
+                                }
+                            },
+                        }
+                    }
+                    // `{:1}` and `{}` are not to be used
+                    Position::ArgumentIs(..) | Position::ArgumentImplicitlyIs(_) => {
+                        let reported = struct_span_err!(
+                            tcx.sess,
+                            span,
+                            E0231,
+                            "only named substitution parameters are allowed"
+                        )
+                        .emit();
+                        result = Err(reported);
+                    }
+                },
+            }
+        }
+
+        result
+    }
+
+    pub fn format(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        trait_ref: ty::TraitRef<'tcx>,
+        options: &FxHashMap<Symbol, String>,
+    ) -> String {
+        let name = tcx.item_name(trait_ref.def_id);
+        let trait_str = tcx.def_path_str(trait_ref.def_id);
+        let generics = tcx.generics_of(trait_ref.def_id);
+        let generic_map = generics
+            .params
+            .iter()
+            .filter_map(|param| {
+                let value = match param.kind {
+                    GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
+                        trait_ref.substs[param.index as usize].to_string()
+                    }
+                    GenericParamDefKind::Lifetime => return None,
+                };
+                let name = param.name;
+                Some((name, value))
+            })
+            .collect::<FxHashMap<Symbol, String>>();
+        let empty_string = String::new();
+
+        let s = self.0.as_str();
+        let parser = Parser::new(s, None, None, false, ParseMode::Format);
+        let item_context = (options.get(&sym::ItemContext)).unwrap_or(&empty_string);
+        parser
+            .map(|p| match p {
+                Piece::String(s) => s,
+                Piece::NextArgument(a) => match a.position {
+                    Position::ArgumentNamed(s) => {
+                        let s = Symbol::intern(s);
+                        match generic_map.get(&s) {
+                            Some(val) => val,
+                            None if s == name => &trait_str,
+                            None => {
+                                if let Some(val) = options.get(&s) {
+                                    val
+                                } else if s == sym::from_desugaring || s == sym::from_method {
+                                    // don't break messages using these two arguments incorrectly
+                                    &empty_string
+                                } else if s == sym::ItemContext {
+                                    &item_context
+                                } else if s == sym::integral {
+                                    "{integral}"
+                                } else if s == sym::integer_ {
+                                    "{integer}"
+                                } else if s == sym::float {
+                                    "{float}"
+                                } else {
+                                    bug!(
+                                        "broken on_unimplemented {:?} for {:?}: \
+                                      no argument matching {:?}",
+                                        self.0,
+                                        trait_ref,
+                                        s
+                                    )
+                                }
+                            }
+                        }
+                    }
+                    _ => bug!("broken on_unimplemented {:?} - bad format arg", self.0),
+                },
+            })
+            .collect()
+    }
+}
index 0f4aa87b43f5e7d0e499f22b0519517eb3ab8115..22e7d3ea5dd5ba1ab468e6bf1faa2b2b1187f88f 100644 (file)
@@ -714,7 +714,6 @@ fn suggest_dereferences(
                     obligation.cause.body_id,
                     span,
                     base_ty,
-                    span,
                 );
                 if let Some(steps) = autoderef.find_map(|(ty, steps)| {
                     // Re-add the `&`
@@ -1117,7 +1116,7 @@ fn suggest_add_reference_to_arg(
                         err.span_suggestions(
                             span.shrink_to_lo(),
                             "consider borrowing here",
-                            ["&".to_string(), "&mut ".to_string()].into_iter(),
+                            ["&".to_string(), "&mut ".to_string()],
                             Applicability::MaybeIncorrect,
                         );
                     } else {
@@ -2446,12 +2445,12 @@ fn note_obligation_cause_code<T>(
                             (Ok(l), Ok(r)) => l.line == r.line,
                             _ => true,
                         };
-                    if !ident.span.overlaps(span) && !same_line {
+                    if !ident.span.is_dummy() && !ident.span.overlaps(span) && !same_line {
                         multispan.push_span_label(ident.span, "required by a bound in this");
                     }
                 }
                 let descr = format!("required by a bound in `{}`", item_name);
-                if span != DUMMY_SP {
+                if !span.is_dummy() {
                     let msg = format!("required by this bound in `{}`", item_name);
                     multispan.push_span_label(span, msg);
                     err.span_note(multispan, &descr);
index a417e1440b9ee1f35c2281a40e25f52ccd4ca228..b486c07f354b93bbf26f57cf3e1f8ace88d89286 100644 (file)
@@ -85,7 +85,7 @@ pub struct PendingPredicateObligation<'tcx> {
 
 impl<'a, 'tcx> FulfillmentContext<'tcx> {
     /// Creates a new fulfillment context.
-    pub fn new() -> FulfillmentContext<'tcx> {
+    pub(super) fn new() -> FulfillmentContext<'tcx> {
         FulfillmentContext {
             predicates: ObligationForest::new(),
             relationships: FxHashMap::default(),
@@ -93,7 +93,7 @@ pub fn new() -> FulfillmentContext<'tcx> {
         }
     }
 
-    pub fn new_in_snapshot() -> FulfillmentContext<'tcx> {
+    pub(super) fn new_in_snapshot() -> FulfillmentContext<'tcx> {
         FulfillmentContext {
             predicates: ObligationForest::new(),
             relationships: FxHashMap::default(),
index be603c609cb364438f148b0a9e11342abb1e3ef6..b6ded4ce5a3962e0d252dd81b0b226c72017174e 100644 (file)
@@ -70,7 +70,7 @@ pub fn can_type_implement_copy<'tcx>(
                     }
                 }
                 Err(errors) => {
-                    infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+                    infcx.err_ctxt().report_fulfillment_errors(&errors, None);
                 }
             };
         }
index a33534f5747fa11b941e71677016967ea9223868..10e48610e3abb46287812cd87e0a0a7ddd722fd8 100644 (file)
@@ -12,7 +12,6 @@
 mod fulfill;
 pub mod misc;
 mod object_safety;
-mod on_unimplemented;
 pub mod outlives_bounds;
 mod project;
 pub mod query;
@@ -58,7 +57,6 @@
 pub use self::object_safety::is_vtable_safe_method;
 pub use self::object_safety::MethodViolationCode;
 pub use self::object_safety::ObjectSafetyViolation;
-pub use self::on_unimplemented::{OnUnimplementedDirective, OnUnimplementedNote};
 pub use self::project::{normalize, normalize_projection_type, normalize_to};
 pub use self::select::{EvaluationCache, SelectionCache, SelectionContext};
 pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError};
@@ -214,7 +212,7 @@ fn do_normalize_predicates<'tcx>(
     let predicates = match fully_normalize(&infcx, cause, elaborated_env, predicates) {
         Ok(predicates) => predicates,
         Err(errors) => {
-            let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+            let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
             return Err(reported);
         }
     };
diff --git a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs
deleted file mode 100644 (file)
index fb062ea..0000000
+++ /dev/null
@@ -1,393 +0,0 @@
-use rustc_ast::{MetaItem, NestedMetaItem};
-use rustc_attr as attr;
-use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::{struct_span_err, ErrorGuaranteed};
-use rustc_hir::def_id::DefId;
-use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt};
-use rustc_parse_format::{ParseMode, Parser, Piece, Position};
-use rustc_span::symbol::{kw, sym, Symbol};
-use rustc_span::{Span, DUMMY_SP};
-
-use crate::errors::{
-    EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented,
-};
-
-#[derive(Clone, Debug)]
-pub struct OnUnimplementedFormatString(Symbol);
-
-#[derive(Debug)]
-pub struct OnUnimplementedDirective {
-    pub condition: Option<MetaItem>,
-    pub subcommands: Vec<OnUnimplementedDirective>,
-    pub message: Option<OnUnimplementedFormatString>,
-    pub label: Option<OnUnimplementedFormatString>,
-    pub note: Option<OnUnimplementedFormatString>,
-    pub parent_label: Option<OnUnimplementedFormatString>,
-    pub append_const_msg: Option<Option<Symbol>>,
-}
-
-#[derive(Default)]
-/// For the `#[rustc_on_unimplemented]` attribute
-pub struct OnUnimplementedNote {
-    pub message: Option<String>,
-    pub label: Option<String>,
-    pub note: Option<String>,
-    pub parent_label: Option<String>,
-    /// Append a message for `~const Trait` errors. `None` means not requested and
-    /// should fallback to a generic message, `Some(None)` suggests using the default
-    /// appended message, `Some(Some(s))` suggests use the `s` message instead of the
-    /// default one..
-    pub append_const_msg: Option<Option<Symbol>>,
-}
-
-impl<'tcx> OnUnimplementedDirective {
-    fn parse(
-        tcx: TyCtxt<'tcx>,
-        item_def_id: DefId,
-        items: &[NestedMetaItem],
-        span: Span,
-        is_root: bool,
-    ) -> Result<Self, ErrorGuaranteed> {
-        let mut errored = None;
-        let mut item_iter = items.iter();
-
-        let parse_value = |value_str| {
-            OnUnimplementedFormatString::try_parse(tcx, item_def_id, value_str, span).map(Some)
-        };
-
-        let condition = if is_root {
-            None
-        } else {
-            let cond = item_iter
-                .next()
-                .ok_or_else(|| tcx.sess.emit_err(EmptyOnClauseInOnUnimplemented { span }))?
-                .meta_item()
-                .ok_or_else(|| tcx.sess.emit_err(InvalidOnClauseInOnUnimplemented { span }))?;
-            attr::eval_condition(cond, &tcx.sess.parse_sess, Some(tcx.features()), &mut |cfg| {
-                if let Some(value) = cfg.value && let Err(guar) = parse_value(value) {
-                    errored = Some(guar);
-                }
-                true
-            });
-            Some(cond.clone())
-        };
-
-        let mut message = None;
-        let mut label = None;
-        let mut note = None;
-        let mut parent_label = None;
-        let mut subcommands = vec![];
-        let mut append_const_msg = None;
-
-        for item in item_iter {
-            if item.has_name(sym::message) && message.is_none() {
-                if let Some(message_) = item.value_str() {
-                    message = parse_value(message_)?;
-                    continue;
-                }
-            } else if item.has_name(sym::label) && label.is_none() {
-                if let Some(label_) = item.value_str() {
-                    label = parse_value(label_)?;
-                    continue;
-                }
-            } else if item.has_name(sym::note) && note.is_none() {
-                if let Some(note_) = item.value_str() {
-                    note = parse_value(note_)?;
-                    continue;
-                }
-            } else if item.has_name(sym::parent_label) && parent_label.is_none() {
-                if let Some(parent_label_) = item.value_str() {
-                    parent_label = parse_value(parent_label_)?;
-                    continue;
-                }
-            } else if item.has_name(sym::on)
-                && is_root
-                && message.is_none()
-                && label.is_none()
-                && note.is_none()
-            {
-                if let Some(items) = item.meta_item_list() {
-                    match Self::parse(tcx, item_def_id, &items, item.span(), false) {
-                        Ok(subcommand) => subcommands.push(subcommand),
-                        Err(reported) => errored = Some(reported),
-                    };
-                    continue;
-                }
-            } else if item.has_name(sym::append_const_msg) && append_const_msg.is_none() {
-                if let Some(msg) = item.value_str() {
-                    append_const_msg = Some(Some(msg));
-                    continue;
-                } else if item.is_word() {
-                    append_const_msg = Some(None);
-                    continue;
-                }
-            }
-
-            // nothing found
-            tcx.sess.emit_err(NoValueInOnUnimplemented { span: item.span() });
-        }
-
-        if let Some(reported) = errored {
-            Err(reported)
-        } else {
-            Ok(OnUnimplementedDirective {
-                condition,
-                subcommands,
-                message,
-                label,
-                note,
-                parent_label,
-                append_const_msg,
-            })
-        }
-    }
-
-    pub fn of_item(tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result<Option<Self>, ErrorGuaranteed> {
-        let Some(attr) = tcx.get_attr(item_def_id, sym::rustc_on_unimplemented) else {
-            return Ok(None);
-        };
-
-        let result = if let Some(items) = attr.meta_item_list() {
-            Self::parse(tcx, item_def_id, &items, attr.span, true).map(Some)
-        } else if let Some(value) = attr.value_str() {
-            Ok(Some(OnUnimplementedDirective {
-                condition: None,
-                message: None,
-                subcommands: vec![],
-                label: Some(OnUnimplementedFormatString::try_parse(
-                    tcx,
-                    item_def_id,
-                    value,
-                    attr.span,
-                )?),
-                note: None,
-                parent_label: None,
-                append_const_msg: None,
-            }))
-        } else {
-            let reported =
-                tcx.sess.delay_span_bug(DUMMY_SP, "of_item: neither meta_item_list nor value_str");
-            return Err(reported);
-        };
-        debug!("of_item({:?}) = {:?}", item_def_id, result);
-        result
-    }
-
-    pub fn evaluate(
-        &self,
-        tcx: TyCtxt<'tcx>,
-        trait_ref: ty::TraitRef<'tcx>,
-        options: &[(Symbol, Option<String>)],
-    ) -> OnUnimplementedNote {
-        let mut message = None;
-        let mut label = None;
-        let mut note = None;
-        let mut parent_label = None;
-        let mut append_const_msg = None;
-        info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options);
-
-        let options_map: FxHashMap<Symbol, String> =
-            options.iter().filter_map(|(k, v)| v.as_ref().map(|v| (*k, v.to_owned()))).collect();
-
-        for command in self.subcommands.iter().chain(Some(self)).rev() {
-            if let Some(ref condition) = command.condition && !attr::eval_condition(
-                condition,
-                &tcx.sess.parse_sess,
-                Some(tcx.features()),
-                &mut |cfg| {
-                    let value = cfg.value.map(|v| {
-                        OnUnimplementedFormatString(v).format(tcx, trait_ref, &options_map)
-                    });
-
-                    options.contains(&(cfg.name, value))
-                },
-            ) {
-                debug!("evaluate: skipping {:?} due to condition", command);
-                continue;
-            }
-            debug!("evaluate: {:?} succeeded", command);
-            if let Some(ref message_) = command.message {
-                message = Some(message_.clone());
-            }
-
-            if let Some(ref label_) = command.label {
-                label = Some(label_.clone());
-            }
-
-            if let Some(ref note_) = command.note {
-                note = Some(note_.clone());
-            }
-
-            if let Some(ref parent_label_) = command.parent_label {
-                parent_label = Some(parent_label_.clone());
-            }
-
-            append_const_msg = command.append_const_msg;
-        }
-
-        OnUnimplementedNote {
-            label: label.map(|l| l.format(tcx, trait_ref, &options_map)),
-            message: message.map(|m| m.format(tcx, trait_ref, &options_map)),
-            note: note.map(|n| n.format(tcx, trait_ref, &options_map)),
-            parent_label: parent_label.map(|e_s| e_s.format(tcx, trait_ref, &options_map)),
-            append_const_msg,
-        }
-    }
-}
-
-impl<'tcx> OnUnimplementedFormatString {
-    fn try_parse(
-        tcx: TyCtxt<'tcx>,
-        item_def_id: DefId,
-        from: Symbol,
-        err_sp: Span,
-    ) -> Result<Self, ErrorGuaranteed> {
-        let result = OnUnimplementedFormatString(from);
-        result.verify(tcx, item_def_id, err_sp)?;
-        Ok(result)
-    }
-
-    fn verify(
-        &self,
-        tcx: TyCtxt<'tcx>,
-        item_def_id: DefId,
-        span: Span,
-    ) -> Result<(), ErrorGuaranteed> {
-        let trait_def_id = if tcx.is_trait(item_def_id) {
-            item_def_id
-        } else {
-            tcx.trait_id_of_impl(item_def_id)
-                .expect("expected `on_unimplemented` to correspond to a trait")
-        };
-        let trait_name = tcx.item_name(trait_def_id);
-        let generics = tcx.generics_of(item_def_id);
-        let s = self.0.as_str();
-        let parser = Parser::new(s, None, None, false, ParseMode::Format);
-        let mut result = Ok(());
-        for token in parser {
-            match token {
-                Piece::String(_) => (), // Normal string, no need to check it
-                Piece::NextArgument(a) => match a.position {
-                    Position::ArgumentNamed(s) => {
-                        match Symbol::intern(s) {
-                            // `{Self}` is allowed
-                            kw::SelfUpper => (),
-                            // `{ThisTraitsName}` is allowed
-                            s if s == trait_name => (),
-                            // `{from_method}` is allowed
-                            sym::from_method => (),
-                            // `{from_desugaring}` is allowed
-                            sym::from_desugaring => (),
-                            // `{ItemContext}` is allowed
-                            sym::ItemContext => (),
-                            // `{integral}` and `{integer}` and `{float}` are allowed
-                            sym::integral | sym::integer_ | sym::float => (),
-                            // So is `{A}` if A is a type parameter
-                            s => match generics.params.iter().find(|param| param.name == s) {
-                                Some(_) => (),
-                                None => {
-                                    let reported = struct_span_err!(
-                                        tcx.sess,
-                                        span,
-                                        E0230,
-                                        "there is no parameter `{}` on {}",
-                                        s,
-                                        if trait_def_id == item_def_id {
-                                            format!("trait `{}`", trait_name)
-                                        } else {
-                                            "impl".to_string()
-                                        }
-                                    )
-                                    .emit();
-                                    result = Err(reported);
-                                }
-                            },
-                        }
-                    }
-                    // `{:1}` and `{}` are not to be used
-                    Position::ArgumentIs(..) | Position::ArgumentImplicitlyIs(_) => {
-                        let reported = struct_span_err!(
-                            tcx.sess,
-                            span,
-                            E0231,
-                            "only named substitution parameters are allowed"
-                        )
-                        .emit();
-                        result = Err(reported);
-                    }
-                },
-            }
-        }
-
-        result
-    }
-
-    pub fn format(
-        &self,
-        tcx: TyCtxt<'tcx>,
-        trait_ref: ty::TraitRef<'tcx>,
-        options: &FxHashMap<Symbol, String>,
-    ) -> String {
-        let name = tcx.item_name(trait_ref.def_id);
-        let trait_str = tcx.def_path_str(trait_ref.def_id);
-        let generics = tcx.generics_of(trait_ref.def_id);
-        let generic_map = generics
-            .params
-            .iter()
-            .filter_map(|param| {
-                let value = match param.kind {
-                    GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
-                        trait_ref.substs[param.index as usize].to_string()
-                    }
-                    GenericParamDefKind::Lifetime => return None,
-                };
-                let name = param.name;
-                Some((name, value))
-            })
-            .collect::<FxHashMap<Symbol, String>>();
-        let empty_string = String::new();
-
-        let s = self.0.as_str();
-        let parser = Parser::new(s, None, None, false, ParseMode::Format);
-        let item_context = (options.get(&sym::ItemContext)).unwrap_or(&empty_string);
-        parser
-            .map(|p| match p {
-                Piece::String(s) => s,
-                Piece::NextArgument(a) => match a.position {
-                    Position::ArgumentNamed(s) => {
-                        let s = Symbol::intern(s);
-                        match generic_map.get(&s) {
-                            Some(val) => val,
-                            None if s == name => &trait_str,
-                            None => {
-                                if let Some(val) = options.get(&s) {
-                                    val
-                                } else if s == sym::from_desugaring || s == sym::from_method {
-                                    // don't break messages using these two arguments incorrectly
-                                    &empty_string
-                                } else if s == sym::ItemContext {
-                                    &item_context
-                                } else if s == sym::integral {
-                                    "{integral}"
-                                } else if s == sym::integer_ {
-                                    "{integer}"
-                                } else if s == sym::float {
-                                    "{float}"
-                                } else {
-                                    bug!(
-                                        "broken on_unimplemented {:?} for {:?}: \
-                                      no argument matching {:?}",
-                                        self.0,
-                                        trait_ref,
-                                        s
-                                    )
-                                }
-                            }
-                        }
-                    }
-                    _ => bug!("broken on_unimplemented {:?} - bad format arg", self.0),
-                },
-            })
-            .collect()
-    }
-}
index b1a161c353637610c4d3fd3caad65ed26bb0219e..e1092a788e32b5df96786eb40146d485a096a43f 100644 (file)
@@ -2,7 +2,7 @@
 use crate::traits::query::type_op::{self, TypeOp, TypeOpOutput};
 use crate::traits::query::NoSolution;
 use crate::traits::ObligationCause;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir as hir;
 use rustc_hir::HirId;
 use rustc_middle::ty::{self, ParamEnv, Ty};
@@ -22,7 +22,7 @@ fn implied_bounds_tys(
         &'a self,
         param_env: ty::ParamEnv<'tcx>,
         body_id: hir::HirId,
-        tys: FxHashSet<Ty<'tcx>>,
+        tys: FxIndexSet<Ty<'tcx>>,
     ) -> Bounds<'a, 'tcx>;
 }
 
@@ -103,7 +103,7 @@ fn implied_bounds_tys(
         &'a self,
         param_env: ParamEnv<'tcx>,
         body_id: HirId,
-        tys: FxHashSet<Ty<'tcx>>,
+        tys: FxIndexSet<Ty<'tcx>>,
     ) -> Bounds<'a, 'tcx> {
         tys.into_iter()
             .map(move |ty| {
index daee5dd8f02e6ed14a210c950bdf429a59d1b25c..572f82117cc0e701440b9b0308f6848b539ed214 100644 (file)
@@ -647,7 +647,7 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
     #[instrument(skip(self), level = "debug")]
     fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> {
         let tcx = self.selcx.tcx();
-        if tcx.lazy_normalization() {
+        if tcx.lazy_normalization() || !needs_normalization(&constant, self.param_env.reveal()) {
             constant
         } else {
             let constant = constant.super_fold_with(self);
@@ -2187,7 +2187,7 @@ fn confirm_impl_candidate<'cx, 'tcx>(
 // Verify that the trait item and its implementation have compatible substs lists
 fn check_substs_compatible<'tcx>(
     tcx: TyCtxt<'tcx>,
-    assoc_ty: &ty::AssocItem,
+    assoc_item: &ty::AssocItem,
     substs: ty::SubstsRef<'tcx>,
 ) -> bool {
     fn check_substs_compatible_inner<'tcx>(
@@ -2219,7 +2219,10 @@ fn check_substs_compatible_inner<'tcx>(
         true
     }
 
-    check_substs_compatible_inner(tcx, tcx.generics_of(assoc_ty.def_id), substs.as_slice())
+    let generics = tcx.generics_of(assoc_item.def_id);
+    // Chop off any additional substs (RPITIT) substs
+    let substs = &substs[0..generics.count().min(substs.len())];
+    check_substs_compatible_inner(tcx, generics, substs)
 }
 
 fn confirm_impl_trait_in_trait_candidate<'tcx>(
@@ -2248,11 +2251,27 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>(
         };
     }
 
-    let impl_fn_def_id = leaf_def.item.def_id;
     // Rebase from {trait}::{fn}::{opaque} to {impl}::{fn}::{opaque},
     // since `data.substs` are the impl substs.
     let impl_fn_substs =
         obligation.predicate.substs.rebase_onto(tcx, tcx.parent(trait_fn_def_id), data.substs);
+    let impl_fn_substs = translate_substs(
+        selcx.infcx(),
+        obligation.param_env,
+        data.impl_def_id,
+        impl_fn_substs,
+        leaf_def.defining_node,
+    );
+
+    if !check_substs_compatible(tcx, &leaf_def.item, impl_fn_substs) {
+        let err = tcx.ty_error_with_message(
+            obligation.cause.span,
+            "impl method and trait method have different parameters",
+        );
+        return Progress { term: err.into(), obligations };
+    }
+
+    let impl_fn_def_id = leaf_def.item.def_id;
 
     let cause = ObligationCause::new(
         obligation.cause.span,
index 715f5be8e2f4bbe22dd35ce61078f0aa370c0680..a7932b332c94b1ca0c360b36ed3a1b4174836975 100644 (file)
@@ -353,6 +353,10 @@ fn try_fold_const(
         &mut self,
         constant: ty::Const<'tcx>,
     ) -> Result<ty::Const<'tcx>, Self::Error> {
+        if !needs_normalization(&constant, self.param_env.reveal()) {
+            return Ok(constant);
+        }
+
         let constant = constant.try_super_fold_with(self)?;
         debug!(?constant, ?self.param_env);
         Ok(crate::traits::project::with_replaced_escaping_bound_vars(
index 4c5bc333961dc76345898a8a8284cf1a53cd7284..3671a0d87df57408b3f5db09a6c032019f5f53cd 100644 (file)
@@ -20,7 +20,7 @@
 use crate::traits::coherence::Conflict;
 use crate::traits::query::evaluate_obligation::InferCtxtExt;
 use crate::traits::{util, SelectionResult};
-use crate::traits::{Ambiguous, ErrorReporting, Overflow, Unimplemented};
+use crate::traits::{ErrorReporting, Overflow, Unimplemented};
 
 use super::BuiltinImplConditions;
 use super::IntercrateAmbiguityCause;
@@ -200,15 +200,7 @@ fn candidate_from_obligation_no_cache<'o>(
                     // and report ambiguity.
                     if i > 1 {
                         debug!("multiple matches, ambig");
-                        return Err(Ambiguous(
-                            candidates
-                                .into_iter()
-                                .filter_map(|c| match c.candidate {
-                                    SelectionCandidate::ImplCandidate(def_id) => Some(def_id),
-                                    _ => None,
-                                })
-                                .collect(),
-                        ));
+                        return Ok(None);
                     }
                 }
             }
index 84be1ced520febd20370d7188a7252ad12c377ba..a12f67125bbc0f2afba2fe9b15af46572743bacf 100644 (file)
@@ -2,6 +2,12 @@
 //!
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html#selection
 
+// FIXME: The `map` field in ProvisionalEvaluationCache should be changed to
+// a `FxIndexMap` to avoid query instability, but right now it causes a perf regression. This would be
+// fixed or at least lightened by the addition of the `drain_filter` method to `FxIndexMap`
+// Relevant: https://github.com/rust-lang/rust/pull/103723 and https://github.com/bluss/indexmap/issues/242
+#![allow(rustc::potential_query_instability)]
+
 use self::EvaluationResult::*;
 use self::SelectionCandidate::*;
 
@@ -24,7 +30,8 @@
 use crate::traits::project::ProjectAndUnifyResult;
 use crate::traits::project::ProjectionCacheKeyExt;
 use crate::traits::ProjectionCacheKey;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::{Diagnostic, ErrorGuaranteed};
 use rustc_hir as hir;
@@ -294,9 +301,6 @@ pub fn select(
                 assert!(self.query_mode == TraitQueryMode::Canonical);
                 return Err(SelectionError::Overflow(OverflowError::Canonical));
             }
-            Err(SelectionError::Ambiguous(_)) => {
-                return Ok(None);
-            }
             Err(e) => {
                 return Err(e);
             }
@@ -931,7 +935,6 @@ fn evaluate_stack<'o>(
 
         match self.candidate_from_obligation(stack) {
             Ok(Some(c)) => self.evaluate_candidate(stack, &c),
-            Err(SelectionError::Ambiguous(_)) => Ok(EvaluatedToAmbig),
             Ok(None) => Ok(EvaluatedToAmbig),
             Err(Overflow(OverflowError::Canonical)) => Err(OverflowError::Canonical),
             Err(ErrorReporting) => Err(OverflowError::ErrorReporting),
@@ -956,7 +959,7 @@ pub(crate) fn coinductive_match<I>(&mut self, mut cycle: I) -> bool
 
     fn coinductive_predicate(&self, predicate: ty::Predicate<'tcx>) -> bool {
         let result = match predicate.kind().skip_binder() {
-            ty::PredicateKind::Trait(ref data) => self.tcx().trait_is_auto(data.def_id()),
+            ty::PredicateKind::Trait(ref data) => self.tcx().trait_is_coinductive(data.def_id()),
             ty::PredicateKind::WellFormed(_) => true,
             _ => false,
         };
@@ -1975,6 +1978,7 @@ fn copy_clone_conditions(
     /// Bar<i32> where struct Bar<T> { x: T, y: u32 } -> [i32, u32]
     /// Zed<i32> where enum Zed { A(T), B(u32) } -> [i32, u32]
     /// ```
+    #[instrument(level = "debug", skip(self), ret)]
     fn constituent_types_for_ty(
         &self,
         t: ty::Binder<'tcx, Ty<'tcx>>,
index c891658582a0a89b34222703a47894385c45a5e3..231a18f86eae72eaea55261dc2344e087e7d12ba 100644 (file)
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/specialization.html
 
 pub mod specialization_graph;
+use rustc_infer::traits::{TraitEngine, TraitEngineExt as _};
 use specialization_graph::GraphExt;
 
 use crate::errors::NegativePositiveConflict;
 use crate::infer::{InferCtxt, InferOk, TyCtxtInferExt};
+use crate::traits::engine::TraitEngineExt as _;
 use crate::traits::select::IntercrateAmbiguityCause;
 use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause};
-use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
+use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::{struct_span_err, DiagnosticBuilder, EmissionGuarantee};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::ty::{self, ImplSubject, TyCtxt};
@@ -200,36 +202,32 @@ fn fulfill_implication<'tcx>(
         return Err(());
     };
 
+    // Needs to be `in_snapshot` because this function is used to rebase
+    // substitutions, which may happen inside of a select within a probe.
+    let mut engine = <dyn TraitEngine<'tcx>>::new_in_snapshot(infcx.tcx);
     // attempt to prove all of the predicates for impl2 given those for impl1
     // (which are packed up in penv)
+    engine.register_predicate_obligations(infcx, obligations.chain(more_obligations));
 
-    infcx.save_and_restore_in_snapshot_flag(|infcx| {
-        let errors = traits::fully_solve_obligations(&infcx, obligations.chain(more_obligations));
-        match &errors[..] {
-            [] => {
-                debug!(
-                    "fulfill_implication: an impl for {:?} specializes {:?}",
-                    source_trait, target_trait
-                );
+    let errors = engine.select_all_or_error(infcx);
+    if !errors.is_empty() {
+        // no dice!
+        debug!(
+            "fulfill_implication: for impls on {:?} and {:?}, \
+                 could not fulfill: {:?} given {:?}",
+            source_trait,
+            target_trait,
+            errors,
+            param_env.caller_bounds()
+        );
+        return Err(());
+    }
 
-                // Now resolve the *substitution* we built for the target earlier, replacing
-                // the inference variables inside with whatever we got from fulfillment.
-                Ok(infcx.resolve_vars_if_possible(target_substs))
-            }
-            errors => {
-                // no dice!
-                debug!(
-                    "fulfill_implication: for impls on {:?} and {:?}, \
-                     could not fulfill: {:?} given {:?}",
-                    source_trait,
-                    target_trait,
-                    errors,
-                    param_env.caller_bounds()
-                );
-                Err(())
-            }
-        }
-    })
+    debug!("fulfill_implication: an impl for {:?} specializes {:?}", source_trait, target_trait);
+
+    // Now resolve the *substitution* we built for the target earlier, replacing
+    // the inference variables inside with whatever we got from fulfillment.
+    Ok(infcx.resolve_vars_if_possible(target_substs))
 }
 
 // Query provider for `specialization_graph_of`.
@@ -435,7 +433,7 @@ pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Opti
 
     // FIXME: Currently only handles ?Sized.
     //        Needs to support ?Move and ?DynSized when they are implemented.
-    let mut types_without_default_bounds = FxHashSet::default();
+    let mut types_without_default_bounds = FxIndexSet::default();
     let sized_trait = tcx.lang_items().sized_trait();
 
     if !substs.is_empty() {
index 8908fe230b0ebeee9de7da80ef350a111ed2ee5e..fc0a9f69003363dfd447a006f9a19b183e9a97af 100644 (file)
@@ -547,7 +547,7 @@ fn compute(&mut self, arg: GenericArg<'tcx>) {
                 }
 
                 ty::FnDef(did, substs) => {
-                    let obligations = self.nominal_obligations(did, substs);
+                    let obligations = self.nominal_obligations_without_const(did, substs);
                     self.out.extend(obligations);
                 }
 
index 2035252fe39a63bb66611c6e84cfebab0e954541..07f92299f72b43326f5195dd87fbe87e9ae704de 100644 (file)
@@ -728,7 +728,7 @@ fn bound_vars_for_item<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> SubstsRef<'tcx
         ty::GenericParamDefKind::Lifetime => {
             let br = ty::BoundRegion {
                 var: ty::BoundVar::from_usize(substs.len()),
-                kind: ty::BrAnon(substs.len() as u32),
+                kind: ty::BrAnon(substs.len() as u32, None),
             };
             tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into()
         }
index 0492e94b94e9830d602f2cdee3a8940abf488cb7..b64d53e60dee6d8211103c879d713f58f4b33ba1 100644 (file)
@@ -498,13 +498,13 @@ fn lower_into(self, interner: RustInterner<'tcx>) -> Region<'tcx> {
                 ty::DebruijnIndex::from_u32(var.debruijn.depth()),
                 ty::BoundRegion {
                     var: ty::BoundVar::from_usize(var.index),
-                    kind: ty::BrAnon(var.index as u32),
+                    kind: ty::BrAnon(var.index as u32, None),
                 },
             ),
             chalk_ir::LifetimeData::InferenceVar(_var) => unimplemented!(),
             chalk_ir::LifetimeData::Placeholder(p) => ty::RePlaceholder(ty::Placeholder {
                 universe: ty::UniverseIndex::from_usize(p.ui.counter),
-                name: ty::BoundRegionKind::BrAnon(p.idx as u32),
+                name: ty::BoundRegionKind::BrAnon(p.idx as u32, None),
             }),
             chalk_ir::LifetimeData::Static => return interner.tcx.lifetimes.re_static,
             chalk_ir::LifetimeData::Empty(_) => {
@@ -933,7 +933,7 @@ fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<Self::BreakTy> {
                     }
                 }
 
-                ty::BoundRegionKind::BrAnon(var) => match self.parameters.entry(var) {
+                ty::BoundRegionKind::BrAnon(var, _) => match self.parameters.entry(var) {
                     Entry::Vacant(entry) => {
                         entry.insert(chalk_ir::VariableKind::Lifetime);
                     }
@@ -991,13 +991,13 @@ fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> {
             ty::ReLateBound(index, br) if index == self.binder_index => match br.kind {
                 ty::BrNamed(def_id, _name) => match self.named_parameters.get(&def_id) {
                     Some(idx) => {
-                        let new_br = ty::BoundRegion { var: br.var, kind: ty::BrAnon(*idx) };
+                        let new_br = ty::BoundRegion { var: br.var, kind: ty::BrAnon(*idx, None) };
                         return self.tcx.mk_region(ty::ReLateBound(index, new_br));
                     }
                     None => panic!("Missing `BrNamed`."),
                 },
                 ty::BrEnv => unimplemented!(),
-                ty::BrAnon(_) => {}
+                ty::BrAnon(..) => {}
             },
             _ => (),
         };
@@ -1072,14 +1072,16 @@ fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> {
                 Some(idx) => {
                     let br = ty::BoundRegion {
                         var: ty::BoundVar::from_u32(*idx),
-                        kind: ty::BrAnon(*idx),
+                        kind: ty::BrAnon(*idx, None),
                     };
                     self.tcx.mk_region(ty::ReLateBound(self.binder_index, br))
                 }
                 None => {
                     let idx = self.named_regions.len() as u32;
-                    let br =
-                        ty::BoundRegion { var: ty::BoundVar::from_u32(idx), kind: ty::BrAnon(idx) };
+                    let br = ty::BoundRegion {
+                        var: ty::BoundVar::from_u32(idx),
+                        kind: ty::BrAnon(idx, None),
+                    };
                     self.named_regions.insert(_re.def_id, idx);
                     self.tcx.mk_region(ty::ReLateBound(self.binder_index, br))
                 }
@@ -1156,7 +1158,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
     fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<Self::BreakTy> {
         match *r {
             ty::RePlaceholder(p) if p.universe == self.universe_index => {
-                if let ty::BoundRegionKind::BrAnon(anon) = p.name {
+                if let ty::BoundRegionKind::BrAnon(anon, _) = p.name {
                     self.next_anon_region_placeholder = self.next_anon_region_placeholder.max(anon);
                 }
             }
index d5a8ca5ea784a2508c2c569785e1aeed6344a591..7b4ad9fea137a7bd30bf835c5a86f528b058f764 100644 (file)
@@ -2,20 +2,18 @@
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::canonical::{Canonical, QueryResponse};
 use rustc_infer::infer::TyCtxtInferExt;
-use rustc_infer::traits::TraitEngineExt as _;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::InternalSubsts;
 use rustc_middle::ty::{self, EarlyBinder, ParamEnvAnd, Ty, TyCtxt};
 use rustc_span::source_map::{Span, DUMMY_SP};
+use rustc_trait_selection::infer::InferCtxtBuilderExt;
 use rustc_trait_selection::traits::query::dropck_outlives::trivial_dropck_outlives;
 use rustc_trait_selection::traits::query::dropck_outlives::{
     DropckConstraint, DropckOutlivesResult,
 };
 use rustc_trait_selection::traits::query::normalize::AtExt;
 use rustc_trait_selection::traits::query::{CanonicalTyGoal, NoSolution};
-use rustc_trait_selection::traits::{
-    Normalized, ObligationCause, TraitEngine, TraitEngineExt as _,
-};
+use rustc_trait_selection::traits::{Normalized, ObligationCause};
 
 pub(crate) fn provide(p: &mut Providers) {
     *p = Providers { dropck_outlives, adt_dtorck_constraint, ..*p };
@@ -27,120 +25,109 @@ fn dropck_outlives<'tcx>(
 ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, DropckOutlivesResult<'tcx>>>, NoSolution> {
     debug!("dropck_outlives(goal={:#?})", canonical_goal);
 
-    let (ref infcx, goal, canonical_inference_vars) =
-        tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &canonical_goal);
-    let tcx = infcx.tcx;
-    let ParamEnvAnd { param_env, value: for_ty } = goal;
-
-    let mut result = DropckOutlivesResult { kinds: vec![], overflows: vec![] };
-
-    // A stack of types left to process. Each round, we pop
-    // something from the stack and invoke
-    // `dtorck_constraint_for_ty`. This may produce new types that
-    // have to be pushed on the stack. This continues until we have explored
-    // all the reachable types from the type `for_ty`.
-    //
-    // Example: Imagine that we have the following code:
-    //
-    // ```rust
-    // struct A {
-    //     value: B,
-    //     children: Vec<A>,
-    // }
-    //
-    // struct B {
-    //     value: u32
-    // }
-    //
-    // fn f() {
-    //   let a: A = ...;
-    //   ..
-    // } // here, `a` is dropped
-    // ```
-    //
-    // at the point where `a` is dropped, we need to figure out
-    // which types inside of `a` contain region data that may be
-    // accessed by any destructors in `a`. We begin by pushing `A`
-    // onto the stack, as that is the type of `a`. We will then
-    // invoke `dtorck_constraint_for_ty` which will expand `A`
-    // into the types of its fields `(B, Vec<A>)`. These will get
-    // pushed onto the stack. Eventually, expanding `Vec<A>` will
-    // lead to us trying to push `A` a second time -- to prevent
-    // infinite recursion, we notice that `A` was already pushed
-    // once and stop.
-    let mut ty_stack = vec![(for_ty, 0)];
-
-    // Set used to detect infinite recursion.
-    let mut ty_set = FxHashSet::default();
-
-    let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
-
-    let cause = ObligationCause::dummy();
-    let mut constraints = DropckConstraint::empty();
-    while let Some((ty, depth)) = ty_stack.pop() {
-        debug!(
-            "{} kinds, {} overflows, {} ty_stack",
-            result.kinds.len(),
-            result.overflows.len(),
-            ty_stack.len()
-        );
-        dtorck_constraint_for_ty(tcx, DUMMY_SP, for_ty, depth, ty, &mut constraints)?;
-
-        // "outlives" represent types/regions that may be touched
-        // by a destructor.
-        result.kinds.append(&mut constraints.outlives);
-        result.overflows.append(&mut constraints.overflows);
-
-        // If we have even one overflow, we should stop trying to evaluate further --
-        // chances are, the subsequent overflows for this evaluation won't provide useful
-        // information and will just decrease the speed at which we can emit these errors
-        // (since we'll be printing for just that much longer for the often enormous types
-        // that result here).
-        if !result.overflows.is_empty() {
-            break;
-        }
+    tcx.infer_ctxt().enter_canonical_trait_query(&canonical_goal, |ocx, goal| {
+        let tcx = ocx.infcx.tcx;
+        let ParamEnvAnd { param_env, value: for_ty } = goal;
+
+        let mut result = DropckOutlivesResult { kinds: vec![], overflows: vec![] };
+
+        // A stack of types left to process. Each round, we pop
+        // something from the stack and invoke
+        // `dtorck_constraint_for_ty`. This may produce new types that
+        // have to be pushed on the stack. This continues until we have explored
+        // all the reachable types from the type `for_ty`.
+        //
+        // Example: Imagine that we have the following code:
+        //
+        // ```rust
+        // struct A {
+        //     value: B,
+        //     children: Vec<A>,
+        // }
+        //
+        // struct B {
+        //     value: u32
+        // }
+        //
+        // fn f() {
+        //   let a: A = ...;
+        //   ..
+        // } // here, `a` is dropped
+        // ```
+        //
+        // at the point where `a` is dropped, we need to figure out
+        // which types inside of `a` contain region data that may be
+        // accessed by any destructors in `a`. We begin by pushing `A`
+        // onto the stack, as that is the type of `a`. We will then
+        // invoke `dtorck_constraint_for_ty` which will expand `A`
+        // into the types of its fields `(B, Vec<A>)`. These will get
+        // pushed onto the stack. Eventually, expanding `Vec<A>` will
+        // lead to us trying to push `A` a second time -- to prevent
+        // infinite recursion, we notice that `A` was already pushed
+        // once and stop.
+        let mut ty_stack = vec![(for_ty, 0)];
+
+        // Set used to detect infinite recursion.
+        let mut ty_set = FxHashSet::default();
+
+        let cause = ObligationCause::dummy();
+        let mut constraints = DropckConstraint::empty();
+        while let Some((ty, depth)) = ty_stack.pop() {
+            debug!(
+                "{} kinds, {} overflows, {} ty_stack",
+                result.kinds.len(),
+                result.overflows.len(),
+                ty_stack.len()
+            );
+            dtorck_constraint_for_ty(tcx, DUMMY_SP, for_ty, depth, ty, &mut constraints)?;
+
+            // "outlives" represent types/regions that may be touched
+            // by a destructor.
+            result.kinds.append(&mut constraints.outlives);
+            result.overflows.append(&mut constraints.overflows);
+
+            // If we have even one overflow, we should stop trying to evaluate further --
+            // chances are, the subsequent overflows for this evaluation won't provide useful
+            // information and will just decrease the speed at which we can emit these errors
+            // (since we'll be printing for just that much longer for the often enormous types
+            // that result here).
+            if !result.overflows.is_empty() {
+                break;
+            }
 
-        // dtorck types are "types that will get dropped but which
-        // do not themselves define a destructor", more or less. We have
-        // to push them onto the stack to be expanded.
-        for ty in constraints.dtorck_types.drain(..) {
-            match infcx.at(&cause, param_env).normalize(ty) {
-                Ok(Normalized { value: ty, obligations }) => {
-                    fulfill_cx.register_predicate_obligations(infcx, obligations);
-
-                    debug!("dropck_outlives: ty from dtorck_types = {:?}", ty);
-
-                    match ty.kind() {
-                        // All parameters live for the duration of the
-                        // function.
-                        ty::Param(..) => {}
-
-                        // A projection that we couldn't resolve - it
-                        // might have a destructor.
-                        ty::Projection(..) | ty::Opaque(..) => {
-                            result.kinds.push(ty.into());
-                        }
+            // dtorck types are "types that will get dropped but which
+            // do not themselves define a destructor", more or less. We have
+            // to push them onto the stack to be expanded.
+            for ty in constraints.dtorck_types.drain(..) {
+                let Normalized { value: ty, obligations } =
+                    ocx.infcx.at(&cause, param_env).normalize(ty)?;
+                ocx.register_obligations(obligations);
+
+                debug!("dropck_outlives: ty from dtorck_types = {:?}", ty);
+
+                match ty.kind() {
+                    // All parameters live for the duration of the
+                    // function.
+                    ty::Param(..) => {}
+
+                    // A projection that we couldn't resolve - it
+                    // might have a destructor.
+                    ty::Projection(..) | ty::Opaque(..) => {
+                        result.kinds.push(ty.into());
+                    }
 
-                        _ => {
-                            if ty_set.insert(ty) {
-                                ty_stack.push((ty, depth + 1));
-                            }
+                    _ => {
+                        if ty_set.insert(ty) {
+                            ty_stack.push((ty, depth + 1));
                         }
                     }
                 }
-
-                // We don't actually expect to fail to normalize.
-                // That implies a WF error somewhere else.
-                Err(NoSolution) => {
-                    return Err(NoSolution);
-                }
             }
         }
-    }
-
-    debug!("dropck_outlives: result = {:#?}", result);
 
-    infcx.make_canonicalized_query_response(canonical_inference_vars, result, &mut *fulfill_cx)
+        debug!("dropck_outlives: result = {:#?}", result);
+        Ok(result)
+    })
 }
 
 /// Returns a set of constraints that needs to be satisfied in
index 3cef47c0f8ba481d2b3bde2a117b38be3ae5bb18..cb41c4f94e2e69b803caaba802a51c7fc06f2b25 100644 (file)
@@ -235,7 +235,9 @@ fn recurse_build(&mut self, node: thir::ExprId) -> Result<NodeId, ErrorGuarantee
                     neg,
                 }) {
                     Ok(c) => c,
-                    Err(LitToConstError::Reported) => self.tcx.const_error(node.ty),
+                    Err(LitToConstError::Reported(guar)) => {
+                        self.tcx.const_error_with_guaranteed(node.ty, guar)
+                    }
                     Err(LitToConstError::TypeError) => {
                         bug!("encountered type error in lit_to_const")
                     }
index 52ba0eee97cd5e4d526383e09bf240c0a6d298b2..b59be0a0ea7945d5907438b653215a5f6320c165 100644 (file)
@@ -668,7 +668,7 @@ fn layout_of_uncached<'tcx>(
                 let mut abi = Abi::Aggregate { sized: true };
                 let index = VariantIdx::new(0);
                 for field in &variants[index] {
-                    assert!(!field.is_unsized());
+                    assert!(field.is_sized());
                     align = align.max(field.align);
 
                     // If all non-ZST fields have the same ABI, forward this ABI
index 2373fb2ec4fb04d5de652c08fc91be338212b4be..c94a27b12a3a73661f7295f57a79f152ba3b9c3c 100644 (file)
@@ -87,9 +87,10 @@ changelog-seen = 2
 # this flag will indicate that this version check should not be done.
 #version-check = true
 
-# Link libstdc++ statically into the rustc_llvm instead of relying on a
-# dynamic version to be available.
-#static-libstdcpp = true
+# When true, link libstdc++ statically into the rustc_llvm.
+# This is useful if you don't want to use the dynamic version of that
+# library provided by LLVM.
+#static-libstdcpp = false
 
 # Whether to use Ninja to build LLVM. This runs much faster than make.
 #ninja = true
index 8c6663569a553e87f226bbd7a1e1c361acbebfd6..e5fbfc55761f41302171b33cf17ac00acc1602bc 100644 (file)
     // The rustc fork of LLVM 14 and earlier also special-cases these function names to be able to optimize them
     // like `malloc`, `realloc`, and `free`, respectively.
     #[rustc_allocator]
-    #[cfg_attr(not(bootstrap), rustc_nounwind)]
-    #[cfg_attr(bootstrap, rustc_allocator_nounwind)]
+    #[rustc_nounwind]
     fn __rust_alloc(size: usize, align: usize) -> *mut u8;
     #[rustc_deallocator]
-    #[cfg_attr(not(bootstrap), rustc_nounwind)]
-    #[cfg_attr(bootstrap, rustc_allocator_nounwind)]
+    #[rustc_nounwind]
     fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize);
     #[rustc_reallocator]
-    #[cfg_attr(not(bootstrap), rustc_nounwind)]
-    #[cfg_attr(bootstrap, rustc_allocator_nounwind)]
+    #[rustc_nounwind]
     fn __rust_realloc(ptr: *mut u8, old_size: usize, align: usize, new_size: usize) -> *mut u8;
     #[rustc_allocator_zeroed]
-    #[cfg_attr(not(bootstrap), rustc_nounwind)]
-    #[cfg_attr(bootstrap, rustc_allocator_nounwind)]
+    #[rustc_nounwind]
     fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8;
 }
 
index b2f0194599b287057f41023545a244749eaf232f..1a5938fd34cf17d2b58d8c836be0f7d6c387af58 100644 (file)
@@ -22,7 +22,6 @@ fn allocate_zeroed() {
 }
 
 #[bench]
-#[cfg_attr(miri, ignore)] // isolated Miri does not support benchmarks
 fn alloc_owned_small(b: &mut Bencher) {
     b.iter(|| {
         let _: Box<_> = Box::new(10);
index 66f4c19e0f91ab44df2e8991bad69ec58219428a..97186589a4f4c30f1f0d935e61dca057c9b9e634 100644 (file)
@@ -1661,7 +1661,7 @@ fn try_from(boxed_slice: Box<[T]>) -> Result<Self, Self::Error> {
 }
 
 #[cfg(not(no_global_oom_handling))]
-#[stable(feature = "boxed_array_try_from_vec", since = "CURRENT_RUSTC_VERSION")]
+#[stable(feature = "boxed_array_try_from_vec", since = "1.66.0")]
 impl<T, const N: usize> TryFrom<Vec<T>> for Box<[T; N]> {
     type Error = Vec<T>;
 
index c4c75e46a2a3b687574c14327e129332c54f40c0..8a77193471234fb7149e0ec2fc80f7cd18fd98c7 100644 (file)
@@ -580,7 +580,7 @@ impl<K, V> BTreeMap<K, V> {
     /// map.insert(1, "a");
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_stable(feature = "const_btree_new", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "const_btree_new", since = "1.66.0")]
     #[must_use]
     pub const fn new() -> BTreeMap<K, V> {
         BTreeMap { root: None, length: 0, alloc: ManuallyDrop::new(Global), _marker: PhantomData }
@@ -711,7 +711,7 @@ pub fn get_key_value<Q: ?Sized>(&self, k: &Q) -> Option<(&K, &V)>
     /// map.insert(2, "a");
     /// assert_eq!(map.first_key_value(), Some((&1, &"b")));
     /// ```
-    #[stable(feature = "map_first_last", since = "CURRENT_RUSTC_VERSION")]
+    #[stable(feature = "map_first_last", since = "1.66.0")]
     pub fn first_key_value(&self) -> Option<(&K, &V)>
     where
         K: Ord,
@@ -739,7 +739,7 @@ pub fn first_key_value(&self) -> Option<(&K, &V)>
     /// assert_eq!(*map.get(&1).unwrap(), "first");
     /// assert_eq!(*map.get(&2).unwrap(), "b");
     /// ```
-    #[stable(feature = "map_first_last", since = "CURRENT_RUSTC_VERSION")]
+    #[stable(feature = "map_first_last", since = "1.66.0")]
     pub fn first_entry(&mut self) -> Option<OccupiedEntry<'_, K, V, A>>
     where
         K: Ord,
@@ -773,7 +773,7 @@ pub fn first_entry(&mut self) -> Option<OccupiedEntry<'_, K, V, A>>
     /// }
     /// assert!(map.is_empty());
     /// ```
-    #[stable(feature = "map_first_last", since = "CURRENT_RUSTC_VERSION")]
+    #[stable(feature = "map_first_last", since = "1.66.0")]
     pub fn pop_first(&mut self) -> Option<(K, V)>
     where
         K: Ord,
@@ -796,7 +796,7 @@ pub fn pop_first(&mut self) -> Option<(K, V)>
     /// map.insert(2, "a");
     /// assert_eq!(map.last_key_value(), Some((&2, &"a")));
     /// ```
-    #[stable(feature = "map_first_last", since = "CURRENT_RUSTC_VERSION")]
+    #[stable(feature = "map_first_last", since = "1.66.0")]
     pub fn last_key_value(&self) -> Option<(&K, &V)>
     where
         K: Ord,
@@ -824,7 +824,7 @@ pub fn last_key_value(&self) -> Option<(&K, &V)>
     /// assert_eq!(*map.get(&1).unwrap(), "a");
     /// assert_eq!(*map.get(&2).unwrap(), "last");
     /// ```
-    #[stable(feature = "map_first_last", since = "CURRENT_RUSTC_VERSION")]
+    #[stable(feature = "map_first_last", since = "1.66.0")]
     pub fn last_entry(&mut self) -> Option<OccupiedEntry<'_, K, V, A>>
     where
         K: Ord,
@@ -858,7 +858,7 @@ pub fn last_entry(&mut self) -> Option<OccupiedEntry<'_, K, V, A>>
     /// }
     /// assert!(map.is_empty());
     /// ```
-    #[stable(feature = "map_first_last", since = "CURRENT_RUSTC_VERSION")]
+    #[stable(feature = "map_first_last", since = "1.66.0")]
     pub fn pop_last(&mut self) -> Option<(K, V)>
     where
         K: Ord,
index aadb0dc9c40d9304a68176eaea9d60f9a12bf433..64bce0ff8c0483f805179f10d61e69f7b52feba2 100644 (file)
@@ -94,6 +94,7 @@ fn test_partial_eq() {
 
 #[test]
 #[cfg(target_arch = "x86_64")]
+#[cfg_attr(miri, ignore)] // We'd like to run Miri with layout randomization
 fn test_sizes() {
     assert_eq!(core::mem::size_of::<LeafNode<(), ()>>(), 16);
     assert_eq!(core::mem::size_of::<LeafNode<i64, i64>>(), 16 + CAPACITY * 2 * 8);
index b8e5cf8eb5a82d972d1a4bfab45588164dc01fd4..4ddb211925202f45b27248d46f0c0e5888d17b1f 100644 (file)
@@ -343,7 +343,7 @@ impl<T> BTreeSet<T> {
     /// let mut set: BTreeSet<i32> = BTreeSet::new();
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_stable(feature = "const_btree_new", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "const_btree_new", since = "1.66.0")]
     #[must_use]
     pub const fn new() -> BTreeSet<T> {
         BTreeSet { map: BTreeMap::new() }
@@ -796,7 +796,7 @@ pub fn is_superset(&self, other: &BTreeSet<T, A>) -> bool
     /// assert_eq!(set.first(), Some(&1));
     /// ```
     #[must_use]
-    #[stable(feature = "map_first_last", since = "CURRENT_RUSTC_VERSION")]
+    #[stable(feature = "map_first_last", since = "1.66.0")]
     pub fn first(&self) -> Option<&T>
     where
         T: Ord,
@@ -822,7 +822,7 @@ pub fn first(&self) -> Option<&T>
     /// assert_eq!(set.last(), Some(&2));
     /// ```
     #[must_use]
-    #[stable(feature = "map_first_last", since = "CURRENT_RUSTC_VERSION")]
+    #[stable(feature = "map_first_last", since = "1.66.0")]
     pub fn last(&self) -> Option<&T>
     where
         T: Ord,
@@ -846,7 +846,7 @@ pub fn last(&self) -> Option<&T>
     /// }
     /// assert!(set.is_empty());
     /// ```
-    #[stable(feature = "map_first_last", since = "CURRENT_RUSTC_VERSION")]
+    #[stable(feature = "map_first_last", since = "1.66.0")]
     pub fn pop_first(&mut self) -> Option<T>
     where
         T: Ord,
@@ -870,7 +870,7 @@ pub fn pop_first(&mut self) -> Option<T>
     /// }
     /// assert!(set.is_empty());
     /// ```
-    #[stable(feature = "map_first_last", since = "CURRENT_RUSTC_VERSION")]
+    #[stable(feature = "map_first_last", since = "1.66.0")]
     pub fn pop_last(&mut self) -> Option<T>
     where
         T: Ord,
index 161a375736c65438e77b9e015448ec722594d436..3e0b0f735508e5859c382937b2bced3e8597eb95 100644 (file)
@@ -139,7 +139,7 @@ fn fmt(
                 " because the computed capacity exceeded the collection's maximum"
             }
             TryReserveErrorKind::AllocError { .. } => {
-                " because the memory allocator returned a error"
+                " because the memory allocator returned an error"
             }
         };
         fmt.write_str(reason)
index 1f2daef213c3b78a2cf2fb02d56f05a9f446b947..6e0f83020f9574de20c56761a70ca4978941574a 100644 (file)
@@ -3,7 +3,6 @@
 use super::*;
 
 #[bench]
-#[cfg_attr(miri, ignore)] // isolated Miri does not support benchmarks
 fn bench_push_back_100(b: &mut test::Bencher) {
     let mut deq = VecDeque::with_capacity(101);
     b.iter(|| {
@@ -16,7 +15,6 @@ fn bench_push_back_100(b: &mut test::Bencher) {
 }
 
 #[bench]
-#[cfg_attr(miri, ignore)] // isolated Miri does not support benchmarks
 fn bench_push_front_100(b: &mut test::Bencher) {
     let mut deq = VecDeque::with_capacity(101);
     b.iter(|| {
@@ -29,12 +27,15 @@ fn bench_push_front_100(b: &mut test::Bencher) {
 }
 
 #[bench]
-#[cfg_attr(miri, ignore)] // isolated Miri does not support benchmarks
 fn bench_pop_back_100(b: &mut test::Bencher) {
-    let mut deq = VecDeque::<i32>::with_capacity(101);
+    let size = 100;
+    let mut deq = VecDeque::<i32>::with_capacity(size + 1);
+    // We'll mess with private state to pretend like `deq` is filled.
+    // Make sure the buffer is initialized so that we don't read uninit memory.
+    unsafe { deq.ptr().write_bytes(0u8, size + 1) };
 
     b.iter(|| {
-        deq.head = 100;
+        deq.head = size;
         deq.tail = 0;
         while !deq.is_empty() {
             test::black_box(deq.pop_back());
@@ -43,9 +44,9 @@ fn bench_pop_back_100(b: &mut test::Bencher) {
 }
 
 #[bench]
-#[cfg_attr(miri, ignore)] // isolated Miri does not support benchmarks
 fn bench_retain_whole_10000(b: &mut test::Bencher) {
-    let v = (1..100000).collect::<VecDeque<u32>>();
+    let size = if cfg!(miri) { 1000 } else { 100000 };
+    let v = (1..size).collect::<VecDeque<u32>>();
 
     b.iter(|| {
         let mut v = v.clone();
@@ -54,9 +55,9 @@ fn bench_retain_whole_10000(b: &mut test::Bencher) {
 }
 
 #[bench]
-#[cfg_attr(miri, ignore)] // isolated Miri does not support benchmarks
 fn bench_retain_odd_10000(b: &mut test::Bencher) {
-    let v = (1..100000).collect::<VecDeque<u32>>();
+    let size = if cfg!(miri) { 1000 } else { 100000 };
+    let v = (1..size).collect::<VecDeque<u32>>();
 
     b.iter(|| {
         let mut v = v.clone();
@@ -65,23 +66,26 @@ fn bench_retain_odd_10000(b: &mut test::Bencher) {
 }
 
 #[bench]
-#[cfg_attr(miri, ignore)] // isolated Miri does not support benchmarks
 fn bench_retain_half_10000(b: &mut test::Bencher) {
-    let v = (1..100000).collect::<VecDeque<u32>>();
+    let size = if cfg!(miri) { 1000 } else { 100000 };
+    let v = (1..size).collect::<VecDeque<u32>>();
 
     b.iter(|| {
         let mut v = v.clone();
-        v.retain(|x| *x > 50000)
+        v.retain(|x| *x > size / 2)
     })
 }
 
 #[bench]
-#[cfg_attr(miri, ignore)] // isolated Miri does not support benchmarks
 fn bench_pop_front_100(b: &mut test::Bencher) {
-    let mut deq = VecDeque::<i32>::with_capacity(101);
+    let size = 100;
+    let mut deq = VecDeque::<i32>::with_capacity(size + 1);
+    // We'll mess with private state to pretend like `deq` is filled.
+    // Make sure the buffer is initialized so that we don't read uninit memory.
+    unsafe { deq.ptr().write_bytes(0u8, size + 1) };
 
     b.iter(|| {
-        deq.head = 100;
+        deq.head = size;
         deq.tail = 0;
         while !deq.is_empty() {
             test::black_box(deq.pop_front());
index 38887f29af1537733249ec7a3da964a6c0b25ed4..9193c79bee875daf690d6f3af31e252cee70ff21 100644 (file)
@@ -1,3 +1,4 @@
+use core::borrow::Borrow;
 use core::iter::*;
 use core::mem;
 use core::num::Wrapping;
@@ -403,13 +404,31 @@ fn bench_trusted_random_access_adapters(b: &mut Bencher) {
 
 /// Exercises the iter::Copied specialization for slice::Iter
 #[bench]
-fn bench_copied_array_chunks(b: &mut Bencher) {
+fn bench_copied_chunks(b: &mut Bencher) {
+    let v = vec![1u8; 1024];
+
+    b.iter(|| {
+        let mut iter = black_box(&v).iter().copied();
+        let mut acc = Wrapping(0);
+        // This uses a while-let loop to side-step the TRA specialization in ArrayChunks
+        while let Ok(chunk) = iter.next_chunk::<{ mem::size_of::<u64>() }>() {
+            let d = u64::from_ne_bytes(chunk);
+            acc += Wrapping(d.rotate_left(7).wrapping_add(1));
+        }
+        acc
+    })
+}
+
+/// Exercises the TrustedRandomAccess specialization in ArrayChunks
+#[bench]
+fn bench_trusted_random_access_chunks(b: &mut Bencher) {
     let v = vec![1u8; 1024];
 
     b.iter(|| {
         black_box(&v)
             .iter()
-            .copied()
+            // this shows that we're not relying on the slice::Iter specialization in Copied
+            .map(|b| *b.borrow())
             .array_chunks::<{ mem::size_of::<u64>() }>()
             .map(|ary| {
                 let d = u64::from_ne_bytes(ary);
index 1e462e3fc3f8c4e2f8bb73f10c21f92db19fc822..f1244d93285e30ba8777f0de2719eead94a960d2 100644 (file)
@@ -1,10 +1,10 @@
 // wasm32 does not support benches (no time).
 #![cfg(not(target_arch = "wasm32"))]
 #![feature(flt2dec)]
-#![feature(int_log)]
 #![feature(test)]
 #![feature(trusted_random_access)]
 #![feature(iter_array_chunks)]
+#![feature(iter_next_chunk)]
 
 extern crate test;
 
index 920e559cc4aa39e8d7eafed71a225b94b657e588..f50d9a8e1bdf38cc94626ac35167613c0819dfe5 100644 (file)
@@ -7,8 +7,8 @@
 use crate::cmp;
 use crate::error::Error;
 use crate::fmt;
-use crate::mem::{self, ValidAlign};
-use crate::ptr::NonNull;
+use crate::mem;
+use crate::ptr::{Alignment, NonNull};
 
 // While this function is used in one place and its implementation
 // could be inlined, the previous attempts to do so made rustc
@@ -46,7 +46,7 @@ pub struct Layout {
     //
     // (However, we do not analogously require `align >= sizeof(void*)`,
     //  even though that is *also* a requirement of `posix_memalign`.)
-    align: ValidAlign,
+    align: Alignment,
 }
 
 impl Layout {
@@ -71,11 +71,11 @@ pub const fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutEr
         }
 
         // SAFETY: just checked that align is a power of two.
-        Layout::from_size_valid_align(size, unsafe { ValidAlign::new_unchecked(align) })
+        Layout::from_size_alignment(size, unsafe { Alignment::new_unchecked(align) })
     }
 
     #[inline(always)]
-    const fn max_size_for_align(align: ValidAlign) -> usize {
+    const fn max_size_for_align(align: Alignment) -> usize {
         // (power-of-two implies align != 0.)
 
         // Rounded up size is:
@@ -95,7 +95,7 @@ const fn max_size_for_align(align: ValidAlign) -> usize {
 
     /// Internal helper constructor to skip revalidating alignment validity.
     #[inline]
-    const fn from_size_valid_align(size: usize, align: ValidAlign) -> Result<Self, LayoutError> {
+    const fn from_size_alignment(size: usize, align: Alignment) -> Result<Self, LayoutError> {
         if size > Self::max_size_for_align(align) {
             return Err(LayoutError);
         }
@@ -117,7 +117,7 @@ const fn from_size_valid_align(size: usize, align: ValidAlign) -> Result<Self, L
     #[rustc_allow_const_fn_unstable(ptr_alignment_type)]
     pub const unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self {
         // SAFETY: the caller is required to uphold the preconditions.
-        unsafe { Layout { size, align: ValidAlign::new_unchecked(align) } }
+        unsafe { Layout { size, align: Alignment::new_unchecked(align) } }
     }
 
     /// The minimum size in bytes for a memory block of this layout.
@@ -321,7 +321,7 @@ pub fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutError> {
         let alloc_size = padded_size.checked_mul(n).ok_or(LayoutError)?;
 
         // The safe constructor is called here to enforce the isize size limit.
-        Layout::from_size_valid_align(alloc_size, self.align).map(|layout| (layout, padded_size))
+        Layout::from_size_alignment(alloc_size, self.align).map(|layout| (layout, padded_size))
     }
 
     /// Creates a layout describing the record for `self` followed by
@@ -379,7 +379,7 @@ pub fn extend(&self, next: Self) -> Result<(Self, usize), LayoutError> {
         let new_size = offset.checked_add(next.size()).ok_or(LayoutError)?;
 
         // The safe constructor is called here to enforce the isize size limit.
-        let layout = Layout::from_size_valid_align(new_size, new_align)?;
+        let layout = Layout::from_size_alignment(new_size, new_align)?;
         Ok((layout, offset))
     }
 
@@ -400,7 +400,7 @@ pub fn extend(&self, next: Self) -> Result<(Self, usize), LayoutError> {
     pub fn repeat_packed(&self, n: usize) -> Result<Self, LayoutError> {
         let size = self.size().checked_mul(n).ok_or(LayoutError)?;
         // The safe constructor is called here to enforce the isize size limit.
-        Layout::from_size_valid_align(size, self.align)
+        Layout::from_size_alignment(size, self.align)
     }
 
     /// Creates a layout describing the record for `self` followed by
@@ -414,7 +414,7 @@ pub fn repeat_packed(&self, n: usize) -> Result<Self, LayoutError> {
     pub fn extend_packed(&self, next: Self) -> Result<Self, LayoutError> {
         let new_size = self.size().checked_add(next.size()).ok_or(LayoutError)?;
         // The safe constructor is called here to enforce the isize size limit.
-        Layout::from_size_valid_align(new_size, self.align)
+        Layout::from_size_alignment(new_size, self.align)
     }
 
     /// Creates a layout describing the record for a `[T; n]`.
@@ -425,10 +425,10 @@ pub fn extend_packed(&self, next: Self) -> Result<Self, LayoutError> {
     #[inline]
     pub fn array<T>(n: usize) -> Result<Self, LayoutError> {
         // Reduce the amount of code we need to monomorphize per `T`.
-        return inner(mem::size_of::<T>(), ValidAlign::of::<T>(), n);
+        return inner(mem::size_of::<T>(), Alignment::of::<T>(), n);
 
         #[inline]
-        fn inner(element_size: usize, align: ValidAlign, n: usize) -> Result<Layout, LayoutError> {
+        fn inner(element_size: usize, align: Alignment, n: usize) -> Result<Layout, LayoutError> {
             // We need to check two things about the size:
             //  - That the total size won't overflow a `usize`, and
             //  - That the total size still fits in an `isize`.
@@ -443,7 +443,7 @@ fn inner(element_size: usize, align: ValidAlign, n: usize) -> Result<Layout, Lay
 
             // SAFETY: We just checked above that the `array_size` will not
             // exceed `isize::MAX` even when rounded up to the alignment.
-            // And `ValidAlign` guarantees it's a power of two.
+            // And `Alignment` guarantees it's a power of two.
             unsafe { Ok(Layout::from_size_align_unchecked(array_size, align.as_usize())) }
         }
     }
index eae0e1c7618663459a2148fb20ab6baef6606c87..2090756d7a3ec82252be10dc39e91d16cdff1234 100644 (file)
@@ -865,24 +865,6 @@ fn try_collect_into_array<I, T, R, const N: usize>(
         return Ok(Try::from_output(unsafe { mem::zeroed() }));
     }
 
-    struct Guard<'a, T, const N: usize> {
-        array_mut: &'a mut [MaybeUninit<T>; N],
-        initialized: usize,
-    }
-
-    impl<T, const N: usize> Drop for Guard<'_, T, N> {
-        fn drop(&mut self) {
-            debug_assert!(self.initialized <= N);
-
-            // SAFETY: this slice will contain only initialized objects.
-            unsafe {
-                crate::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(
-                    &mut self.array_mut.get_unchecked_mut(..self.initialized),
-                ));
-            }
-        }
-    }
-
     let mut array = MaybeUninit::uninit_array::<N>();
     let mut guard = Guard { array_mut: &mut array, initialized: 0 };
 
@@ -896,13 +878,11 @@ fn drop(&mut self) {
                     ControlFlow::Continue(elem) => elem,
                 };
 
-                // SAFETY: `guard.initialized` starts at 0, is increased by one in the
-                // loop and the loop is aborted once it reaches N (which is
-                // `array.len()`).
+                // SAFETY: `guard.initialized` starts at 0, which means push can be called
+                // at most N times, which this loop does.
                 unsafe {
-                    guard.array_mut.get_unchecked_mut(guard.initialized).write(item);
+                    guard.push_unchecked(item);
                 }
-                guard.initialized += 1;
             }
             None => {
                 let alive = 0..guard.initialized;
@@ -920,6 +900,55 @@ fn drop(&mut self) {
     Ok(Try::from_output(output))
 }
 
+/// Panic guard for incremental initialization of arrays.
+///
+/// Disarm the guard with `mem::forget` once the array has been initialized.
+///
+/// # Safety
+///
+/// All write accesses to this structure are unsafe and must maintain a correct
+/// count of `initialized` elements.
+///
+/// To minimize indirection fields are still pub but callers should at least use
+/// `push_unchecked` to signal that something unsafe is going on.
+pub(crate) struct Guard<'a, T, const N: usize> {
+    /// The array to be initialized.
+    pub array_mut: &'a mut [MaybeUninit<T>; N],
+    /// The number of items that have been initialized so far.
+    pub initialized: usize,
+}
+
+impl<T, const N: usize> Guard<'_, T, N> {
+    /// Adds an item to the array and updates the initialized item counter.
+    ///
+    /// # Safety
+    ///
+    /// No more than N elements must be initialized.
+    #[inline]
+    pub unsafe fn push_unchecked(&mut self, item: T) {
+        // SAFETY: If `initialized` was correct before and the caller does not
+        // invoke this method more than N times then writes will be in-bounds
+        // and slots will not be initialized more than once.
+        unsafe {
+            self.array_mut.get_unchecked_mut(self.initialized).write(item);
+            self.initialized = self.initialized.unchecked_add(1);
+        }
+    }
+}
+
+impl<T, const N: usize> Drop for Guard<'_, T, N> {
+    fn drop(&mut self) {
+        debug_assert!(self.initialized <= N);
+
+        // SAFETY: this slice will contain only initialized objects.
+        unsafe {
+            crate::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(
+                &mut self.array_mut.get_unchecked_mut(..self.initialized),
+            ));
+        }
+    }
+}
+
 /// Returns the next chunk of `N` items from the iterator or errors with an
 /// iterator over the remainder. Used for `Iterator::next_chunk`.
 #[inline]
index f0fa2e1d2c190a629def5e5185408d8419ff3e71..5db5cbfc3dfdde2c6349e3fc145c05f29f4d6fdb 100644 (file)
@@ -24,6 +24,7 @@
 
 use crate::const_closure::ConstFnMutClosure;
 use crate::marker::Destruct;
+#[cfg(bootstrap)]
 use crate::marker::StructuralPartialEq;
 
 use self::Ordering::*;
@@ -331,6 +332,7 @@ pub struct AssertParamIsEq<T: Eq + ?Sized> {
 /// assert_eq!(Ordering::Greater, result);
 /// ```
 #[derive(Clone, Copy, Eq, Debug, Hash)]
+#[cfg_attr(not(bootstrap), derive_const(PartialOrd, Ord, PartialEq))]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[repr(i8)]
 pub enum Ordering {
@@ -877,10 +879,12 @@ fn clamp(self, min: Self, max: Self) -> Self
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
+#[cfg(bootstrap)]
 impl StructuralPartialEq for Ordering {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+#[cfg(bootstrap)]
 impl const PartialEq for Ordering {
     #[inline]
     fn eq(&self, other: &Self) -> bool {
@@ -890,6 +894,7 @@ fn eq(&self, other: &Self) -> bool {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+#[cfg(bootstrap)]
 impl const Ord for Ordering {
     #[inline]
     fn cmp(&self, other: &Ordering) -> Ordering {
@@ -899,6 +904,7 @@ fn cmp(&self, other: &Ordering) -> Ordering {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+#[cfg(bootstrap)]
 impl const PartialOrd for Ordering {
     #[inline]
     fn partial_cmp(&self, other: &Ordering) -> Option<Ordering> {
index a5b4e965552c03cf8443cd5fdd7735bb9e789510..d96b53de0a338328fec822aa2a2bfa1e66de5e9f 100644 (file)
@@ -99,7 +99,7 @@
 /// ```
 #[cfg_attr(not(test), rustc_diagnostic_item = "Default")]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(not(bootstrap), const_trait)]
+#[const_trait]
 pub trait Default: Sized {
     /// Returns the "default value" for a type.
     ///
index b24ca037d1afc3e5cd094f774c00be678a9f7e28..c9c7cdf4defc6d16e67b68a22f571eee4ab21d15 100644 (file)
@@ -493,7 +493,7 @@ fn description(&self) -> &str {
     }
 }
 
-#[stable(feature = "duration_checked_float", since = "CURRENT_RUSTC_VERSION")]
+#[stable(feature = "duration_checked_float", since = "1.66.0")]
 impl Error for crate::time::TryFromFloatSecsError {}
 
 #[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")]
index aa13435e6808d0de31fa8c0d8bc387c245296266..c755afa39eb608de9ffffd576b0b4d5fa443b0f5 100644 (file)
@@ -86,7 +86,8 @@
 #![stable(feature = "rust1", since = "1.0.0")]
 
 use crate::fmt;
-use crate::marker;
+use crate::intrinsics::const_eval_select;
+use crate::marker::{self, Destruct};
 
 #[stable(feature = "rust1", since = "1.0.0")]
 #[allow(deprecated)]
 /// [impl]: ../../std/primitive.str.html#impl-Hash-for-str
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_diagnostic_item = "Hash"]
+#[const_trait]
 pub trait Hash {
     /// Feeds this value into the given [`Hasher`].
     ///
@@ -234,13 +236,25 @@ pub trait Hash {
     /// [`hash`]: Hash::hash
     /// [`hash_slice`]: Hash::hash_slice
     #[stable(feature = "hash_slice", since = "1.3.0")]
-    fn hash_slice<H: Hasher>(data: &[Self], state: &mut H)
+    fn hash_slice<H: ~const Hasher>(data: &[Self], state: &mut H)
     where
         Self: Sized,
     {
-        for piece in data {
-            piece.hash(state);
+        //FIXME(const_trait_impl): revert to only a for loop
+        fn rt<T: Hash, H: Hasher>(data: &[T], state: &mut H) {
+            for piece in data {
+                piece.hash(state)
+            }
+        }
+        const fn ct<T: ~const Hash, H: ~const Hasher>(data: &[T], state: &mut H) {
+            let mut i = 0;
+            while i < data.len() {
+                data[i].hash(state);
+                i += 1;
+            }
         }
+        // SAFETY: same behavior, CT just uses while instead of for
+        unsafe { const_eval_select((data, state), ct, rt) };
     }
 }
 
@@ -313,6 +327,7 @@ pub(crate) mod macros {
 /// [`write_u8`]: Hasher::write_u8
 /// [`write_u32`]: Hasher::write_u32
 #[stable(feature = "rust1", since = "1.0.0")]
+#[const_trait]
 pub trait Hasher {
     /// Returns the hash value for the values written so far.
     ///
@@ -558,7 +573,8 @@ fn write_str(&mut self, s: &str) {
 }
 
 #[stable(feature = "indirect_hasher_impl", since = "1.22.0")]
-impl<H: Hasher + ?Sized> Hasher for &mut H {
+#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
+impl<H: ~const Hasher + ?Sized> const Hasher for &mut H {
     fn finish(&self) -> u64 {
         (**self).finish()
     }
@@ -638,6 +654,7 @@ fn write_str(&mut self, s: &str) {
 /// [`build_hasher`]: BuildHasher::build_hasher
 /// [`HashMap`]: ../../std/collections/struct.HashMap.html
 #[stable(since = "1.7.0", feature = "build_hasher")]
+#[const_trait]
 pub trait BuildHasher {
     /// Type of the hasher that will be created.
     #[stable(since = "1.7.0", feature = "build_hasher")]
@@ -698,9 +715,10 @@ pub trait BuildHasher {
     /// );
     /// ```
     #[unstable(feature = "build_hasher_simple_hash_one", issue = "86161")]
-    fn hash_one<T: Hash>(&self, x: T) -> u64
+    fn hash_one<T: ~const Hash + ~const Destruct>(&self, x: T) -> u64
     where
         Self: Sized,
+        Self::Hasher: ~const Hasher + ~const Destruct,
     {
         let mut hasher = self.build_hasher();
         x.hash(&mut hasher);
@@ -764,7 +782,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 }
 
 #[stable(since = "1.7.0", feature = "build_hasher")]
-impl<H: Default + Hasher> BuildHasher for BuildHasherDefault<H> {
+#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
+impl<H: ~const Default + Hasher> const BuildHasher for BuildHasherDefault<H> {
     type Hasher = H;
 
     fn build_hasher(&self) -> H {
@@ -806,14 +825,15 @@ mod impls {
     macro_rules! impl_write {
         ($(($ty:ident, $meth:ident),)*) => {$(
             #[stable(feature = "rust1", since = "1.0.0")]
-            impl Hash for $ty {
+            #[rustc_const_unstable(feature = "const_hash", issue = "104061")]
+            impl const Hash for $ty {
                 #[inline]
-                fn hash<H: Hasher>(&self, state: &mut H) {
+                fn hash<H: ~const Hasher>(&self, state: &mut H) {
                     state.$meth(*self)
                 }
 
                 #[inline]
-                fn hash_slice<H: Hasher>(data: &[$ty], state: &mut H) {
+                fn hash_slice<H: ~const Hasher>(data: &[$ty], state: &mut H) {
                     let newlen = data.len() * mem::size_of::<$ty>();
                     let ptr = data.as_ptr() as *const u8;
                     // SAFETY: `ptr` is valid and aligned, as this macro is only used
@@ -842,33 +862,37 @@ fn hash_slice<H: Hasher>(data: &[$ty], state: &mut H) {
     }
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl Hash for bool {
+    #[rustc_const_unstable(feature = "const_hash", issue = "104061")]
+    impl const Hash for bool {
         #[inline]
-        fn hash<H: Hasher>(&self, state: &mut H) {
+        fn hash<H: ~const Hasher>(&self, state: &mut H) {
             state.write_u8(*self as u8)
         }
     }
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl Hash for char {
+    #[rustc_const_unstable(feature = "const_hash", issue = "104061")]
+    impl const Hash for char {
         #[inline]
-        fn hash<H: Hasher>(&self, state: &mut H) {
+        fn hash<H: ~const Hasher>(&self, state: &mut H) {
             state.write_u32(*self as u32)
         }
     }
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl Hash for str {
+    #[rustc_const_unstable(feature = "const_hash", issue = "104061")]
+    impl const Hash for str {
         #[inline]
-        fn hash<H: Hasher>(&self, state: &mut H) {
+        fn hash<H: ~const Hasher>(&self, state: &mut H) {
             state.write_str(self);
         }
     }
 
     #[stable(feature = "never_hash", since = "1.29.0")]
-    impl Hash for ! {
+    #[rustc_const_unstable(feature = "const_hash", issue = "104061")]
+    impl const Hash for ! {
         #[inline]
-        fn hash<H: Hasher>(&self, _: &mut H) {
+        fn hash<H: ~const Hasher>(&self, _: &mut H) {
             *self
         }
     }
@@ -876,9 +900,10 @@ fn hash<H: Hasher>(&self, _: &mut H) {
     macro_rules! impl_hash_tuple {
         () => (
             #[stable(feature = "rust1", since = "1.0.0")]
-            impl Hash for () {
+            #[rustc_const_unstable(feature = "const_hash", issue = "104061")]
+            impl const Hash for () {
                 #[inline]
-                fn hash<H: Hasher>(&self, _state: &mut H) {}
+                fn hash<H: ~const Hasher>(&self, _state: &mut H) {}
             }
         );
 
@@ -886,10 +911,11 @@ fn hash<H: Hasher>(&self, _state: &mut H) {}
             maybe_tuple_doc! {
                 $($name)+ @
                 #[stable(feature = "rust1", since = "1.0.0")]
-                impl<$($name: Hash),+> Hash for ($($name,)+) where last_type!($($name,)+): ?Sized {
+                #[rustc_const_unstable(feature = "const_hash", issue = "104061")]
+                impl<$($name: ~const Hash),+> const Hash for ($($name,)+) where last_type!($($name,)+): ?Sized {
                     #[allow(non_snake_case)]
                     #[inline]
-                    fn hash<S: Hasher>(&self, state: &mut S) {
+                    fn hash<S: ~const Hasher>(&self, state: &mut S) {
                         let ($(ref $name,)+) = *self;
                         $($name.hash(state);)+
                     }
@@ -932,24 +958,27 @@ macro_rules! last_type {
     impl_hash_tuple! { T B C D E F G H I J K L }
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<T: Hash> Hash for [T] {
+    #[rustc_const_unstable(feature = "const_hash", issue = "104061")]
+    impl<T: ~const Hash> const Hash for [T] {
         #[inline]
-        fn hash<H: Hasher>(&self, state: &mut H) {
+        fn hash<H: ~const Hasher>(&self, state: &mut H) {
             state.write_length_prefix(self.len());
             Hash::hash_slice(self, state)
         }
     }
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<T: ?Sized + Hash> Hash for &T {
+    #[rustc_const_unstable(feature = "const_hash", issue = "104061")]
+    impl<T: ?Sized + ~const Hash> const Hash for &T {
         #[inline]
-        fn hash<H: Hasher>(&self, state: &mut H) {
+        fn hash<H: ~const Hasher>(&self, state: &mut H) {
             (**self).hash(state);
         }
     }
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<T: ?Sized + Hash> Hash for &mut T {
+    #[rustc_const_unstable(feature = "const_hash", issue = "104061")]
+    impl<T: ?Sized + ~const Hash> const Hash for &mut T {
         #[inline]
         fn hash<H: Hasher>(&self, state: &mut H) {
             (**self).hash(state);
index 81bf1dfdf451089e41985e9b578cfc8d87e0f868..7f8287bf56f645d40d4a3f4658641539d55bb765 100644 (file)
@@ -118,7 +118,7 @@ macro_rules! load_int_le {
 /// Safety: this performs unchecked indexing of `buf` at `start..start+len`, so
 /// that must be in-bounds.
 #[inline]
-unsafe fn u8to64_le(buf: &[u8], start: usize, len: usize) -> u64 {
+const unsafe fn u8to64_le(buf: &[u8], start: usize, len: usize) -> u64 {
     debug_assert!(len < 8);
     let mut i = 0; // current byte index (from LSB) in the output u64
     let mut out = 0;
@@ -138,7 +138,8 @@ unsafe fn u8to64_le(buf: &[u8], start: usize, len: usize) -> u64 {
         out |= (unsafe { *buf.get_unchecked(start + i) } as u64) << (i * 8);
         i += 1;
     }
-    debug_assert_eq!(i, len);
+    //FIXME(fee1-dead): use debug_assert_eq
+    debug_assert!(i == len);
     out
 }
 
@@ -150,8 +151,9 @@ impl SipHasher {
         since = "1.13.0",
         note = "use `std::collections::hash_map::DefaultHasher` instead"
     )]
+    #[rustc_const_unstable(feature = "const_hash", issue = "104061")]
     #[must_use]
-    pub fn new() -> SipHasher {
+    pub const fn new() -> SipHasher {
         SipHasher::new_with_keys(0, 0)
     }
 
@@ -162,8 +164,9 @@ pub fn new() -> SipHasher {
         since = "1.13.0",
         note = "use `std::collections::hash_map::DefaultHasher` instead"
     )]
+    #[rustc_const_unstable(feature = "const_hash", issue = "104061")]
     #[must_use]
-    pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher {
+    pub const fn new_with_keys(key0: u64, key1: u64) -> SipHasher {
         SipHasher(SipHasher24 { hasher: Hasher::new_with_keys(key0, key1) })
     }
 }
@@ -176,7 +179,8 @@ impl SipHasher13 {
         since = "1.13.0",
         note = "use `std::collections::hash_map::DefaultHasher` instead"
     )]
-    pub fn new() -> SipHasher13 {
+    #[rustc_const_unstable(feature = "const_hash", issue = "104061")]
+    pub const fn new() -> SipHasher13 {
         SipHasher13::new_with_keys(0, 0)
     }
 
@@ -187,14 +191,15 @@ pub fn new() -> SipHasher13 {
         since = "1.13.0",
         note = "use `std::collections::hash_map::DefaultHasher` instead"
     )]
-    pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher13 {
+    #[rustc_const_unstable(feature = "const_hash", issue = "104061")]
+    pub const fn new_with_keys(key0: u64, key1: u64) -> SipHasher13 {
         SipHasher13 { hasher: Hasher::new_with_keys(key0, key1) }
     }
 }
 
 impl<S: Sip> Hasher<S> {
     #[inline]
-    fn new_with_keys(key0: u64, key1: u64) -> Hasher<S> {
+    const fn new_with_keys(key0: u64, key1: u64) -> Hasher<S> {
         let mut state = Hasher {
             k0: key0,
             k1: key1,
@@ -209,7 +214,7 @@ fn new_with_keys(key0: u64, key1: u64) -> Hasher<S> {
     }
 
     #[inline]
-    fn reset(&mut self) {
+    const fn reset(&mut self) {
         self.length = 0;
         self.state.v0 = self.k0 ^ 0x736f6d6570736575;
         self.state.v1 = self.k1 ^ 0x646f72616e646f6d;
@@ -220,7 +225,8 @@ fn reset(&mut self) {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl super::Hasher for SipHasher {
+#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
+impl const super::Hasher for SipHasher {
     #[inline]
     fn write(&mut self, msg: &[u8]) {
         self.0.hasher.write(msg)
@@ -238,7 +244,8 @@ fn finish(&self) -> u64 {
 }
 
 #[unstable(feature = "hashmap_internals", issue = "none")]
-impl super::Hasher for SipHasher13 {
+#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
+impl const super::Hasher for SipHasher13 {
     #[inline]
     fn write(&mut self, msg: &[u8]) {
         self.hasher.write(msg)
@@ -255,7 +262,7 @@ fn finish(&self) -> u64 {
     }
 }
 
-impl<S: Sip> super::Hasher for Hasher<S> {
+impl<S: ~const Sip> const super::Hasher for Hasher<S> {
     // Note: no integer hashing methods (`write_u*`, `write_i*`) are defined
     // for this type. We could add them, copy the `short_write` implementation
     // in librustc_data_structures/sip128.rs, and add `write_u*`/`write_i*`
@@ -335,7 +342,7 @@ fn finish(&self) -> u64 {
     }
 }
 
-impl<S: Sip> Clone for Hasher<S> {
+impl<S: Sip> const Clone for Hasher<S> {
     #[inline]
     fn clone(&self) -> Hasher<S> {
         Hasher {
@@ -359,6 +366,7 @@ fn default() -> Hasher<S> {
 }
 
 #[doc(hidden)]
+#[const_trait]
 trait Sip {
     fn c_rounds(_: &mut State);
     fn d_rounds(_: &mut State);
@@ -367,7 +375,7 @@ trait Sip {
 #[derive(Debug, Clone, Default)]
 struct Sip13Rounds;
 
-impl Sip for Sip13Rounds {
+impl const Sip for Sip13Rounds {
     #[inline]
     fn c_rounds(state: &mut State) {
         compress!(state);
@@ -384,7 +392,7 @@ fn d_rounds(state: &mut State) {
 #[derive(Debug, Clone, Default)]
 struct Sip24Rounds;
 
-impl Sip for Sip24Rounds {
+impl const Sip for Sip24Rounds {
     #[inline]
     fn c_rounds(state: &mut State) {
         compress!(state);
index 3412d3730d01175de0d2febcaa1d6615f4a05ff2..c53175ba4f3f0f7bb23c701eda24d79abfae5926 100644 (file)
@@ -220,7 +220,7 @@ pub fn spin_loop() {
 ///
 /// [`std::convert::identity`]: crate::convert::identity
 #[inline]
-#[stable(feature = "bench_black_box", since = "CURRENT_RUSTC_VERSION")]
+#[stable(feature = "bench_black_box", since = "1.66.0")]
 #[rustc_const_unstable(feature = "const_black_box", issue = "none")]
 pub const fn black_box<T>(dummy: T) -> T {
     crate::intrinsics::black_box(dummy)
index bfbd4301230ae144b19fb2bbfdcdaa562f559561..819ccf5a3e9e70ed7a63165fcffbb70cb67acc3b 100644 (file)
@@ -59,6 +59,9 @@
 use crate::marker::Tuple;
 use crate::mem;
 
+#[cfg(not(bootstrap))]
+pub mod mir;
+
 // These imports are used for simplifying intra-doc links
 #[allow(unused_imports)]
 #[cfg(all(target_has_atomic = "8", target_has_atomic = "32", target_has_atomic = "ptr"))]
@@ -790,7 +793,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     /// uninitialized at that point in the control flow.
     ///
     /// This intrinsic should not be used outside of the compiler.
-    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
+    #[rustc_safe_intrinsic]
     pub fn rustc_peek<T>(_: T) -> T;
 
     /// Aborts the execution of the process.
@@ -808,7 +811,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     /// On Unix, the
     /// process will probably terminate with a signal like `SIGABRT`, `SIGILL`, `SIGTRAP`, `SIGSEGV` or
     /// `SIGBUS`.  The precise behaviour is not guaranteed and not stable.
-    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
+    #[rustc_safe_intrinsic]
     pub fn abort() -> !;
 
     /// Informs the optimizer that this point in the code is not reachable,
@@ -847,7 +850,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     ///
     /// This intrinsic does not have a stable counterpart.
     #[rustc_const_unstable(feature = "const_likely", issue = "none")]
-    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
+    #[rustc_safe_intrinsic]
     pub fn likely(b: bool) -> bool;
 
     /// Hints to the compiler that branch condition is likely to be false.
@@ -862,7 +865,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     ///
     /// This intrinsic does not have a stable counterpart.
     #[rustc_const_unstable(feature = "const_likely", issue = "none")]
-    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
+    #[rustc_safe_intrinsic]
     pub fn unlikely(b: bool) -> bool;
 
     /// Executes a breakpoint trap, for inspection by a debugger.
@@ -882,7 +885,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     ///
     /// The stabilized version of this intrinsic is [`core::mem::size_of`].
     #[rustc_const_stable(feature = "const_size_of", since = "1.40.0")]
-    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
+    #[rustc_safe_intrinsic]
     pub fn size_of<T>() -> usize;
 
     /// The minimum alignment of a type.
@@ -894,7 +897,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     ///
     /// The stabilized version of this intrinsic is [`core::mem::align_of`].
     #[rustc_const_stable(feature = "const_min_align_of", since = "1.40.0")]
-    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
+    #[rustc_safe_intrinsic]
     pub fn min_align_of<T>() -> usize;
     /// The preferred alignment of a type.
     ///
@@ -923,7 +926,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     ///
     /// The stabilized version of this intrinsic is [`core::any::type_name`].
     #[rustc_const_unstable(feature = "const_type_name", issue = "63084")]
-    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
+    #[rustc_safe_intrinsic]
     pub fn type_name<T: ?Sized>() -> &'static str;
 
     /// Gets an identifier which is globally unique to the specified type. This
@@ -937,7 +940,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     ///
     /// The stabilized version of this intrinsic is [`core::any::TypeId::of`].
     #[rustc_const_unstable(feature = "const_type_id", issue = "77125")]
-    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
+    #[rustc_safe_intrinsic]
     pub fn type_id<T: ?Sized + 'static>() -> u64;
 
     /// A guard for unsafe functions that cannot ever be executed if `T` is uninhabited:
@@ -945,7 +948,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     ///
     /// This intrinsic does not have a stable counterpart.
     #[rustc_const_stable(feature = "const_assert_type", since = "1.59.0")]
-    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
+    #[rustc_safe_intrinsic]
     pub fn assert_inhabited<T>();
 
     /// A guard for unsafe functions that cannot ever be executed if `T` does not permit
@@ -953,7 +956,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     ///
     /// This intrinsic does not have a stable counterpart.
     #[rustc_const_unstable(feature = "const_assert_type2", issue = "none")]
-    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
+    #[rustc_safe_intrinsic]
     pub fn assert_zero_valid<T>();
 
     /// A guard for unsafe functions that cannot ever be executed if `T` has invalid
@@ -961,7 +964,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     ///
     /// This intrinsic does not have a stable counterpart.
     #[rustc_const_unstable(feature = "const_assert_type2", issue = "none")]
-    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
+    #[rustc_safe_intrinsic]
     pub fn assert_uninit_valid<T>();
 
     /// Gets a reference to a static `Location` indicating where it was called.
@@ -973,7 +976,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     ///
     /// Consider using [`core::panic::Location::caller`] instead.
     #[rustc_const_unstable(feature = "const_caller_location", issue = "76156")]
-    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
+    #[rustc_safe_intrinsic]
     pub fn caller_location() -> &'static crate::panic::Location<'static>;
 
     /// Moves a value out of scope without running drop glue.
@@ -986,7 +989,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     /// Therefore, implementations must not require the user to uphold
     /// any safety invariants.
     #[rustc_const_unstable(feature = "const_intrinsic_forget", issue = "none")]
-    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
+    #[rustc_safe_intrinsic]
     pub fn forget<T: ?Sized>(_: T);
 
     /// Reinterprets the bits of a value of one type as another type.
@@ -1266,7 +1269,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     ///
     /// The stabilized version of this intrinsic is [`mem::needs_drop`](crate::mem::needs_drop).
     #[rustc_const_stable(feature = "const_needs_drop", since = "1.40.0")]
-    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
+    #[rustc_safe_intrinsic]
     pub fn needs_drop<T: ?Sized>() -> bool;
 
     /// Calculates the offset from a pointer.
@@ -1311,7 +1314,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     /// any safety invariants.
     ///
     /// Consider using [`pointer::mask`] instead.
-    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
+    #[rustc_safe_intrinsic]
     pub fn ptr_mask<T>(ptr: *const T, mask: usize) -> *const T;
 
     /// Equivalent to the appropriate `llvm.memcpy.p0i8.0i8.*` intrinsic, with
@@ -1503,7 +1506,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     ///
     /// The stabilized version of this intrinsic is
     /// [`f32::min`]
-    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
+    #[rustc_safe_intrinsic]
     pub fn minnumf32(x: f32, y: f32) -> f32;
     /// Returns the minimum of two `f64` values.
     ///
@@ -1514,7 +1517,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     ///
     /// The stabilized version of this intrinsic is
     /// [`f64::min`]
-    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
+    #[rustc_safe_intrinsic]
     pub fn minnumf64(x: f64, y: f64) -> f64;
     /// Returns the maximum of two `f32` values.
     ///
@@ -1525,7 +1528,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     ///
     /// The stabilized version of this intrinsic is
     /// [`f32::max`]
-    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
+    #[rustc_safe_intrinsic]
     pub fn maxnumf32(x: f32, y: f32) -> f32;
     /// Returns the maximum of two `f64` values.
     ///
@@ -1536,7 +1539,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     ///
     /// The stabilized version of this intrinsic is
     /// [`f64::max`]
-    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
+    #[rustc_safe_intrinsic]
     pub fn maxnumf64(x: f64, y: f64) -> f64;
 
     /// Copies the sign from `y` to `x` for `f32` values.
@@ -1657,7 +1660,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     /// primitives via the `count_ones` method. For example,
     /// [`u32::count_ones`]
     #[rustc_const_stable(feature = "const_ctpop", since = "1.40.0")]
-    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
+    #[rustc_safe_intrinsic]
     pub fn ctpop<T: Copy>(x: T) -> T;
 
     /// Returns the number of leading unset bits (zeroes) in an integer type `T`.
@@ -1695,7 +1698,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     /// assert_eq!(num_leading, 16);
     /// ```
     #[rustc_const_stable(feature = "const_ctlz", since = "1.40.0")]
-    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
+    #[rustc_safe_intrinsic]
     pub fn ctlz<T: Copy>(x: T) -> T;
 
     /// Like `ctlz`, but extra-unsafe as it returns `undef` when
@@ -1752,7 +1755,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     /// assert_eq!(num_trailing, 16);
     /// ```
     #[rustc_const_stable(feature = "const_cttz", since = "1.40.0")]
-    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
+    #[rustc_safe_intrinsic]
     pub fn cttz<T: Copy>(x: T) -> T;
 
     /// Like `cttz`, but extra-unsafe as it returns `undef` when
@@ -1785,7 +1788,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     /// primitives via the `swap_bytes` method. For example,
     /// [`u32::swap_bytes`]
     #[rustc_const_stable(feature = "const_bswap", since = "1.40.0")]
-    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
+    #[rustc_safe_intrinsic]
     pub fn bswap<T: Copy>(x: T) -> T;
 
     /// Reverses the bits in an integer type `T`.
@@ -1799,7 +1802,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     /// primitives via the `reverse_bits` method. For example,
     /// [`u32::reverse_bits`]
     #[rustc_const_stable(feature = "const_bitreverse", since = "1.40.0")]
-    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
+    #[rustc_safe_intrinsic]
     pub fn bitreverse<T: Copy>(x: T) -> T;
 
     /// Performs checked integer addition.
@@ -1813,7 +1816,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     /// primitives via the `overflowing_add` method. For example,
     /// [`u32::overflowing_add`]
     #[rustc_const_stable(feature = "const_int_overflow", since = "1.40.0")]
-    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
+    #[rustc_safe_intrinsic]
     pub fn add_with_overflow<T: Copy>(x: T, y: T) -> (T, bool);
 
     /// Performs checked integer subtraction
@@ -1827,7 +1830,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     /// primitives via the `overflowing_sub` method. For example,
     /// [`u32::overflowing_sub`]
     #[rustc_const_stable(feature = "const_int_overflow", since = "1.40.0")]
-    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
+    #[rustc_safe_intrinsic]
     pub fn sub_with_overflow<T: Copy>(x: T, y: T) -> (T, bool);
 
     /// Performs checked integer multiplication
@@ -1841,7 +1844,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     /// primitives via the `overflowing_mul` method. For example,
     /// [`u32::overflowing_mul`]
     #[rustc_const_stable(feature = "const_int_overflow", since = "1.40.0")]
-    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
+    #[rustc_safe_intrinsic]
     pub fn mul_with_overflow<T: Copy>(x: T, y: T) -> (T, bool);
 
     /// Performs an exact division, resulting in undefined behavior where
@@ -1916,7 +1919,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     /// primitives via the `rotate_left` method. For example,
     /// [`u32::rotate_left`]
     #[rustc_const_stable(feature = "const_int_rotate", since = "1.40.0")]
-    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
+    #[rustc_safe_intrinsic]
     pub fn rotate_left<T: Copy>(x: T, y: T) -> T;
 
     /// Performs rotate right.
@@ -1930,7 +1933,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     /// primitives via the `rotate_right` method. For example,
     /// [`u32::rotate_right`]
     #[rustc_const_stable(feature = "const_int_rotate", since = "1.40.0")]
-    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
+    #[rustc_safe_intrinsic]
     pub fn rotate_right<T: Copy>(x: T, y: T) -> T;
 
     /// Returns (a + b) mod 2<sup>N</sup>, where N is the width of T in bits.
@@ -1944,7 +1947,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     /// primitives via the `wrapping_add` method. For example,
     /// [`u32::wrapping_add`]
     #[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")]
-    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
+    #[rustc_safe_intrinsic]
     pub fn wrapping_add<T: Copy>(a: T, b: T) -> T;
     /// Returns (a - b) mod 2<sup>N</sup>, where N is the width of T in bits.
     ///
@@ -1957,7 +1960,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     /// primitives via the `wrapping_sub` method. For example,
     /// [`u32::wrapping_sub`]
     #[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")]
-    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
+    #[rustc_safe_intrinsic]
     pub fn wrapping_sub<T: Copy>(a: T, b: T) -> T;
     /// Returns (a * b) mod 2<sup>N</sup>, where N is the width of T in bits.
     ///
@@ -1970,7 +1973,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     /// primitives via the `wrapping_mul` method. For example,
     /// [`u32::wrapping_mul`]
     #[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")]
-    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
+    #[rustc_safe_intrinsic]
     pub fn wrapping_mul<T: Copy>(a: T, b: T) -> T;
 
     /// Computes `a + b`, saturating at numeric bounds.
@@ -1984,7 +1987,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     /// primitives via the `saturating_add` method. For example,
     /// [`u32::saturating_add`]
     #[rustc_const_stable(feature = "const_int_saturating", since = "1.40.0")]
-    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
+    #[rustc_safe_intrinsic]
     pub fn saturating_add<T: Copy>(a: T, b: T) -> T;
     /// Computes `a - b`, saturating at numeric bounds.
     ///
@@ -1997,7 +2000,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     /// primitives via the `saturating_sub` method. For example,
     /// [`u32::saturating_sub`]
     #[rustc_const_stable(feature = "const_int_saturating", since = "1.40.0")]
-    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
+    #[rustc_safe_intrinsic]
     pub fn saturating_sub<T: Copy>(a: T, b: T) -> T;
 
     /// Returns the value of the discriminant for the variant in 'v';
@@ -2010,7 +2013,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     ///
     /// The stabilized version of this intrinsic is [`core::mem::discriminant`].
     #[rustc_const_unstable(feature = "const_discriminant", issue = "69821")]
-    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
+    #[rustc_safe_intrinsic]
     pub fn discriminant_value<T>(v: &T) -> <T as DiscriminantKind>::Discriminant;
 
     /// Returns the number of variants of the type `T` cast to a `usize`;
@@ -2023,7 +2026,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     ///
     /// The to-be-stabilized version of this intrinsic is [`mem::variant_count`].
     #[rustc_const_unstable(feature = "variant_count", issue = "73662")]
-    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
+    #[rustc_safe_intrinsic]
     pub fn variant_count<T>() -> usize;
 
     /// Rust's "try catch" construct which invokes the function pointer `try_fn`
@@ -2057,7 +2060,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     /// Therefore, implementations must not require the user to uphold
     /// any safety invariants.
     #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
-    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
+    #[rustc_safe_intrinsic]
     pub fn ptr_guaranteed_cmp<T>(ptr: *const T, other: *const T) -> u8;
 
     /// Allocates a block of memory at compile time.
@@ -2108,7 +2111,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     ///
     /// [`std::hint::black_box`]: crate::hint::black_box
     #[rustc_const_unstable(feature = "const_black_box", issue = "none")]
-    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
+    #[rustc_safe_intrinsic]
     pub fn black_box<T>(dummy: T) -> T;
 
     /// `ptr` must point to a vtable.
diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs
new file mode 100644 (file)
index 0000000..1bacdc3
--- /dev/null
@@ -0,0 +1,123 @@
+//! Rustc internal tooling for hand-writing MIR.
+//!
+//! If for some reasons you are not writing rustc tests and have found yourself considering using
+//! this feature, turn back. This is *exceptionally* unstable. There is no attempt at all to make
+//! anything work besides those things which the rustc test suite happened to need. If you make a
+//! typo you'll probably ICE. Really, this is not the solution to your problems. Consider instead
+//! supporting the [stable MIR project group](https://github.com/rust-lang/project-stable-mir).
+//!
+//! The documentation for this module describes how to use this feature. If you are interested in
+//! hacking on the implementation, most of that documentation lives at
+//! `rustc_mir_building/src/build/custom/mod.rs`.
+//!
+//! Typical usage will look like this:
+//!
+//! ```rust
+//! #![feature(core_intrinsics, custom_mir)]
+//!
+//! extern crate core;
+//! use core::intrinsics::mir::*;
+//!
+//! #[custom_mir(dialect = "built")]
+//! pub fn simple(x: i32) -> i32 {
+//!     mir!(
+//!         let temp1: i32;
+//!         let temp2: _;
+//!
+//!         {
+//!             temp1 = x;
+//!             Goto(exit)
+//!         }
+//!
+//!         exit = {
+//!             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 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.
+//!
+//! 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.
+//!
+
+#![unstable(
+    feature = "custom_mir",
+    reason = "MIR is an implementation detail and extremely unstable",
+    issue = "none"
+)]
+#![allow(unused_variables, non_snake_case, missing_debug_implementations)]
+
+/// Type representing basic blocks.
+///
+/// All terminators will have this type as a return type. It helps achieve some type safety.
+pub struct BasicBlock;
+
+macro_rules! define {
+    ($name:literal, $($sig:tt)*) => {
+        #[rustc_diagnostic_item = $name]
+        pub $($sig)* { panic!() }
+    }
+}
+
+define!("mir_return", fn Return() -> BasicBlock);
+define!("mir_goto", fn Goto(destination: BasicBlock) -> BasicBlock);
+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);
+
+/// Convenience 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.
+#[rustc_macro_transparency = "transparent"]
+pub macro mir {
+    (
+        $(let $local_decl:ident $(: $local_decl_ty:ty)? ;)*
+
+        $entry_block:block
+
+        $(
+            $block_name:ident = $block:block
+        )*
+    ) => {{
+        // First, we declare all basic blocks.
+        $(
+            let $block_name: ::core::intrinsics::mir::BasicBlock;
+        )*
+
+        {
+            // Now all locals
+            #[allow(non_snake_case)]
+            let RET;
+            $(
+                let $local_decl $(: $local_decl_ty)? ;
+            )*
+
+            {
+                // Finally, the contents of the basic blocks
+                $entry_block;
+                $(
+                    $block;
+                )*
+
+                RET
+            }
+        }
+    }}
+}
index d4fb886101fe78aff33812627e5c10748edeb4b3..5e4211058aa6f2b8bcd0182ef18fc340f54c771d 100644 (file)
@@ -1,6 +1,8 @@
 use crate::array;
-use crate::iter::{ByRefSized, FusedIterator, Iterator};
-use crate::ops::{ControlFlow, Try};
+use crate::const_closure::ConstFnMutClosure;
+use crate::iter::{ByRefSized, FusedIterator, Iterator, TrustedRandomAccessNoCoerce};
+use crate::mem::{self, MaybeUninit};
+use crate::ops::{ControlFlow, NeverShortCircuit, Try};
 
 /// An iterator over `N` elements of the iterator at a time.
 ///
@@ -82,7 +84,13 @@ fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
         }
     }
 
-    impl_fold_via_try_fold! { fold -> try_fold }
+    fn fold<B, F>(self, init: B, f: F) -> B
+    where
+        Self: Sized,
+        F: FnMut(B, Self::Item) -> B,
+    {
+        <Self as SpecFold>::fold(self, init, f)
+    }
 }
 
 #[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
@@ -168,3 +176,64 @@ fn is_empty(&self) -> bool {
         self.iter.len() < N
     }
 }
+
+trait SpecFold: Iterator {
+    fn fold<B, F>(self, init: B, f: F) -> B
+    where
+        Self: Sized,
+        F: FnMut(B, Self::Item) -> B;
+}
+
+impl<I, const N: usize> SpecFold for ArrayChunks<I, N>
+where
+    I: Iterator,
+{
+    #[inline]
+    default fn fold<B, F>(mut self, init: B, mut f: F) -> B
+    where
+        Self: Sized,
+        F: FnMut(B, Self::Item) -> B,
+    {
+        let fold = ConstFnMutClosure::new(&mut f, NeverShortCircuit::wrap_mut_2_imp);
+        self.try_fold(init, fold).0
+    }
+}
+
+impl<I, const N: usize> SpecFold for ArrayChunks<I, N>
+where
+    I: Iterator + TrustedRandomAccessNoCoerce,
+{
+    #[inline]
+    fn fold<B, F>(mut self, init: B, mut f: F) -> B
+    where
+        Self: Sized,
+        F: FnMut(B, Self::Item) -> B,
+    {
+        let mut accum = init;
+        let inner_len = self.iter.size();
+        let mut i = 0;
+        // Use a while loop because (0..len).step_by(N) doesn't optimize well.
+        while inner_len - i >= N {
+            let mut chunk = MaybeUninit::uninit_array();
+            let mut guard = array::Guard { array_mut: &mut chunk, initialized: 0 };
+            while guard.initialized < N {
+                // SAFETY: The method consumes the iterator and the loop condition ensures that
+                // all accesses are in bounds and only happen once.
+                unsafe {
+                    let idx = i + guard.initialized;
+                    guard.push_unchecked(self.iter.__iterator_get_unchecked(idx));
+                }
+            }
+            mem::forget(guard);
+            // SAFETY: The loop above initialized all elements
+            let chunk = unsafe { MaybeUninit::array_assume_init(chunk) };
+            accum = f(accum, chunk);
+            i += N;
+        }
+
+        // unlike try_fold this method does not need to take care of the remainder
+        // since `self` will be dropped
+
+        accum
+    }
+}
index 659409557c9107213485fdb1acc1575d1b0ad9d8..8425354837841608c002775d7651bd4d3f72443f 100644 (file)
 #![feature(const_float_bits_conv)]
 #![feature(const_float_classify)]
 #![feature(const_fmt_arguments_new)]
+#![feature(const_hash)]
 #![feature(const_heap)]
 #![feature(const_convert)]
 #![feature(const_index_range_slice_index)]
 #![feature(const_refs_to_cell)]
 #![feature(decl_macro)]
 #![feature(deprecated_suggestion)]
+#![cfg_attr(not(bootstrap), feature(derive_const))]
 #![feature(doc_cfg)]
 #![feature(doc_notable_trait)]
 #![feature(rustdoc_internals)]
index 2850d84acc3274b09f9169dc6c1b377ddd516730..32bdc26bc51adad308ff88f7fbbcde931af04230 100644 (file)
@@ -1464,6 +1464,19 @@ macro_rules! trace_macros {
         /* compiler built-in */
     }
 
+    /// Attribute macro used to apply derive macros for implementing traits
+    /// in a const context.
+    ///
+    /// See [the reference] for more info.
+    ///
+    /// [the reference]: ../../../reference/attributes/derive.html
+    #[unstable(feature = "derive_const", issue = "none")]
+    #[rustc_builtin_macro]
+    #[cfg(not(bootstrap))]
+    pub macro derive_const($item:item) {
+        /* compiler built-in */
+    }
+
     /// Attribute macro applied to a function to turn it into a unit test.
     ///
     /// See [the reference] for more info.
index 2e1a667097c015432277219bcb081d8050052ce2..956a69eda8a57af9038d125b0ded989c79adb75b 100644 (file)
 #[stable(feature = "maybe_uninit", since = "1.36.0")]
 pub use maybe_uninit::MaybeUninit;
 
-// FIXME: This is left here for now to avoid complications around pending reverts.
-// Once <https://github.com/rust-lang/rust/issues/101899> is fully resolved,
-// this should be removed and the references in `alloc::Layout` updated.
-pub(crate) use ptr::Alignment as ValidAlign;
-
 mod transmutability;
 #[unstable(feature = "transmutability", issue = "99571")]
 pub use transmutability::{Assume, BikeshedIntrinsicFrom};
index 81f050cb283d47bc94879ea2e77d0cf912988355..e64eb1cf7aed8d5d47b9c327befbf0c9bbb1d817 100644 (file)
@@ -107,6 +107,9 @@ pub const fn count_zeros(self) -> u32 {
 
         /// Returns the number of leading zeros in the binary representation of `self`.
         ///
+        /// Depending on what you're doing with the value, you might also be interested in the
+        /// [`ilog2`] function which returns a consistent number, even if the type widens.
+        ///
         /// # Examples
         ///
         /// Basic usage:
@@ -116,6 +119,7 @@ pub const fn count_zeros(self) -> u32 {
         ///
         /// assert_eq!(n.leading_zeros(), 0);
         /// ```
+        #[doc = concat!("[`ilog2`]: ", stringify!($SelfT), "::ilog2")]
         #[stable(feature = "rust1", since = "1.0.0")]
         #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
         #[must_use = "this returns the result of the operation, \
@@ -467,8 +471,8 @@ pub const fn checked_add(self, rhs: Self) -> Option<Self> {
         #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_add_unsigned(2), Some(3));")]
         #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add_unsigned(3), None);")]
         /// ```
-        #[stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
-        #[rustc_const_stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
+        #[stable(feature = "mixed_integer_ops", since = "1.66.0")]
+        #[rustc_const_stable(feature = "mixed_integer_ops", since = "1.66.0")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -535,8 +539,8 @@ pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
         #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_sub_unsigned(2), Some(-1));")]
         #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 2).checked_sub_unsigned(3), None);")]
         /// ```
-        #[stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
-        #[rustc_const_stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
+        #[stable(feature = "mixed_integer_ops", since = "1.66.0")]
+        #[rustc_const_stable(feature = "mixed_integer_ops", since = "1.66.0")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -905,8 +909,8 @@ pub const fn saturating_add(self, rhs: Self) -> Self {
         #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".saturating_add_unsigned(2), 3);")]
         #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.saturating_add_unsigned(100), ", stringify!($SelfT), "::MAX);")]
         /// ```
-        #[stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
-        #[rustc_const_stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
+        #[stable(feature = "mixed_integer_ops", since = "1.66.0")]
+        #[rustc_const_stable(feature = "mixed_integer_ops", since = "1.66.0")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -951,8 +955,8 @@ pub const fn saturating_sub(self, rhs: Self) -> Self {
         #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".saturating_sub_unsigned(127), -27);")]
         #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.saturating_sub_unsigned(100), ", stringify!($SelfT), "::MIN);")]
         /// ```
-        #[stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
-        #[rustc_const_stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
+        #[stable(feature = "mixed_integer_ops", since = "1.66.0")]
+        #[rustc_const_stable(feature = "mixed_integer_ops", since = "1.66.0")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -1129,8 +1133,8 @@ pub const fn wrapping_add(self, rhs: Self) -> Self {
         #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_add_unsigned(27), 127);")]
         #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.wrapping_add_unsigned(2), ", stringify!($SelfT), "::MIN + 1);")]
         /// ```
-        #[stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
-        #[rustc_const_stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
+        #[stable(feature = "mixed_integer_ops", since = "1.66.0")]
+        #[rustc_const_stable(feature = "mixed_integer_ops", since = "1.66.0")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline(always)]
@@ -1169,8 +1173,8 @@ pub const fn wrapping_sub(self, rhs: Self) -> Self {
         #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".wrapping_sub_unsigned(127), -127);")]
         #[doc = concat!("assert_eq!((-2", stringify!($SelfT), ").wrapping_sub_unsigned(", stringify!($UnsignedT), "::MAX), -1);")]
         /// ```
-        #[stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
-        #[rustc_const_stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
+        #[stable(feature = "mixed_integer_ops", since = "1.66.0")]
+        #[rustc_const_stable(feature = "mixed_integer_ops", since = "1.66.0")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline(always)]
@@ -1566,8 +1570,8 @@ pub const fn carrying_add(self, rhs: Self, carry: bool) -> (Self, bool) {
         #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN).overflowing_add_unsigned(", stringify!($UnsignedT), "::MAX), (", stringify!($SelfT), "::MAX, false));")]
         #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).overflowing_add_unsigned(3), (", stringify!($SelfT), "::MIN, true));")]
         /// ```
-        #[stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
-        #[rustc_const_stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
+        #[stable(feature = "mixed_integer_ops", since = "1.66.0")]
+        #[rustc_const_stable(feature = "mixed_integer_ops", since = "1.66.0")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -1648,8 +1652,8 @@ pub const fn borrowing_sub(self, rhs: Self, borrow: bool) -> (Self, bool) {
         #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX).overflowing_sub_unsigned(", stringify!($UnsignedT), "::MAX), (", stringify!($SelfT), "::MIN, false));")]
         #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 2).overflowing_sub_unsigned(3), (", stringify!($SelfT), "::MAX, true));")]
         /// ```
-        #[stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
-        #[rustc_const_stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
+        #[stable(feature = "mixed_integer_ops", since = "1.66.0")]
+        #[rustc_const_stable(feature = "mixed_integer_ops", since = "1.66.0")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -2068,11 +2072,15 @@ pub const fn div_euclid(self, rhs: Self) -> Self {
         pub const fn rem_euclid(self, rhs: Self) -> Self {
             let r = self % rhs;
             if r < 0 {
-                if rhs < 0 {
-                    r - rhs
-                } else {
-                    r + rhs
-                }
+                // Semantically equivalent to `if rhs < 0 { r - rhs } else { r + rhs }`.
+                // If `rhs` is not `Self::MIN`, then `r + abs(rhs)` will not overflow
+                // and is clearly equivalent, because `r` is negative.
+                // Otherwise, `rhs` is `Self::MIN`, then we have
+                // `r.wrapping_add(Self::MIN.wrapping_abs())`, which evaluates
+                // to `r.wrapping_add(Self::MIN)`, which is equivalent to
+                // `r - Self::MIN`, which is what we wanted (and will not overflow
+                // for negative `r`).
+                r.wrapping_add(rhs.wrapping_abs())
             } else {
                 r
             }
@@ -2271,15 +2279,16 @@ pub const fn checked_next_multiple_of(self, rhs: Self) -> Option<Self> {
         /// # Panics
         ///
         /// This function will panic if `self` is less than or equal to zero,
-        /// or if `base` is less then 2.
+        /// or if `base` is less than 2.
         ///
         /// # Examples
         ///
         /// ```
-        /// #![feature(int_log)]
         #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".ilog(5), 1);")]
         /// ```
-        #[unstable(feature = "int_log", issue = "70887")]
+        #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_allow_const_fn_unstable(const_option)]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -2298,10 +2307,11 @@ pub const fn ilog(self, base: Self) -> u32 {
         /// # Examples
         ///
         /// ```
-        /// #![feature(int_log)]
         #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".ilog2(), 1);")]
         /// ```
-        #[unstable(feature = "int_log", issue = "70887")]
+        #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_allow_const_fn_unstable(const_option)]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -2319,10 +2329,11 @@ pub const fn ilog2(self) -> u32 {
         /// # Example
         ///
         /// ```
-        /// #![feature(int_log)]
         #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".ilog10(), 1);")]
         /// ```
-        #[unstable(feature = "int_log", issue = "70887")]
+        #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_allow_const_fn_unstable(const_option)]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -2343,10 +2354,10 @@ pub const fn ilog10(self) -> u32 {
         /// # Examples
         ///
         /// ```
-        /// #![feature(int_log)]
         #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_ilog(5), Some(1));")]
         /// ```
-        #[unstable(feature = "int_log", issue = "70887")]
+        #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -2379,10 +2390,10 @@ pub const fn checked_ilog(self, base: Self) -> Option<u32> {
         /// # Examples
         ///
         /// ```
-        /// #![feature(int_log)]
         #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_ilog2(), Some(1));")]
         /// ```
-        #[unstable(feature = "int_log", issue = "70887")]
+        #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -2403,10 +2414,10 @@ pub const fn checked_ilog2(self) -> Option<u32> {
         /// # Example
         ///
         /// ```
-        /// #![feature(int_log)]
         #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_ilog10(), Some(1));")]
         /// ```
-        #[unstable(feature = "int_log", issue = "70887")]
+        #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
index 6b6f3417f8ad5788ab7aebce12024111ed6665af..5b7521220acdb2d99ac15aeac715d45c7d4cde1b 100644 (file)
@@ -460,14 +460,14 @@ pub const fn checked_next_power_of_two(self) -> Option<$Ty> {
                 /// # Examples
                 ///
                 /// ```
-                /// #![feature(int_log)]
                 #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
                 ///
                 #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(7).unwrap().ilog2(), 2);")]
                 #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(8).unwrap().ilog2(), 3);")]
                 #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(9).unwrap().ilog2(), 3);")]
                 /// ```
-                #[unstable(feature = "int_log", issue = "70887")]
+                #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+                #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
                 #[must_use = "this returns the result of the operation, \
                               without modifying the original"]
                 #[inline]
@@ -485,14 +485,14 @@ pub const fn ilog2(self) -> u32 {
                 /// # Examples
                 ///
                 /// ```
-                /// #![feature(int_log)]
                 #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
                 ///
                 #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(99).unwrap().ilog10(), 1);")]
                 #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(100).unwrap().ilog10(), 2);")]
                 #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(101).unwrap().ilog10(), 2);")]
                 /// ```
-                #[unstable(feature = "int_log", issue = "70887")]
+                #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+                #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
                 #[must_use = "this returns the result of the operation, \
                               without modifying the original"]
                 #[inline]
index 93f65c5c7aaf3a6111abe21c9bfcf3ceee415b62..741d7ec6f592d159e1e4ac6cf60cda9c39da4716 100644 (file)
@@ -109,6 +109,9 @@ pub const fn count_zeros(self) -> u32 {
 
         /// Returns the number of leading zeros in the binary representation of `self`.
         ///
+        /// Depending on what you're doing with the value, you might also be interested in the
+        /// [`ilog2`] function which returns a consistent number, even if the type widens.
+        ///
         /// # Examples
         ///
         /// Basic usage:
@@ -118,6 +121,7 @@ pub const fn count_zeros(self) -> u32 {
         ///
         /// assert_eq!(n.leading_zeros(), 2);
         /// ```
+        #[doc = concat!("[`ilog2`]: ", stringify!($SelfT), "::ilog2")]
         #[stable(feature = "rust1", since = "1.0.0")]
         #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
         #[must_use = "this returns the result of the operation, \
@@ -478,8 +482,8 @@ pub const fn checked_add(self, rhs: Self) -> Option<Self> {
         #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_add_signed(-2), None);")]
         #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add_signed(3), None);")]
         /// ```
-        #[stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
-        #[rustc_const_stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
+        #[stable(feature = "mixed_integer_ops", since = "1.66.0")]
+        #[rustc_const_stable(feature = "mixed_integer_ops", since = "1.66.0")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -692,15 +696,16 @@ pub const fn checked_rem_euclid(self, rhs: Self) -> Option<Self> {
         ///
         /// # Panics
         ///
-        /// This function will panic if `self` is zero, or if `base` is less then 2.
+        /// This function will panic if `self` is zero, or if `base` is less than 2.
         ///
         /// # Examples
         ///
         /// ```
-        /// #![feature(int_log)]
         #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".ilog(5), 1);")]
         /// ```
-        #[unstable(feature = "int_log", issue = "70887")]
+        #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_allow_const_fn_unstable(const_option)]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -719,10 +724,11 @@ pub const fn ilog(self, base: Self) -> u32 {
         /// # Examples
         ///
         /// ```
-        /// #![feature(int_log)]
         #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".ilog2(), 1);")]
         /// ```
-        #[unstable(feature = "int_log", issue = "70887")]
+        #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_allow_const_fn_unstable(const_option)]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -740,10 +746,11 @@ pub const fn ilog2(self) -> u32 {
         /// # Example
         ///
         /// ```
-        /// #![feature(int_log)]
         #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".ilog10(), 1);")]
         /// ```
-        #[unstable(feature = "int_log", issue = "70887")]
+        #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_allow_const_fn_unstable(const_option)]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -764,10 +771,10 @@ pub const fn ilog10(self) -> u32 {
         /// # Examples
         ///
         /// ```
-        /// #![feature(int_log)]
         #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_ilog(5), Some(1));")]
         /// ```
-        #[unstable(feature = "int_log", issue = "70887")]
+        #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -800,10 +807,10 @@ pub const fn checked_ilog(self, base: Self) -> Option<u32> {
         /// # Examples
         ///
         /// ```
-        /// #![feature(int_log)]
         #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_ilog2(), Some(1));")]
         /// ```
-        #[unstable(feature = "int_log", issue = "70887")]
+        #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -822,10 +829,10 @@ pub const fn checked_ilog2(self) -> Option<u32> {
         /// # Examples
         ///
         /// ```
-        /// #![feature(int_log)]
         #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_ilog10(), Some(1));")]
         /// ```
-        #[unstable(feature = "int_log", issue = "70887")]
+        #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -1025,8 +1032,8 @@ pub const fn saturating_add(self, rhs: Self) -> Self {
         #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".saturating_add_signed(-2), 0);")]
         #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).saturating_add_signed(4), ", stringify!($SelfT), "::MAX);")]
         /// ```
-        #[stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
-        #[rustc_const_stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
+        #[stable(feature = "mixed_integer_ops", since = "1.66.0")]
+        #[rustc_const_stable(feature = "mixed_integer_ops", since = "1.66.0")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -1165,8 +1172,8 @@ pub const fn wrapping_add(self, rhs: Self) -> Self {
         #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".wrapping_add_signed(-2), ", stringify!($SelfT), "::MAX);")]
         #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).wrapping_add_signed(4), 1);")]
         /// ```
-        #[stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
-        #[rustc_const_stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
+        #[stable(feature = "mixed_integer_ops", since = "1.66.0")]
+        #[rustc_const_stable(feature = "mixed_integer_ops", since = "1.66.0")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -1534,8 +1541,8 @@ pub const fn carrying_add(self, rhs: Self, carry: bool) -> (Self, bool) {
         #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_add_signed(-2), (", stringify!($SelfT), "::MAX, true));")]
         #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).overflowing_add_signed(4), (1, true));")]
         /// ```
-        #[stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
-        #[rustc_const_stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
+        #[stable(feature = "mixed_integer_ops", since = "1.66.0")]
+        #[rustc_const_stable(feature = "mixed_integer_ops", since = "1.66.0")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
index 4f4c99c4ad97c829251f2f9c26fbffe051680a8a..c67867f4436e4a46374987c4b730a7dc1520cac7 100644 (file)
@@ -61,7 +61,7 @@
 #[doc(alias = "&*")]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_diagnostic_item = "Deref"]
-#[cfg_attr(not(bootstrap), const_trait)]
+#[const_trait]
 pub trait Deref {
     /// The resulting type after dereferencing.
     #[stable(feature = "rust1", since = "1.0.0")]
index 8d4b0a7ccacdb68527c3b7128446af63e35e5e20..910a92ec0d996d7b373481a9608e384f99a687c3 100644 (file)
@@ -75,6 +75,7 @@
 )]
 #[fundamental] // so that regex can rely that `&str: !FnMut`
 #[must_use = "closures are lazy and do nothing unless called"]
+#[const_trait]
 pub trait Fn<Args>: FnMut<Args> {
     /// Performs the call operation.
     #[unstable(feature = "fn_traits", issue = "29625")]
@@ -244,6 +245,7 @@ pub trait Fn<Args: Tuple>: FnMut<Args> {
 )]
 #[fundamental] // so that regex can rely that `&str: !FnMut`
 #[must_use = "closures are lazy and do nothing unless called"]
+#[const_trait]
 pub trait FnMut<Args>: FnOnce<Args> {
     /// Performs the call operation.
     #[unstable(feature = "fn_traits", issue = "29625")]
@@ -413,6 +415,7 @@ pub trait FnMut<Args: Tuple>: FnOnce<Args> {
 )]
 #[fundamental] // so that regex can rely that `&str: !FnMut`
 #[must_use = "closures are lazy and do nothing unless called"]
+#[const_trait]
 pub trait FnOnce<Args> {
     /// The returned type after the call operator is used.
     #[lang = "fn_once_output"]
@@ -576,9 +579,10 @@ mod impls {
     use crate::marker::Tuple;
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<A: Tuple, F: ?Sized> Fn<A> for &F
+    #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
+    impl<A: Tuple, F: ?Sized> const Fn<A> for &F
     where
-        F: Fn<A>,
+        F: ~const Fn<A>,
     {
         extern "rust-call" fn call(&self, args: A) -> F::Output {
             (**self).call(args)
@@ -586,9 +590,10 @@ extern "rust-call" fn call(&self, args: A) -> F::Output {
     }
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<A: Tuple, F: ?Sized> FnMut<A> for &F
+    #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
+    impl<A: Tuple, F: ?Sized> const FnMut<A> for &F
     where
-        F: Fn<A>,
+        F: ~const Fn<A>,
     {
         extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output {
             (**self).call(args)
@@ -596,9 +601,10 @@ extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output {
     }
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<A: Tuple, F: ?Sized> FnOnce<A> for &F
+    #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
+    impl<A: Tuple, F: ?Sized> const FnOnce<A> for &F
     where
-        F: Fn<A>,
+        F: ~const Fn<A>,
     {
         type Output = F::Output;
 
@@ -608,9 +614,10 @@ extern "rust-call" fn call_once(self, args: A) -> F::Output {
     }
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<A: Tuple, F: ?Sized> FnMut<A> for &mut F
+    #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
+    impl<A: Tuple, F: ?Sized> const FnMut<A> for &mut F
     where
-        F: FnMut<A>,
+        F: ~const FnMut<A>,
     {
         extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output {
             (*self).call_mut(args)
@@ -618,9 +625,10 @@ extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output {
     }
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<A: Tuple, F: ?Sized> FnOnce<A> for &mut F
+    #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
+    impl<A: Tuple, F: ?Sized> const FnOnce<A> for &mut F
     where
-        F: FnMut<A>,
+        F: ~const FnMut<A>,
     {
         type Output = F::Output;
         extern "rust-call" fn call_once(self, args: A) -> F::Output {
index dd4e3ac1c2fe5319dca6f39370dcddc34b0e8827..5e3dc48b6ca1c1b8a8cc464162b7a598ebb767c8 100644 (file)
@@ -55,7 +55,7 @@
 #[doc(alias = "]")]
 #[doc(alias = "[")]
 #[doc(alias = "[]")]
-#[cfg_attr(not(bootstrap), const_trait)]
+#[const_trait]
 pub trait Index<Idx: ?Sized> {
     /// The returned type after indexing.
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -164,7 +164,7 @@ pub trait Index<Idx: ?Sized> {
 #[doc(alias = "[")]
 #[doc(alias = "]")]
 #[doc(alias = "[]")]
-#[cfg_attr(not(bootstrap), const_trait)]
+#[const_trait]
 pub trait IndexMut<Idx: ?Sized>: Index<Idx> {
     /// Performs the mutable indexing (`container[index]`) operation.
     ///
index a81dbc6924fb737a3d9891bd7099f6f89ec7a24c..f284b43595576e837d3e3054e8959aa403d799ea 100644 (file)
@@ -1720,7 +1720,7 @@ impl<T, U> Option<(T, U)> {
     /// assert_eq!(y.unzip(), (None, None));
     /// ```
     #[inline]
-    #[stable(feature = "unzip_option", since = "CURRENT_RUSTC_VERSION")]
+    #[stable(feature = "unzip_option", since = "1.66.0")]
     #[rustc_const_unstable(feature = "const_option", issue = "67441")]
     pub const fn unzip(self) -> (Option<T>, Option<U>)
     where
index a9de7c94e5a11ac25a7d6de036b1134bee3805f9..4fd1eb234137fb56cbe1fa6d22343b0daacb3aff 100644 (file)
@@ -70,8 +70,7 @@ pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
 #[cold]
 #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
 #[cfg_attr(feature = "panic_immediate_abort", inline)]
-#[cfg_attr(not(bootstrap), rustc_nounwind)]
-#[cfg_attr(bootstrap, rustc_allocator_nounwind)]
+#[rustc_nounwind]
 pub fn panic_str_nounwind(msg: &'static str) -> ! {
     if cfg!(feature = "panic_immediate_abort") {
         super::intrinsics::abort()
@@ -158,8 +157,7 @@ fn panic_bounds_check(index: usize, len: usize) -> ! {
 #[cold]
 #[inline(never)]
 #[lang = "panic_no_unwind"] // needed by codegen for panic in nounwind function
-#[cfg_attr(not(bootstrap), rustc_nounwind)]
-#[cfg_attr(bootstrap, rustc_allocator_nounwind)]
+#[rustc_nounwind]
 fn panic_no_unwind() -> ! {
     panic_str_nounwind("panic in a function that cannot unwind")
 }
index ccef35b45325a4001603c6edc7f6fc6c73d017f2..f0258640e2aec4c508b421cdd87d031e34adfa9a 100644 (file)
@@ -1059,7 +1059,7 @@ impl<P, U> DispatchFromDyn<Pin<U>> for Pin<P> where P: DispatchFromDyn<U> {}
 /// 8  | let x: Pin<&mut Foo> = {
 ///    |     - borrow later stored here
 /// 9  |     let x: Pin<&mut Foo> = pin!(Foo { /* … */ });
-///    |                            ^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+///    |                            ^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
 /// 10 |     x
 /// 11 | }; // <- Foo is dropped
 ///    | - temporary value is freed at the end of this statement
index 804a179bdb3c04a835e47c97db8896da119f73bb..d3d255a802d7f626ec89be2d0d5f683ec5914254 100644 (file)
 #[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
 pub use crate::macros::builtin::{bench, derive, global_allocator, test, test_case};
 
+#[unstable(feature = "derive_const", issue = "none")]
+#[cfg(not(bootstrap))]
+pub use crate::macros::builtin::derive_const;
+
 #[unstable(
     feature = "cfg_accessible",
     issue = "64797",
index 5a083227bb0efda119a32a6458b3d129affaace6..926d2ae51139864944c44d843ba81f6c176d9bd5 100644 (file)
@@ -568,6 +568,31 @@ pub const fn wrapping_byte_offset(self, count: isize) -> Self {
     ///
     /// For non-`Sized` pointees this operation changes only the data pointer,
     /// leaving the metadata untouched.
+    ///
+    /// ## Examples
+    ///
+    /// ```
+    /// #![feature(ptr_mask, strict_provenance)]
+    /// let v = 17_u32;
+    /// let ptr: *const u32 = &v;
+    ///
+    /// // `u32` is 4 bytes aligned,
+    /// // which means that lower 2 bits are always 0.
+    /// let tag_mask = 0b11;
+    /// let ptr_mask = !tag_mask;
+    ///
+    /// // We can store something in these lower bits
+    /// let tagged_ptr = ptr.map_addr(|a| a | 0b10);
+    ///
+    /// // Get the "tag" back
+    /// let tag = tagged_ptr.addr() & tag_mask;
+    /// assert_eq!(tag, 0b10);
+    ///
+    /// // Note that `tagged_ptr` is unaligned, it's UB to read from it.
+    /// // To get original pointer `mask` can be used:
+    /// let masked_ptr = tagged_ptr.mask(ptr_mask);
+    /// assert_eq!(unsafe { *masked_ptr }, 17);
+    /// ```
     #[unstable(feature = "ptr_mask", issue = "98290")]
     #[must_use = "returns a new pointer rather than modifying its argument"]
     #[inline(always)]
index 565c38d222a2c4339ceec5e77fc9d8a0adeae978..742fe4f3f633b1085392a8129f464cfeae168f25 100644 (file)
@@ -35,7 +35,8 @@
 //!   be used for inter-thread synchronization.
 //! * The result of casting a reference to a pointer is valid for as long as the
 //!   underlying object is live and no reference (just raw pointers) is used to
-//!   access the same memory.
+//!   access the same memory. That is, reference and pointer accesses cannot be
+//!   interleaved.
 //!
 //! These axioms, along with careful use of [`offset`] for pointer arithmetic,
 //! are enough to correctly implement many useful things in unsafe code. Stronger guarantees
@@ -64,7 +65,6 @@
 //! separate allocated object), heap allocations (each allocation created by the global allocator is
 //! a separate allocated object), and `static` variables.
 //!
-//!
 //! # Strict Provenance
 //!
 //! **The following text is non-normative, insufficiently formal, and is an extremely strict
@@ -1862,7 +1862,6 @@ macro_rules! fnptr_impls_safety_abi {
         fnptr_impls_safety_abi! { #[stable(feature = "fnptr_impls", since = "1.4.0")] $FnTy, $($Arg),* }
     };
     (@c_unwind $FnTy: ty, $($Arg: ident),*) => {
-        #[cfg(not(bootstrap))]
         fnptr_impls_safety_abi! { #[unstable(feature = "c_unwind", issue = "74990")] $FnTy, $($Arg),* }
     };
     (#[$meta:meta] $FnTy: ty, $($Arg: ident),*) => {
index 6764002bcd434e525fe8cc30d8f3a0f177107462..f71696e9ca0fa9e1b072d6e0f31c1386cc6508e3 100644 (file)
@@ -588,6 +588,34 @@ pub const fn wrapping_byte_offset(self, count: isize) -> Self {
     ///
     /// For non-`Sized` pointees this operation changes only the data pointer,
     /// leaving the metadata untouched.
+    ///
+    /// ## Examples
+    ///
+    /// ```
+    /// #![feature(ptr_mask, strict_provenance)]
+    /// let mut v = 17_u32;
+    /// let ptr: *mut u32 = &mut v;
+    ///
+    /// // `u32` is 4 bytes aligned,
+    /// // which means that lower 2 bits are always 0.
+    /// let tag_mask = 0b11;
+    /// let ptr_mask = !tag_mask;
+    ///
+    /// // We can store something in these lower bits
+    /// let tagged_ptr = ptr.map_addr(|a| a | 0b10);
+    ///
+    /// // Get the "tag" back
+    /// let tag = tagged_ptr.addr() & tag_mask;
+    /// assert_eq!(tag, 0b10);
+    ///
+    /// // Note that `tagged_ptr` is unaligned, it's UB to read from/write to it.
+    /// // To get original pointer `mask` can be used:
+    /// let masked_ptr = tagged_ptr.mask(ptr_mask);
+    /// assert_eq!(unsafe { *masked_ptr }, 17);
+    ///
+    /// unsafe { *masked_ptr = 0 };
+    /// assert_eq!(v, 0);
+    /// ```
     #[unstable(feature = "ptr_mask", issue = "98290")]
     #[must_use = "returns a new pointer rather than modifying its argument"]
     #[inline(always)]
index 4f1bb17344b2943f74c86996e8ac7edb4b8af358..0f58bc643d9655a8aaa299f61efcecf462a5d29e 100644 (file)
@@ -3524,8 +3524,8 @@ pub unsafe fn align_to<U>(&self) -> (&[T], &[U], &[T]) {
         }
     }
 
-    /// Transmute the slice to a slice of another type, ensuring alignment of the types is
-    /// maintained.
+    /// Transmute the mutable slice to a mutable slice of another type, ensuring alignment of the
+    /// types is maintained.
     ///
     /// This method splits the slice into three distinct slices: prefix, correctly aligned middle
     /// slice of a new type, and the suffix slice. The method may make the middle slice the greatest
@@ -3667,7 +3667,8 @@ pub fn as_simd<const LANES: usize>(&self) -> (&[T], &[Simd<T, LANES>], &[T])
         unsafe { self.align_to() }
     }
 
-    /// Split a slice into a prefix, a middle of aligned SIMD types, and a suffix.
+    /// Split a mutable slice into a mutable prefix, a middle of aligned SIMD types,
+    /// and a mutable suffix.
     ///
     /// This is a safe wrapper around [`slice::align_to_mut`], so has the same weak
     /// postconditions as that method.  You're only assured that
index 37c3611d0a908956b9b92f77094da68f6e3aaf25..ba1cb6efa04b6a2480b571584ac7d013d58b2132 100644 (file)
@@ -1232,7 +1232,7 @@ fn fmt_decimal(
 /// }
 /// ```
 #[derive(Debug, Clone, PartialEq, Eq)]
-#[stable(feature = "duration_checked_float", since = "CURRENT_RUSTC_VERSION")]
+#[stable(feature = "duration_checked_float", since = "1.66.0")]
 pub struct TryFromFloatSecsError {
     kind: TryFromFloatSecsErrorKind,
 }
@@ -1250,7 +1250,7 @@ const fn description(&self) -> &'static str {
     }
 }
 
-#[stable(feature = "duration_checked_float", since = "CURRENT_RUSTC_VERSION")]
+#[stable(feature = "duration_checked_float", since = "1.66.0")]
 impl fmt::Display for TryFromFloatSecsError {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         self.description().fmt(f)
@@ -1401,7 +1401,7 @@ impl Duration {
     /// let res = Duration::try_from_secs_f32(val);
     /// assert_eq!(res, Ok(Duration::new(1, 2_929_688)));
     /// ```
-    #[stable(feature = "duration_checked_float", since = "CURRENT_RUSTC_VERSION")]
+    #[stable(feature = "duration_checked_float", since = "1.66.0")]
     #[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")]
     #[inline]
     pub const fn try_from_secs_f32(secs: f32) -> Result<Duration, TryFromFloatSecsError> {
@@ -1478,7 +1478,7 @@ pub const fn try_from_secs_f32(secs: f32) -> Result<Duration, TryFromFloatSecsEr
     /// let res = Duration::try_from_secs_f64(val);
     /// assert_eq!(res, Ok(Duration::new(1, 2_929_688)));
     /// ```
-    #[stable(feature = "duration_checked_float", since = "CURRENT_RUSTC_VERSION")]
+    #[stable(feature = "duration_checked_float", since = "1.66.0")]
     #[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")]
     #[inline]
     pub const fn try_from_secs_f64(secs: f64) -> Result<Duration, TryFromFloatSecsError> {
index fc91fe468cc29836e79493728c92e0ff9f3e627d..28275798f751ed16d151649d491985b0de83c7ac 100644 (file)
@@ -22,7 +22,8 @@ macro_rules! tuple_impls {
         maybe_tuple_doc! {
             $($T)+ @
             #[stable(feature = "rust1", since = "1.0.0")]
-            impl<$($T:PartialEq),+> PartialEq for ($($T,)+)
+            #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+            impl<$($T: ~const PartialEq),+> const PartialEq for ($($T,)+)
             where
                 last_type!($($T,)+): ?Sized
             {
@@ -40,7 +41,7 @@ fn ne(&self, other: &($($T,)+)) -> bool {
         maybe_tuple_doc! {
             $($T)+ @
             #[stable(feature = "rust1", since = "1.0.0")]
-            impl<$($T:Eq),+> Eq for ($($T,)+)
+            impl<$($T: Eq),+> Eq for ($($T,)+)
             where
                 last_type!($($T,)+): ?Sized
             {}
@@ -49,7 +50,8 @@ impl<$($T:Eq),+> Eq for ($($T,)+)
         maybe_tuple_doc! {
             $($T)+ @
             #[stable(feature = "rust1", since = "1.0.0")]
-            impl<$($T:PartialOrd + PartialEq),+> PartialOrd for ($($T,)+)
+            #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+            impl<$($T: ~const PartialOrd + ~const PartialEq),+> const PartialOrd for ($($T,)+)
             where
                 last_type!($($T,)+): ?Sized
             {
@@ -79,7 +81,8 @@ fn gt(&self, other: &($($T,)+)) -> bool {
         maybe_tuple_doc! {
             $($T)+ @
             #[stable(feature = "rust1", since = "1.0.0")]
-            impl<$($T:Ord),+> Ord for ($($T,)+)
+            #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+            impl<$($T: ~const Ord),+> const Ord for ($($T,)+)
             where
                 last_type!($($T,)+): ?Sized
             {
index f7934d062a3798051fbbbbf57bcefb832c5d3963..267245f05dcd2203eb7c8d6a77d086c2c81f0720 100644 (file)
@@ -9,16 +9,19 @@ struct MyHasher {
     hash: u64,
 }
 
-impl Default for MyHasher {
+impl const Default for MyHasher {
     fn default() -> MyHasher {
         MyHasher { hash: 0 }
     }
 }
 
-impl Hasher for MyHasher {
+impl const Hasher for MyHasher {
     fn write(&mut self, buf: &[u8]) {
-        for byte in buf {
-            self.hash += *byte as u64;
+        // FIXME(const_trait_impl): change to for loop
+        let mut i = 0;
+        while i < buf.len() {
+            self.hash += buf[i] as u64;
+            i += 1;
         }
     }
     fn write_str(&mut self, s: &str) {
@@ -32,12 +35,25 @@ fn finish(&self) -> u64 {
 
 #[test]
 fn test_writer_hasher() {
-    fn hash<T: Hash>(t: &T) -> u64 {
+    const fn hash<T: ~const Hash>(t: &T) -> u64 {
         let mut s = MyHasher { hash: 0 };
         t.hash(&mut s);
         s.finish()
     }
 
+    const {
+        // FIXME(fee1-dead): assert_eq
+        assert!(hash(&()) == 0);
+        assert!(hash(&5_u8) == 5);
+        assert!(hash(&5_u16) == 5);
+        assert!(hash(&5_u32) == 5);
+
+        assert!(hash(&'a') == 97);
+
+        let s: &str = "a";
+        assert!(hash(&s) == 97 + 0xFF);
+    };
+
     assert_eq!(hash(&()), 0);
 
     assert_eq!(hash(&5_u8), 5);
@@ -97,7 +113,7 @@ struct CustomHasher {
     output: u64,
 }
 
-impl Hasher for CustomHasher {
+impl const Hasher for CustomHasher {
     fn finish(&self) -> u64 {
         self.output
     }
@@ -109,27 +125,29 @@ fn write_u64(&mut self, data: u64) {
     }
 }
 
-impl Default for CustomHasher {
+impl const Default for CustomHasher {
     fn default() -> CustomHasher {
         CustomHasher { output: 0 }
     }
 }
 
-impl Hash for Custom {
-    fn hash<H: Hasher>(&self, state: &mut H) {
+impl const Hash for Custom {
+    fn hash<H: ~const Hasher>(&self, state: &mut H) {
         state.write_u64(self.hash);
     }
 }
 
 #[test]
 fn test_custom_state() {
-    fn hash<T: Hash>(t: &T) -> u64 {
+    const fn hash<T: ~const Hash>(t: &T) -> u64 {
         let mut c = CustomHasher { output: 0 };
         t.hash(&mut c);
         c.finish()
     }
 
     assert_eq!(hash(&Custom { hash: 5 }), 5);
+
+    const { assert!(hash(&Custom { hash: 6 }) == 6) };
 }
 
 // FIXME: Instantiated functions with i128 in the signature is not supported in Emscripten.
index 877d0841830551b0b104f0f3d5967e553007278f..3abf6efcfa9ba842d312f4bc4deb1a29a5b61d9b 100644 (file)
@@ -8,7 +8,6 @@
 struct Bytes<'a>(&'a [u8]);
 
 impl<'a> Hash for Bytes<'a> {
-    #[allow(unused_must_use)]
     fn hash<H: Hasher>(&self, state: &mut H) {
         let Bytes(v) = *self;
         state.write(v);
@@ -24,6 +23,20 @@ fn hash<T: Hash>(x: &T) -> u64 {
     hash_with(SipHasher::new(), x)
 }
 
+#[test]
+const fn test_const_sip() {
+    let val1 = 0x45;
+    let val2 = 0xfeed;
+
+    const fn const_hash<T: ~const Hash>(x: &T) -> u64 {
+        let mut st = SipHasher::new();
+        x.hash(&mut st);
+        st.finish()
+    }
+
+    assert!(const_hash(&(val1)) != const_hash(&(val2)));
+}
+
 #[test]
 #[allow(unused_must_use)]
 fn test_siphash_1_3() {
index 4e9d89e1e580f688c0d1d95afe636c8cf48a1bff..ef4a7e53bdd339caa6f7b22fbfb37fb16927b201 100644 (file)
@@ -139,7 +139,8 @@ fn test_iterator_array_chunks_fold() {
     let result =
         (0..10).map(|_| CountDrop::new(&count)).array_chunks::<3>().fold(0, |acc, _item| acc + 1);
     assert_eq!(result, 3);
-    assert_eq!(count.get(), 10);
+    // fold impls may or may not process the remainder
+    assert!(count.get() <= 10 && count.get() >= 9);
 }
 
 #[test]
index eda176d9fcbe61c307de586eb8ca416b39af0d3d..61d31b3448734349b7c5b06ba5bf68de895d18b3 100644 (file)
@@ -11,6 +11,7 @@
 #![feature(const_caller_location)]
 #![feature(const_cell_into_inner)]
 #![feature(const_convert)]
+#![feature(const_hash)]
 #![feature(const_heap)]
 #![feature(const_maybe_uninit_as_mut_ptr)]
 #![feature(const_maybe_uninit_assume_init_read)]
@@ -64,7 +65,6 @@
 #![feature(try_trait_v2)]
 #![feature(slice_internals)]
 #![feature(slice_partition_dedup)]
-#![feature(int_log)]
 #![feature(iter_advance_by)]
 #![feature(iter_array_chunks)]
 #![feature(iter_collect_into)]
index f36f7c268064f27e7b97cbfa1187803ec5811f66..dca6321cf62fd6f3d9e0d242f9d7ac090fbaf983 100644 (file)
@@ -57,7 +57,7 @@ fn r(i: Rc<RefCell<isize>>) -> R {
 }
 
 #[test]
-#[cfg_attr(not(bootstrap), allow(for_loops_over_fallibles))]
+#[allow(for_loops_over_fallibles)]
 fn test_option_dance() {
     let x = Some(());
     let mut y = Some(5);
index 962c83a78cb34d56e53fdbac4772fd1fdf566691..704e6ed0159f84b7cf69fc858d6df62a0e016de0 100644 (file)
     /// val: vector of values to select if a lane is masked
     /// ptr: vector of pointers to read from
     /// mask: a "wide" mask of integers, selects as if simd_select(mask, read(ptr), val)
-    /// note, the LLVM intrinsic accepts a mask vector of <N x i1>
+    /// note, the LLVM intrinsic accepts a mask vector of `<N x i1>`
     /// FIXME: review this if/when we fix up our mask story in general?
     pub(crate) fn simd_gather<T, U, V>(val: T, ptr: U, mask: V) -> T;
     /// llvm.masked.scatter
index 5a077a469d8390b427bfd8f69567a0b960d072a9..fc1e0bc426df34db6cb384e73a612c783c40cfd1 100644 (file)
@@ -40,7 +40,7 @@ macro_rules! unsafe_base {
 
 /// SAFETY: This macro should not be used for anything except Shl or Shr, and passed the appropriate shift intrinsic.
 /// It handles performing a bitand in addition to calling the shift operator, so that the result
-/// is well-defined: LLVM can return a poison value if you shl, lshr, or ashr if rhs >= <Int>::BITS
+/// is well-defined: LLVM can return a poison value if you shl, lshr, or ashr if `rhs >= <Int>::BITS`
 /// At worst, this will maybe add another instruction and cycle,
 /// at best, it may open up more optimization opportunities,
 /// or simply be elided entirely, especially for SIMD ISAs which default to this.
index 8001fcff6484bdfe8a5306ff51304762f9491d4c..0d3fc2c5244e03fe20af3b33a2814f4c020640db 100644 (file)
@@ -546,7 +546,7 @@ pub fn eq(&self, other: &Span) -> bool {
     /// Note: The observable result of a macro should only rely on the tokens and
     /// not on this source text. The result of this function is a best effort to
     /// be used for diagnostics only.
-    #[stable(feature = "proc_macro_source_text", since = "CURRENT_RUSTC_VERSION")]
+    #[stable(feature = "proc_macro_source_text", since = "1.66.0")]
     pub fn source_text(&self) -> Option<String> {
         self.0.source_text()
     }
index bc10b12ec2af90dddb9d78895e94c1683cfa0973..daa6976c301431aeb6e579a00e6d26fd4146b4db 100644 (file)
@@ -23,11 +23,11 @@ hashbrown = { version = "0.12", default-features = false, features = ['rustc-dep
 std_detect = { path = "../stdarch/crates/std_detect", default-features = false, features = ['rustc-dep-of-std'] }
 
 # Dependencies of the `backtrace` crate
-addr2line = { version = "0.16.0", optional = true, default-features = false }
+addr2line = { version = "0.17.0", optional = true, default-features = false }
 rustc-demangle = { version = "0.1.21", features = ['rustc-dep-of-std'] }
-miniz_oxide = { version = "0.4.0", optional = true, default-features = false }
+miniz_oxide = { version = "0.5.0", optional = true, default-features = false }
 [dependencies.object]
-version = "0.26.1"
+version = "0.29.0"
 optional = true
 default-features = false
 features = ['read_core', 'elf', 'macho', 'pe', 'unaligned', 'archive']
index 708edc5de4751f0232f04ca98e1d7f6acbf3cc87..df490358827e7ae9c8fd777450dc776a19f66b10 100644 (file)
@@ -3161,14 +3161,16 @@ impl DefaultHasher {
     #[stable(feature = "hashmap_default_hasher", since = "1.13.0")]
     #[inline]
     #[allow(deprecated)]
+    #[rustc_const_unstable(feature = "const_hash", issue = "104061")]
     #[must_use]
-    pub fn new() -> DefaultHasher {
+    pub const fn new() -> DefaultHasher {
         DefaultHasher(SipHasher13::new_with_keys(0, 0))
     }
 }
 
 #[stable(feature = "hashmap_default_hasher", since = "1.13.0")]
-impl Default for DefaultHasher {
+#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
+impl const Default for DefaultHasher {
     /// Creates a new `DefaultHasher` using [`new`].
     /// See its documentation for more.
     ///
@@ -3180,7 +3182,8 @@ fn default() -> DefaultHasher {
 }
 
 #[stable(feature = "hashmap_default_hasher", since = "1.13.0")]
-impl Hasher for DefaultHasher {
+#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
+impl const Hasher for DefaultHasher {
     // The underlying `SipHasher13` doesn't override the other
     // `write_*` methods, so it's ok not to forward them here.
 
index 385585dada896fd6819a5365a27d1ced963fe6fc..9334c833bb6509c82e3fb2a4b3cfb55125740f33 100644 (file)
 //
 // Only for const-ness:
 #![feature(const_collections_with_hasher)]
+#![feature(const_hash)]
 #![feature(const_io_structs)]
 #![feature(const_ip)]
 #![feature(const_ipv4)]
index 9d63281627d667be5eb94f212e649a9bfe26703e..af88b9070c189dc31033414d49f6e69753a6d1dc 100644 (file)
@@ -2142,7 +2142,10 @@ pub fn has_root(&self) -> bool {
 
     /// Returns the `Path` without its final component, if there is one.
     ///
-    /// Returns [`None`] if the path terminates in a root or prefix.
+    /// This means it returns `Some("")` for relative paths with one component.
+    ///
+    /// Returns [`None`] if the path terminates in a root or prefix, or if it's
+    /// the empty string.
     ///
     /// # Examples
     ///
@@ -2156,6 +2159,14 @@ pub fn has_root(&self) -> bool {
     /// let grand_parent = parent.parent().unwrap();
     /// assert_eq!(grand_parent, Path::new("/"));
     /// assert_eq!(grand_parent.parent(), None);
+    ///
+    /// let relative_path = Path::new("foo/bar");
+    /// let parent = relative_path.parent();
+    /// assert_eq!(parent, Some(Path::new("foo")));
+    /// let grand_parent = parent.and_then(Path::parent);
+    /// assert_eq!(grand_parent, Some(Path::new("")));
+    /// let great_grand_parent = grand_parent.and_then(Path::parent);
+    /// assert_eq!(great_grand_parent, None);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[doc(alias = "dirname")]
index 7f0b0439cf08380ba65cf316bcf542c215bedfcd..5fc1b91a1c35780fda47ef22f7722a94b9966e22 100644 (file)
@@ -219,7 +219,7 @@ fn __gnu_unwind_frame(
         }
 
         cfg_if::cfg_if! {
-            if #[cfg(all(windows, target_arch = "x86_64", target_env = "gnu"))] {
+            if #[cfg(all(windows, any(target_arch = "aarch64", target_arch = "x86_64"), target_env = "gnu"))] {
                 // On x86_64 MinGW targets, the unwinding mechanism is SEH however the unwind
                 // handler data (aka LSDA) uses GCC-compatible encoding.
                 #[lang = "eh_personality"]
index 36d9e8921ef31f110eaf284b7747aadd1044e44a..d5ac16e6b94e27a6f80b83c475e4500f4128e615 100644 (file)
 #[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
 pub use core::prelude::v1::{bench, derive, global_allocator, test, test_case};
 
+#[unstable(feature = "derive_const", issue = "none")]
+#[cfg(not(bootstrap))]
+pub use core::prelude::v1::derive_const;
+
 // Do not `doc(no_inline)` either.
 #[unstable(
     feature = "cfg_accessible",
index eb1e7135a6e41dcc04980974fa9c9d77c3e49117..76a1b4a2a86cd461679f1ec152f49f7375a4ee66 100644 (file)
@@ -3,7 +3,7 @@
 
 use crate::fmt;
 use crate::sync::{mutex, poison, LockResult, MutexGuard, PoisonError};
-use crate::sys_common::condvar as sys;
+use crate::sys::locks as sys;
 use crate::time::{Duration, Instant};
 
 /// A type indicating whether a timed wait on a condition variable returned
index 7b507a169b395edeb317737d499ba23cd517c596..4fee8d3e92fc84b58ee1747d095f0bbbcf128d6e 100644 (file)
 mod barrier;
 mod condvar;
 mod lazy_lock;
+mod mpmc;
 mod mutex;
 mod once;
 mod once_lock;
diff --git a/library/std/src/sync/mpmc/array.rs b/library/std/src/sync/mpmc/array.rs
new file mode 100644 (file)
index 0000000..4db7b49
--- /dev/null
@@ -0,0 +1,513 @@
+//! Bounded channel based on a preallocated array.
+//!
+//! This flavor has a fixed, positive capacity.
+//!
+//! The implementation is based on Dmitry Vyukov's bounded MPMC queue.
+//!
+//! Source:
+//!   - <http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue>
+//!   - <https://docs.google.com/document/d/1yIAYmbvL3JxOKOjuCyon7JhW4cSv1wy5hC0ApeGMV9s/pub>
+
+use super::context::Context;
+use super::error::*;
+use super::select::{Operation, Selected, Token};
+use super::utils::{Backoff, CachePadded};
+use super::waker::SyncWaker;
+
+use crate::cell::UnsafeCell;
+use crate::mem::MaybeUninit;
+use crate::ptr;
+use crate::sync::atomic::{self, AtomicUsize, Ordering};
+use crate::time::Instant;
+
+/// A slot in a channel.
+struct Slot<T> {
+    /// The current stamp.
+    stamp: AtomicUsize,
+
+    /// The message in this slot.
+    msg: UnsafeCell<MaybeUninit<T>>,
+}
+
+/// The token type for the array flavor.
+#[derive(Debug)]
+pub(crate) struct ArrayToken {
+    /// Slot to read from or write to.
+    slot: *const u8,
+
+    /// Stamp to store into the slot after reading or writing.
+    stamp: usize,
+}
+
+impl Default for ArrayToken {
+    #[inline]
+    fn default() -> Self {
+        ArrayToken { slot: ptr::null(), stamp: 0 }
+    }
+}
+
+/// Bounded channel based on a preallocated array.
+pub(crate) struct Channel<T> {
+    /// The head of the channel.
+    ///
+    /// This value is a "stamp" consisting of an index into the buffer, a mark bit, and a lap, but
+    /// packed into a single `usize`. The lower bits represent the index, while the upper bits
+    /// represent the lap. The mark bit in the head is always zero.
+    ///
+    /// Messages are popped from the head of the channel.
+    head: CachePadded<AtomicUsize>,
+
+    /// The tail of the channel.
+    ///
+    /// This value is a "stamp" consisting of an index into the buffer, a mark bit, and a lap, but
+    /// packed into a single `usize`. The lower bits represent the index, while the upper bits
+    /// represent the lap. The mark bit indicates that the channel is disconnected.
+    ///
+    /// Messages are pushed into the tail of the channel.
+    tail: CachePadded<AtomicUsize>,
+
+    /// The buffer holding slots.
+    buffer: Box<[Slot<T>]>,
+
+    /// The channel capacity.
+    cap: usize,
+
+    /// A stamp with the value of `{ lap: 1, mark: 0, index: 0 }`.
+    one_lap: usize,
+
+    /// If this bit is set in the tail, that means the channel is disconnected.
+    mark_bit: usize,
+
+    /// Senders waiting while the channel is full.
+    senders: SyncWaker,
+
+    /// Receivers waiting while the channel is empty and not disconnected.
+    receivers: SyncWaker,
+}
+
+impl<T> Channel<T> {
+    /// Creates a bounded channel of capacity `cap`.
+    pub(crate) fn with_capacity(cap: usize) -> Self {
+        assert!(cap > 0, "capacity must be positive");
+
+        // Compute constants `mark_bit` and `one_lap`.
+        let mark_bit = (cap + 1).next_power_of_two();
+        let one_lap = mark_bit * 2;
+
+        // Head is initialized to `{ lap: 0, mark: 0, index: 0 }`.
+        let head = 0;
+        // Tail is initialized to `{ lap: 0, mark: 0, index: 0 }`.
+        let tail = 0;
+
+        // Allocate a buffer of `cap` slots initialized
+        // with stamps.
+        let buffer: Box<[Slot<T>]> = (0..cap)
+            .map(|i| {
+                // Set the stamp to `{ lap: 0, mark: 0, index: i }`.
+                Slot { stamp: AtomicUsize::new(i), msg: UnsafeCell::new(MaybeUninit::uninit()) }
+            })
+            .collect();
+
+        Channel {
+            buffer,
+            cap,
+            one_lap,
+            mark_bit,
+            head: CachePadded::new(AtomicUsize::new(head)),
+            tail: CachePadded::new(AtomicUsize::new(tail)),
+            senders: SyncWaker::new(),
+            receivers: SyncWaker::new(),
+        }
+    }
+
+    /// Attempts to reserve a slot for sending a message.
+    fn start_send(&self, token: &mut Token) -> bool {
+        let backoff = Backoff::new();
+        let mut tail = self.tail.load(Ordering::Relaxed);
+
+        loop {
+            // Check if the channel is disconnected.
+            if tail & self.mark_bit != 0 {
+                token.array.slot = ptr::null();
+                token.array.stamp = 0;
+                return true;
+            }
+
+            // Deconstruct the tail.
+            let index = tail & (self.mark_bit - 1);
+            let lap = tail & !(self.one_lap - 1);
+
+            // Inspect the corresponding slot.
+            debug_assert!(index < self.buffer.len());
+            let slot = unsafe { self.buffer.get_unchecked(index) };
+            let stamp = slot.stamp.load(Ordering::Acquire);
+
+            // If the tail and the stamp match, we may attempt to push.
+            if tail == stamp {
+                let new_tail = if index + 1 < self.cap {
+                    // Same lap, incremented index.
+                    // Set to `{ lap: lap, mark: 0, index: index + 1 }`.
+                    tail + 1
+                } else {
+                    // One lap forward, index wraps around to zero.
+                    // Set to `{ lap: lap.wrapping_add(1), mark: 0, index: 0 }`.
+                    lap.wrapping_add(self.one_lap)
+                };
+
+                // Try moving the tail.
+                match self.tail.compare_exchange_weak(
+                    tail,
+                    new_tail,
+                    Ordering::SeqCst,
+                    Ordering::Relaxed,
+                ) {
+                    Ok(_) => {
+                        // Prepare the token for the follow-up call to `write`.
+                        token.array.slot = slot as *const Slot<T> as *const u8;
+                        token.array.stamp = tail + 1;
+                        return true;
+                    }
+                    Err(_) => {
+                        backoff.spin();
+                        tail = self.tail.load(Ordering::Relaxed);
+                    }
+                }
+            } else if stamp.wrapping_add(self.one_lap) == tail + 1 {
+                atomic::fence(Ordering::SeqCst);
+                let head = self.head.load(Ordering::Relaxed);
+
+                // If the head lags one lap behind the tail as well...
+                if head.wrapping_add(self.one_lap) == tail {
+                    // ...then the channel is full.
+                    return false;
+                }
+
+                backoff.spin();
+                tail = self.tail.load(Ordering::Relaxed);
+            } else {
+                // Snooze because we need to wait for the stamp to get updated.
+                backoff.snooze();
+                tail = self.tail.load(Ordering::Relaxed);
+            }
+        }
+    }
+
+    /// Writes a message into the channel.
+    pub(crate) unsafe fn write(&self, token: &mut Token, msg: T) -> Result<(), T> {
+        // If there is no slot, the channel is disconnected.
+        if token.array.slot.is_null() {
+            return Err(msg);
+        }
+
+        let slot: &Slot<T> = &*(token.array.slot as *const Slot<T>);
+
+        // Write the message into the slot and update the stamp.
+        slot.msg.get().write(MaybeUninit::new(msg));
+        slot.stamp.store(token.array.stamp, Ordering::Release);
+
+        // Wake a sleeping receiver.
+        self.receivers.notify();
+        Ok(())
+    }
+
+    /// Attempts to reserve a slot for receiving a message.
+    fn start_recv(&self, token: &mut Token) -> bool {
+        let backoff = Backoff::new();
+        let mut head = self.head.load(Ordering::Relaxed);
+
+        loop {
+            // Deconstruct the head.
+            let index = head & (self.mark_bit - 1);
+            let lap = head & !(self.one_lap - 1);
+
+            // Inspect the corresponding slot.
+            debug_assert!(index < self.buffer.len());
+            let slot = unsafe { self.buffer.get_unchecked(index) };
+            let stamp = slot.stamp.load(Ordering::Acquire);
+
+            // If the the stamp is ahead of the head by 1, we may attempt to pop.
+            if head + 1 == stamp {
+                let new = if index + 1 < self.cap {
+                    // Same lap, incremented index.
+                    // Set to `{ lap: lap, mark: 0, index: index + 1 }`.
+                    head + 1
+                } else {
+                    // One lap forward, index wraps around to zero.
+                    // Set to `{ lap: lap.wrapping_add(1), mark: 0, index: 0 }`.
+                    lap.wrapping_add(self.one_lap)
+                };
+
+                // Try moving the head.
+                match self.head.compare_exchange_weak(
+                    head,
+                    new,
+                    Ordering::SeqCst,
+                    Ordering::Relaxed,
+                ) {
+                    Ok(_) => {
+                        // Prepare the token for the follow-up call to `read`.
+                        token.array.slot = slot as *const Slot<T> as *const u8;
+                        token.array.stamp = head.wrapping_add(self.one_lap);
+                        return true;
+                    }
+                    Err(_) => {
+                        backoff.spin();
+                        head = self.head.load(Ordering::Relaxed);
+                    }
+                }
+            } else if stamp == head {
+                atomic::fence(Ordering::SeqCst);
+                let tail = self.tail.load(Ordering::Relaxed);
+
+                // If the tail equals the head, that means the channel is empty.
+                if (tail & !self.mark_bit) == head {
+                    // If the channel is disconnected...
+                    if tail & self.mark_bit != 0 {
+                        // ...then receive an error.
+                        token.array.slot = ptr::null();
+                        token.array.stamp = 0;
+                        return true;
+                    } else {
+                        // Otherwise, the receive operation is not ready.
+                        return false;
+                    }
+                }
+
+                backoff.spin();
+                head = self.head.load(Ordering::Relaxed);
+            } else {
+                // Snooze because we need to wait for the stamp to get updated.
+                backoff.snooze();
+                head = self.head.load(Ordering::Relaxed);
+            }
+        }
+    }
+
+    /// Reads a message from the channel.
+    pub(crate) unsafe fn read(&self, token: &mut Token) -> Result<T, ()> {
+        if token.array.slot.is_null() {
+            // The channel is disconnected.
+            return Err(());
+        }
+
+        let slot: &Slot<T> = &*(token.array.slot as *const Slot<T>);
+
+        // Read the message from the slot and update the stamp.
+        let msg = slot.msg.get().read().assume_init();
+        slot.stamp.store(token.array.stamp, Ordering::Release);
+
+        // Wake a sleeping sender.
+        self.senders.notify();
+        Ok(msg)
+    }
+
+    /// Attempts to send a message into the channel.
+    pub(crate) fn try_send(&self, msg: T) -> Result<(), TrySendError<T>> {
+        let token = &mut Token::default();
+        if self.start_send(token) {
+            unsafe { self.write(token, msg).map_err(TrySendError::Disconnected) }
+        } else {
+            Err(TrySendError::Full(msg))
+        }
+    }
+
+    /// Sends a message into the channel.
+    pub(crate) fn send(
+        &self,
+        msg: T,
+        deadline: Option<Instant>,
+    ) -> Result<(), SendTimeoutError<T>> {
+        let token = &mut Token::default();
+        loop {
+            // Try sending a message several times.
+            let backoff = Backoff::new();
+            loop {
+                if self.start_send(token) {
+                    let res = unsafe { self.write(token, msg) };
+                    return res.map_err(SendTimeoutError::Disconnected);
+                }
+
+                if backoff.is_completed() {
+                    break;
+                } else {
+                    backoff.spin();
+                }
+            }
+
+            if let Some(d) = deadline {
+                if Instant::now() >= d {
+                    return Err(SendTimeoutError::Timeout(msg));
+                }
+            }
+
+            Context::with(|cx| {
+                // Prepare for blocking until a receiver wakes us up.
+                let oper = Operation::hook(token);
+                self.senders.register(oper, cx);
+
+                // Has the channel become ready just now?
+                if !self.is_full() || self.is_disconnected() {
+                    let _ = cx.try_select(Selected::Aborted);
+                }
+
+                // Block the current thread.
+                let sel = cx.wait_until(deadline);
+
+                match sel {
+                    Selected::Waiting => unreachable!(),
+                    Selected::Aborted | Selected::Disconnected => {
+                        self.senders.unregister(oper).unwrap();
+                    }
+                    Selected::Operation(_) => {}
+                }
+            });
+        }
+    }
+
+    /// Attempts to receive a message without blocking.
+    pub(crate) fn try_recv(&self) -> Result<T, TryRecvError> {
+        let token = &mut Token::default();
+
+        if self.start_recv(token) {
+            unsafe { self.read(token).map_err(|_| TryRecvError::Disconnected) }
+        } else {
+            Err(TryRecvError::Empty)
+        }
+    }
+
+    /// Receives a message from the channel.
+    pub(crate) fn recv(&self, deadline: Option<Instant>) -> Result<T, RecvTimeoutError> {
+        let token = &mut Token::default();
+        loop {
+            if self.start_recv(token) {
+                let res = unsafe { self.read(token) };
+                return res.map_err(|_| RecvTimeoutError::Disconnected);
+            }
+
+            if let Some(d) = deadline {
+                if Instant::now() >= d {
+                    return Err(RecvTimeoutError::Timeout);
+                }
+            }
+
+            Context::with(|cx| {
+                // Prepare for blocking until a sender wakes us up.
+                let oper = Operation::hook(token);
+                self.receivers.register(oper, cx);
+
+                // Has the channel become ready just now?
+                if !self.is_empty() || self.is_disconnected() {
+                    let _ = cx.try_select(Selected::Aborted);
+                }
+
+                // Block the current thread.
+                let sel = cx.wait_until(deadline);
+
+                match sel {
+                    Selected::Waiting => unreachable!(),
+                    Selected::Aborted | Selected::Disconnected => {
+                        self.receivers.unregister(oper).unwrap();
+                        // If the channel was disconnected, we still have to check for remaining
+                        // messages.
+                    }
+                    Selected::Operation(_) => {}
+                }
+            });
+        }
+    }
+
+    /// Returns the current number of messages inside the channel.
+    pub(crate) fn len(&self) -> usize {
+        loop {
+            // Load the tail, then load the head.
+            let tail = self.tail.load(Ordering::SeqCst);
+            let head = self.head.load(Ordering::SeqCst);
+
+            // If the tail didn't change, we've got consistent values to work with.
+            if self.tail.load(Ordering::SeqCst) == tail {
+                let hix = head & (self.mark_bit - 1);
+                let tix = tail & (self.mark_bit - 1);
+
+                return if hix < tix {
+                    tix - hix
+                } else if hix > tix {
+                    self.cap - hix + tix
+                } else if (tail & !self.mark_bit) == head {
+                    0
+                } else {
+                    self.cap
+                };
+            }
+        }
+    }
+
+    /// Returns the capacity of the channel.
+    #[allow(clippy::unnecessary_wraps)] // This is intentional.
+    pub(crate) fn capacity(&self) -> Option<usize> {
+        Some(self.cap)
+    }
+
+    /// Disconnects the channel and wakes up all blocked senders and receivers.
+    ///
+    /// Returns `true` if this call disconnected the channel.
+    pub(crate) fn disconnect(&self) -> bool {
+        let tail = self.tail.fetch_or(self.mark_bit, Ordering::SeqCst);
+
+        if tail & self.mark_bit == 0 {
+            self.senders.disconnect();
+            self.receivers.disconnect();
+            true
+        } else {
+            false
+        }
+    }
+
+    /// Returns `true` if the channel is disconnected.
+    pub(crate) fn is_disconnected(&self) -> bool {
+        self.tail.load(Ordering::SeqCst) & self.mark_bit != 0
+    }
+
+    /// Returns `true` if the channel is empty.
+    pub(crate) fn is_empty(&self) -> bool {
+        let head = self.head.load(Ordering::SeqCst);
+        let tail = self.tail.load(Ordering::SeqCst);
+
+        // Is the tail equal to the head?
+        //
+        // Note: If the head changes just before we load the tail, that means there was a moment
+        // when the channel was not empty, so it is safe to just return `false`.
+        (tail & !self.mark_bit) == head
+    }
+
+    /// Returns `true` if the channel is full.
+    pub(crate) fn is_full(&self) -> bool {
+        let tail = self.tail.load(Ordering::SeqCst);
+        let head = self.head.load(Ordering::SeqCst);
+
+        // Is the head lagging one lap behind tail?
+        //
+        // Note: If the tail changes just before we load the head, that means there was a moment
+        // when the channel was not full, so it is safe to just return `false`.
+        head.wrapping_add(self.one_lap) == tail & !self.mark_bit
+    }
+}
+
+impl<T> Drop for Channel<T> {
+    fn drop(&mut self) {
+        // Get the index of the head.
+        let hix = self.head.load(Ordering::Relaxed) & (self.mark_bit - 1);
+
+        // Loop over all slots that hold a message and drop them.
+        for i in 0..self.len() {
+            // Compute the index of the next slot holding a message.
+            let index = if hix + i < self.cap { hix + i } else { hix + i - self.cap };
+
+            unsafe {
+                debug_assert!(index < self.buffer.len());
+                let slot = self.buffer.get_unchecked_mut(index);
+                let msg = &mut *slot.msg.get();
+                msg.as_mut_ptr().drop_in_place();
+            }
+        }
+    }
+}
diff --git a/library/std/src/sync/mpmc/context.rs b/library/std/src/sync/mpmc/context.rs
new file mode 100644 (file)
index 0000000..bbfc6ce
--- /dev/null
@@ -0,0 +1,155 @@
+//! Thread-local channel context.
+
+use super::select::Selected;
+use super::waker::current_thread_id;
+
+use crate::cell::Cell;
+use crate::ptr;
+use crate::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
+use crate::sync::Arc;
+use crate::thread::{self, Thread};
+use crate::time::Instant;
+
+/// Thread-local context.
+#[derive(Debug, Clone)]
+pub struct Context {
+    inner: Arc<Inner>,
+}
+
+/// Inner representation of `Context`.
+#[derive(Debug)]
+struct Inner {
+    /// Selected operation.
+    select: AtomicUsize,
+
+    /// A slot into which another thread may store a pointer to its `Packet`.
+    packet: AtomicPtr<()>,
+
+    /// Thread handle.
+    thread: Thread,
+
+    /// Thread id.
+    thread_id: usize,
+}
+
+impl Context {
+    /// Creates a new context for the duration of the closure.
+    #[inline]
+    pub fn with<F, R>(f: F) -> R
+    where
+        F: FnOnce(&Context) -> R,
+    {
+        thread_local! {
+            /// Cached thread-local context.
+            static CONTEXT: Cell<Option<Context>> = Cell::new(Some(Context::new()));
+        }
+
+        let mut f = Some(f);
+        let mut f = |cx: &Context| -> R {
+            let f = f.take().unwrap();
+            f(cx)
+        };
+
+        CONTEXT
+            .try_with(|cell| match cell.take() {
+                None => f(&Context::new()),
+                Some(cx) => {
+                    cx.reset();
+                    let res = f(&cx);
+                    cell.set(Some(cx));
+                    res
+                }
+            })
+            .unwrap_or_else(|_| f(&Context::new()))
+    }
+
+    /// Creates a new `Context`.
+    #[cold]
+    fn new() -> Context {
+        Context {
+            inner: Arc::new(Inner {
+                select: AtomicUsize::new(Selected::Waiting.into()),
+                packet: AtomicPtr::new(ptr::null_mut()),
+                thread: thread::current(),
+                thread_id: current_thread_id(),
+            }),
+        }
+    }
+
+    /// Resets `select` and `packet`.
+    #[inline]
+    fn reset(&self) {
+        self.inner.select.store(Selected::Waiting.into(), Ordering::Release);
+        self.inner.packet.store(ptr::null_mut(), Ordering::Release);
+    }
+
+    /// Attempts to select an operation.
+    ///
+    /// On failure, the previously selected operation is returned.
+    #[inline]
+    pub fn try_select(&self, select: Selected) -> Result<(), Selected> {
+        self.inner
+            .select
+            .compare_exchange(
+                Selected::Waiting.into(),
+                select.into(),
+                Ordering::AcqRel,
+                Ordering::Acquire,
+            )
+            .map(|_| ())
+            .map_err(|e| e.into())
+    }
+
+    /// Stores a packet.
+    ///
+    /// This method must be called after `try_select` succeeds and there is a packet to provide.
+    #[inline]
+    pub fn store_packet(&self, packet: *mut ()) {
+        if !packet.is_null() {
+            self.inner.packet.store(packet, Ordering::Release);
+        }
+    }
+
+    /// Waits until an operation is selected and returns it.
+    ///
+    /// If the deadline is reached, `Selected::Aborted` will be selected.
+    #[inline]
+    pub fn wait_until(&self, deadline: Option<Instant>) -> Selected {
+        loop {
+            // Check whether an operation has been selected.
+            let sel = Selected::from(self.inner.select.load(Ordering::Acquire));
+            if sel != Selected::Waiting {
+                return sel;
+            }
+
+            // If there's a deadline, park the current thread until the deadline is reached.
+            if let Some(end) = deadline {
+                let now = Instant::now();
+
+                if now < end {
+                    thread::park_timeout(end - now);
+                } else {
+                    // The deadline has been reached. Try aborting select.
+                    return match self.try_select(Selected::Aborted) {
+                        Ok(()) => Selected::Aborted,
+                        Err(s) => s,
+                    };
+                }
+            } else {
+                thread::park();
+            }
+        }
+    }
+
+    /// Unparks the thread this context belongs to.
+    #[inline]
+    pub fn unpark(&self) {
+        self.inner.thread.unpark();
+    }
+
+    /// Returns the id of the thread this context belongs to.
+    #[inline]
+    pub fn thread_id(&self) -> usize {
+        self.inner.thread_id
+    }
+}
diff --git a/library/std/src/sync/mpmc/counter.rs b/library/std/src/sync/mpmc/counter.rs
new file mode 100644 (file)
index 0000000..a5a6bdc
--- /dev/null
@@ -0,0 +1,137 @@
+use crate::ops;
+use crate::process;
+use crate::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
+
+/// Reference counter internals.
+struct Counter<C> {
+    /// The number of senders associated with the channel.
+    senders: AtomicUsize,
+
+    /// The number of receivers associated with the channel.
+    receivers: AtomicUsize,
+
+    /// Set to `true` if the last sender or the last receiver reference deallocates the channel.
+    destroy: AtomicBool,
+
+    /// The internal channel.
+    chan: C,
+}
+
+/// Wraps a channel into the reference counter.
+pub(crate) fn new<C>(chan: C) -> (Sender<C>, Receiver<C>) {
+    let counter = Box::into_raw(Box::new(Counter {
+        senders: AtomicUsize::new(1),
+        receivers: AtomicUsize::new(1),
+        destroy: AtomicBool::new(false),
+        chan,
+    }));
+    let s = Sender { counter };
+    let r = Receiver { counter };
+    (s, r)
+}
+
+/// The sending side.
+pub(crate) struct Sender<C> {
+    counter: *mut Counter<C>,
+}
+
+impl<C> Sender<C> {
+    /// Returns the internal `Counter`.
+    fn counter(&self) -> &Counter<C> {
+        unsafe { &*self.counter }
+    }
+
+    /// Acquires another sender reference.
+    pub(crate) fn acquire(&self) -> Sender<C> {
+        let count = self.counter().senders.fetch_add(1, Ordering::Relaxed);
+
+        // Cloning senders and calling `mem::forget` on the clones could potentially overflow the
+        // counter. It's very difficult to recover sensibly from such degenerate scenarios so we
+        // just abort when the count becomes very large.
+        if count > isize::MAX as usize {
+            process::abort();
+        }
+
+        Sender { counter: self.counter }
+    }
+
+    /// Releases the sender reference.
+    ///
+    /// Function `disconnect` will be called if this is the last sender reference.
+    pub(crate) unsafe fn release<F: FnOnce(&C) -> bool>(&self, disconnect: F) {
+        if self.counter().senders.fetch_sub(1, Ordering::AcqRel) == 1 {
+            disconnect(&self.counter().chan);
+
+            if self.counter().destroy.swap(true, Ordering::AcqRel) {
+                drop(Box::from_raw(self.counter));
+            }
+        }
+    }
+}
+
+impl<C> ops::Deref for Sender<C> {
+    type Target = C;
+
+    fn deref(&self) -> &C {
+        &self.counter().chan
+    }
+}
+
+impl<C> PartialEq for Sender<C> {
+    fn eq(&self, other: &Sender<C>) -> bool {
+        self.counter == other.counter
+    }
+}
+
+/// The receiving side.
+pub(crate) struct Receiver<C> {
+    counter: *mut Counter<C>,
+}
+
+impl<C> Receiver<C> {
+    /// Returns the internal `Counter`.
+    fn counter(&self) -> &Counter<C> {
+        unsafe { &*self.counter }
+    }
+
+    /// Acquires another receiver reference.
+    pub(crate) fn acquire(&self) -> Receiver<C> {
+        let count = self.counter().receivers.fetch_add(1, Ordering::Relaxed);
+
+        // Cloning receivers and calling `mem::forget` on the clones could potentially overflow the
+        // counter. It's very difficult to recover sensibly from such degenerate scenarios so we
+        // just abort when the count becomes very large.
+        if count > isize::MAX as usize {
+            process::abort();
+        }
+
+        Receiver { counter: self.counter }
+    }
+
+    /// Releases the receiver reference.
+    ///
+    /// Function `disconnect` will be called if this is the last receiver reference.
+    pub(crate) unsafe fn release<F: FnOnce(&C) -> bool>(&self, disconnect: F) {
+        if self.counter().receivers.fetch_sub(1, Ordering::AcqRel) == 1 {
+            disconnect(&self.counter().chan);
+
+            if self.counter().destroy.swap(true, Ordering::AcqRel) {
+                drop(Box::from_raw(self.counter));
+            }
+        }
+    }
+}
+
+impl<C> ops::Deref for Receiver<C> {
+    type Target = C;
+
+    fn deref(&self) -> &C {
+        &self.counter().chan
+    }
+}
+
+impl<C> PartialEq for Receiver<C> {
+    fn eq(&self, other: &Receiver<C>) -> bool {
+        self.counter == other.counter
+    }
+}
diff --git a/library/std/src/sync/mpmc/error.rs b/library/std/src/sync/mpmc/error.rs
new file mode 100644 (file)
index 0000000..1b8a1f3
--- /dev/null
@@ -0,0 +1,46 @@
+use crate::error;
+use crate::fmt;
+
+pub use crate::sync::mpsc::{RecvError, RecvTimeoutError, SendError, TryRecvError, TrySendError};
+
+/// An error returned from the [`send_timeout`] method.
+///
+/// The error contains the message being sent so it can be recovered.
+///
+/// [`send_timeout`]: super::Sender::send_timeout
+#[derive(PartialEq, Eq, Clone, Copy)]
+pub enum SendTimeoutError<T> {
+    /// The message could not be sent because the channel is full and the operation timed out.
+    ///
+    /// If this is a zero-capacity channel, then the error indicates that there was no receiver
+    /// available to receive the message and the operation timed out.
+    Timeout(T),
+
+    /// The message could not be sent because the channel is disconnected.
+    Disconnected(T),
+}
+
+impl<T> fmt::Debug for SendTimeoutError<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        "SendTimeoutError(..)".fmt(f)
+    }
+}
+
+impl<T> fmt::Display for SendTimeoutError<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match *self {
+            SendTimeoutError::Timeout(..) => "timed out waiting on send operation".fmt(f),
+            SendTimeoutError::Disconnected(..) => "sending on a disconnected channel".fmt(f),
+        }
+    }
+}
+
+impl<T: Send> error::Error for SendTimeoutError<T> {}
+
+impl<T> From<SendError<T>> for SendTimeoutError<T> {
+    fn from(err: SendError<T>) -> SendTimeoutError<T> {
+        match err {
+            SendError(e) => SendTimeoutError::Disconnected(e),
+        }
+    }
+}
diff --git a/library/std/src/sync/mpmc/list.rs b/library/std/src/sync/mpmc/list.rs
new file mode 100644 (file)
index 0000000..2d5b2fb
--- /dev/null
@@ -0,0 +1,638 @@
+//! Unbounded channel implemented as a linked list.
+
+use super::context::Context;
+use super::error::*;
+use super::select::{Operation, Selected, Token};
+use super::utils::{Backoff, CachePadded};
+use super::waker::SyncWaker;
+
+use crate::cell::UnsafeCell;
+use crate::marker::PhantomData;
+use crate::mem::MaybeUninit;
+use crate::ptr;
+use crate::sync::atomic::{self, AtomicPtr, AtomicUsize, Ordering};
+use crate::time::Instant;
+
+// Bits indicating the state of a slot:
+// * If a message has been written into the slot, `WRITE` is set.
+// * If a message has been read from the slot, `READ` is set.
+// * If the block is being destroyed, `DESTROY` is set.
+const WRITE: usize = 1;
+const READ: usize = 2;
+const DESTROY: usize = 4;
+
+// Each block covers one "lap" of indices.
+const LAP: usize = 32;
+// The maximum number of messages a block can hold.
+const BLOCK_CAP: usize = LAP - 1;
+// How many lower bits are reserved for metadata.
+const SHIFT: usize = 1;
+// Has two different purposes:
+// * If set in head, indicates that the block is not the last one.
+// * If set in tail, indicates that the channel is disconnected.
+const MARK_BIT: usize = 1;
+
+/// A slot in a block.
+struct Slot<T> {
+    /// The message.
+    msg: UnsafeCell<MaybeUninit<T>>,
+
+    /// The state of the slot.
+    state: AtomicUsize,
+}
+
+impl<T> Slot<T> {
+    /// Waits until a message is written into the slot.
+    fn wait_write(&self) {
+        let backoff = Backoff::new();
+        while self.state.load(Ordering::Acquire) & WRITE == 0 {
+            backoff.snooze();
+        }
+    }
+}
+
+/// A block in a linked list.
+///
+/// Each block in the list can hold up to `BLOCK_CAP` messages.
+struct Block<T> {
+    /// The next block in the linked list.
+    next: AtomicPtr<Block<T>>,
+
+    /// Slots for messages.
+    slots: [Slot<T>; BLOCK_CAP],
+}
+
+impl<T> Block<T> {
+    /// Creates an empty block.
+    fn new() -> Block<T> {
+        // SAFETY: This is safe because:
+        //  [1] `Block::next` (AtomicPtr) may be safely zero initialized.
+        //  [2] `Block::slots` (Array) may be safely zero initialized because of [3, 4].
+        //  [3] `Slot::msg` (UnsafeCell) may be safely zero initialized because it
+        //       holds a MaybeUninit.
+        //  [4] `Slot::state` (AtomicUsize) may be safely zero initialized.
+        unsafe { MaybeUninit::zeroed().assume_init() }
+    }
+
+    /// Waits until the next pointer is set.
+    fn wait_next(&self) -> *mut Block<T> {
+        let backoff = Backoff::new();
+        loop {
+            let next = self.next.load(Ordering::Acquire);
+            if !next.is_null() {
+                return next;
+            }
+            backoff.snooze();
+        }
+    }
+
+    /// Sets the `DESTROY` bit in slots starting from `start` and destroys the block.
+    unsafe fn destroy(this: *mut Block<T>, start: usize) {
+        // It is not necessary to set the `DESTROY` bit in the last slot because that slot has
+        // begun destruction of the block.
+        for i in start..BLOCK_CAP - 1 {
+            let slot = (*this).slots.get_unchecked(i);
+
+            // Mark the `DESTROY` bit if a thread is still using the slot.
+            if slot.state.load(Ordering::Acquire) & READ == 0
+                && slot.state.fetch_or(DESTROY, Ordering::AcqRel) & READ == 0
+            {
+                // If a thread is still using the slot, it will continue destruction of the block.
+                return;
+            }
+        }
+
+        // No thread is using the block, now it is safe to destroy it.
+        drop(Box::from_raw(this));
+    }
+}
+
+/// A position in a channel.
+#[derive(Debug)]
+struct Position<T> {
+    /// The index in the channel.
+    index: AtomicUsize,
+
+    /// The block in the linked list.
+    block: AtomicPtr<Block<T>>,
+}
+
+/// The token type for the list flavor.
+#[derive(Debug)]
+pub(crate) struct ListToken {
+    /// The block of slots.
+    block: *const u8,
+
+    /// The offset into the block.
+    offset: usize,
+}
+
+impl Default for ListToken {
+    #[inline]
+    fn default() -> Self {
+        ListToken { block: ptr::null(), offset: 0 }
+    }
+}
+
+/// Unbounded channel implemented as a linked list.
+///
+/// Each message sent into the channel is assigned a sequence number, i.e. an index. Indices are
+/// represented as numbers of type `usize` and wrap on overflow.
+///
+/// Consecutive messages are grouped into blocks in order to put less pressure on the allocator and
+/// improve cache efficiency.
+pub(crate) struct Channel<T> {
+    /// The head of the channel.
+    head: CachePadded<Position<T>>,
+
+    /// The tail of the channel.
+    tail: CachePadded<Position<T>>,
+
+    /// Receivers waiting while the channel is empty and not disconnected.
+    receivers: SyncWaker,
+
+    /// Indicates that dropping a `Channel<T>` may drop messages of type `T`.
+    _marker: PhantomData<T>,
+}
+
+impl<T> Channel<T> {
+    /// Creates a new unbounded channel.
+    pub(crate) fn new() -> Self {
+        Channel {
+            head: CachePadded::new(Position {
+                block: AtomicPtr::new(ptr::null_mut()),
+                index: AtomicUsize::new(0),
+            }),
+            tail: CachePadded::new(Position {
+                block: AtomicPtr::new(ptr::null_mut()),
+                index: AtomicUsize::new(0),
+            }),
+            receivers: SyncWaker::new(),
+            _marker: PhantomData,
+        }
+    }
+
+    /// Attempts to reserve a slot for sending a message.
+    fn start_send(&self, token: &mut Token) -> bool {
+        let backoff = Backoff::new();
+        let mut tail = self.tail.index.load(Ordering::Acquire);
+        let mut block = self.tail.block.load(Ordering::Acquire);
+        let mut next_block = None;
+
+        loop {
+            // Check if the channel is disconnected.
+            if tail & MARK_BIT != 0 {
+                token.list.block = ptr::null();
+                return true;
+            }
+
+            // Calculate the offset of the index into the block.
+            let offset = (tail >> SHIFT) % LAP;
+
+            // If we reached the end of the block, wait until the next one is installed.
+            if offset == BLOCK_CAP {
+                backoff.snooze();
+                tail = self.tail.index.load(Ordering::Acquire);
+                block = self.tail.block.load(Ordering::Acquire);
+                continue;
+            }
+
+            // If we're going to have to install the next block, allocate it in advance in order to
+            // make the wait for other threads as short as possible.
+            if offset + 1 == BLOCK_CAP && next_block.is_none() {
+                next_block = Some(Box::new(Block::<T>::new()));
+            }
+
+            // If this is the first message to be sent into the channel, we need to allocate the
+            // first block and install it.
+            if block.is_null() {
+                let new = Box::into_raw(Box::new(Block::<T>::new()));
+
+                if self
+                    .tail
+                    .block
+                    .compare_exchange(block, new, Ordering::Release, Ordering::Relaxed)
+                    .is_ok()
+                {
+                    self.head.block.store(new, Ordering::Release);
+                    block = new;
+                } else {
+                    next_block = unsafe { Some(Box::from_raw(new)) };
+                    tail = self.tail.index.load(Ordering::Acquire);
+                    block = self.tail.block.load(Ordering::Acquire);
+                    continue;
+                }
+            }
+
+            let new_tail = tail + (1 << SHIFT);
+
+            // Try advancing the tail forward.
+            match self.tail.index.compare_exchange_weak(
+                tail,
+                new_tail,
+                Ordering::SeqCst,
+                Ordering::Acquire,
+            ) {
+                Ok(_) => unsafe {
+                    // If we've reached the end of the block, install the next one.
+                    if offset + 1 == BLOCK_CAP {
+                        let next_block = Box::into_raw(next_block.unwrap());
+                        self.tail.block.store(next_block, Ordering::Release);
+                        self.tail.index.fetch_add(1 << SHIFT, Ordering::Release);
+                        (*block).next.store(next_block, Ordering::Release);
+                    }
+
+                    token.list.block = block as *const u8;
+                    token.list.offset = offset;
+                    return true;
+                },
+                Err(_) => {
+                    backoff.spin();
+                    tail = self.tail.index.load(Ordering::Acquire);
+                    block = self.tail.block.load(Ordering::Acquire);
+                }
+            }
+        }
+    }
+
+    /// Writes a message into the channel.
+    pub(crate) unsafe fn write(&self, token: &mut Token, msg: T) -> Result<(), T> {
+        // If there is no slot, the channel is disconnected.
+        if token.list.block.is_null() {
+            return Err(msg);
+        }
+
+        // Write the message into the slot.
+        let block = token.list.block as *mut Block<T>;
+        let offset = token.list.offset;
+        let slot = (*block).slots.get_unchecked(offset);
+        slot.msg.get().write(MaybeUninit::new(msg));
+        slot.state.fetch_or(WRITE, Ordering::Release);
+
+        // Wake a sleeping receiver.
+        self.receivers.notify();
+        Ok(())
+    }
+
+    /// Attempts to reserve a slot for receiving a message.
+    fn start_recv(&self, token: &mut Token) -> bool {
+        let backoff = Backoff::new();
+        let mut head = self.head.index.load(Ordering::Acquire);
+        let mut block = self.head.block.load(Ordering::Acquire);
+
+        loop {
+            // Calculate the offset of the index into the block.
+            let offset = (head >> SHIFT) % LAP;
+
+            // If we reached the end of the block, wait until the next one is installed.
+            if offset == BLOCK_CAP {
+                backoff.snooze();
+                head = self.head.index.load(Ordering::Acquire);
+                block = self.head.block.load(Ordering::Acquire);
+                continue;
+            }
+
+            let mut new_head = head + (1 << SHIFT);
+
+            if new_head & MARK_BIT == 0 {
+                atomic::fence(Ordering::SeqCst);
+                let tail = self.tail.index.load(Ordering::Relaxed);
+
+                // If the tail equals the head, that means the channel is empty.
+                if head >> SHIFT == tail >> SHIFT {
+                    // If the channel is disconnected...
+                    if tail & MARK_BIT != 0 {
+                        // ...then receive an error.
+                        token.list.block = ptr::null();
+                        return true;
+                    } else {
+                        // Otherwise, the receive operation is not ready.
+                        return false;
+                    }
+                }
+
+                // If head and tail are not in the same block, set `MARK_BIT` in head.
+                if (head >> SHIFT) / LAP != (tail >> SHIFT) / LAP {
+                    new_head |= MARK_BIT;
+                }
+            }
+
+            // The block can be null here only if the first message is being sent into the channel.
+            // In that case, just wait until it gets initialized.
+            if block.is_null() {
+                backoff.snooze();
+                head = self.head.index.load(Ordering::Acquire);
+                block = self.head.block.load(Ordering::Acquire);
+                continue;
+            }
+
+            // Try moving the head index forward.
+            match self.head.index.compare_exchange_weak(
+                head,
+                new_head,
+                Ordering::SeqCst,
+                Ordering::Acquire,
+            ) {
+                Ok(_) => unsafe {
+                    // If we've reached the end of the block, move to the next one.
+                    if offset + 1 == BLOCK_CAP {
+                        let next = (*block).wait_next();
+                        let mut next_index = (new_head & !MARK_BIT).wrapping_add(1 << SHIFT);
+                        if !(*next).next.load(Ordering::Relaxed).is_null() {
+                            next_index |= MARK_BIT;
+                        }
+
+                        self.head.block.store(next, Ordering::Release);
+                        self.head.index.store(next_index, Ordering::Release);
+                    }
+
+                    token.list.block = block as *const u8;
+                    token.list.offset = offset;
+                    return true;
+                },
+                Err(_) => {
+                    backoff.spin();
+                    head = self.head.index.load(Ordering::Acquire);
+                    block = self.head.block.load(Ordering::Acquire);
+                }
+            }
+        }
+    }
+
+    /// Reads a message from the channel.
+    pub(crate) unsafe fn read(&self, token: &mut Token) -> Result<T, ()> {
+        if token.list.block.is_null() {
+            // The channel is disconnected.
+            return Err(());
+        }
+
+        // Read the message.
+        let block = token.list.block as *mut Block<T>;
+        let offset = token.list.offset;
+        let slot = (*block).slots.get_unchecked(offset);
+        slot.wait_write();
+        let msg = slot.msg.get().read().assume_init();
+
+        // Destroy the block if we've reached the end, or if another thread wanted to destroy but
+        // couldn't because we were busy reading from the slot.
+        if offset + 1 == BLOCK_CAP {
+            Block::destroy(block, 0);
+        } else if slot.state.fetch_or(READ, Ordering::AcqRel) & DESTROY != 0 {
+            Block::destroy(block, offset + 1);
+        }
+
+        Ok(msg)
+    }
+
+    /// Attempts to send a message into the channel.
+    pub(crate) fn try_send(&self, msg: T) -> Result<(), TrySendError<T>> {
+        self.send(msg, None).map_err(|err| match err {
+            SendTimeoutError::Disconnected(msg) => TrySendError::Disconnected(msg),
+            SendTimeoutError::Timeout(_) => unreachable!(),
+        })
+    }
+
+    /// Sends a message into the channel.
+    pub(crate) fn send(
+        &self,
+        msg: T,
+        _deadline: Option<Instant>,
+    ) -> Result<(), SendTimeoutError<T>> {
+        let token = &mut Token::default();
+        assert!(self.start_send(token));
+        unsafe { self.write(token, msg).map_err(SendTimeoutError::Disconnected) }
+    }
+
+    /// Attempts to receive a message without blocking.
+    pub(crate) fn try_recv(&self) -> Result<T, TryRecvError> {
+        let token = &mut Token::default();
+
+        if self.start_recv(token) {
+            unsafe { self.read(token).map_err(|_| TryRecvError::Disconnected) }
+        } else {
+            Err(TryRecvError::Empty)
+        }
+    }
+
+    /// Receives a message from the channel.
+    pub(crate) fn recv(&self, deadline: Option<Instant>) -> Result<T, RecvTimeoutError> {
+        let token = &mut Token::default();
+        loop {
+            if self.start_recv(token) {
+                unsafe {
+                    return self.read(token).map_err(|_| RecvTimeoutError::Disconnected);
+                }
+            }
+
+            if let Some(d) = deadline {
+                if Instant::now() >= d {
+                    return Err(RecvTimeoutError::Timeout);
+                }
+            }
+
+            // Prepare for blocking until a sender wakes us up.
+            Context::with(|cx| {
+                let oper = Operation::hook(token);
+                self.receivers.register(oper, cx);
+
+                // Has the channel become ready just now?
+                if !self.is_empty() || self.is_disconnected() {
+                    let _ = cx.try_select(Selected::Aborted);
+                }
+
+                // Block the current thread.
+                let sel = cx.wait_until(deadline);
+
+                match sel {
+                    Selected::Waiting => unreachable!(),
+                    Selected::Aborted | Selected::Disconnected => {
+                        self.receivers.unregister(oper).unwrap();
+                        // If the channel was disconnected, we still have to check for remaining
+                        // messages.
+                    }
+                    Selected::Operation(_) => {}
+                }
+            });
+        }
+    }
+
+    /// Returns the current number of messages inside the channel.
+    pub(crate) fn len(&self) -> usize {
+        loop {
+            // Load the tail index, then load the head index.
+            let mut tail = self.tail.index.load(Ordering::SeqCst);
+            let mut head = self.head.index.load(Ordering::SeqCst);
+
+            // If the tail index didn't change, we've got consistent indices to work with.
+            if self.tail.index.load(Ordering::SeqCst) == tail {
+                // Erase the lower bits.
+                tail &= !((1 << SHIFT) - 1);
+                head &= !((1 << SHIFT) - 1);
+
+                // Fix up indices if they fall onto block ends.
+                if (tail >> SHIFT) & (LAP - 1) == LAP - 1 {
+                    tail = tail.wrapping_add(1 << SHIFT);
+                }
+                if (head >> SHIFT) & (LAP - 1) == LAP - 1 {
+                    head = head.wrapping_add(1 << SHIFT);
+                }
+
+                // Rotate indices so that head falls into the first block.
+                let lap = (head >> SHIFT) / LAP;
+                tail = tail.wrapping_sub((lap * LAP) << SHIFT);
+                head = head.wrapping_sub((lap * LAP) << SHIFT);
+
+                // Remove the lower bits.
+                tail >>= SHIFT;
+                head >>= SHIFT;
+
+                // Return the difference minus the number of blocks between tail and head.
+                return tail - head - tail / LAP;
+            }
+        }
+    }
+
+    /// Returns the capacity of the channel.
+    pub(crate) fn capacity(&self) -> Option<usize> {
+        None
+    }
+
+    /// Disconnects senders and wakes up all blocked receivers.
+    ///
+    /// Returns `true` if this call disconnected the channel.
+    pub(crate) fn disconnect_senders(&self) -> bool {
+        let tail = self.tail.index.fetch_or(MARK_BIT, Ordering::SeqCst);
+
+        if tail & MARK_BIT == 0 {
+            self.receivers.disconnect();
+            true
+        } else {
+            false
+        }
+    }
+
+    /// Disconnects receivers.
+    ///
+    /// Returns `true` if this call disconnected the channel.
+    pub(crate) fn disconnect_receivers(&self) -> bool {
+        let tail = self.tail.index.fetch_or(MARK_BIT, Ordering::SeqCst);
+
+        if tail & MARK_BIT == 0 {
+            // If receivers are dropped first, discard all messages to free
+            // memory eagerly.
+            self.discard_all_messages();
+            true
+        } else {
+            false
+        }
+    }
+
+    /// Discards all messages.
+    ///
+    /// This method should only be called when all receivers are dropped.
+    fn discard_all_messages(&self) {
+        let backoff = Backoff::new();
+        let mut tail = self.tail.index.load(Ordering::Acquire);
+        loop {
+            let offset = (tail >> SHIFT) % LAP;
+            if offset != BLOCK_CAP {
+                break;
+            }
+
+            // New updates to tail will be rejected by MARK_BIT and aborted unless it's
+            // at boundary. We need to wait for the updates take affect otherwise there
+            // can be memory leaks.
+            backoff.snooze();
+            tail = self.tail.index.load(Ordering::Acquire);
+        }
+
+        let mut head = self.head.index.load(Ordering::Acquire);
+        let mut block = self.head.block.load(Ordering::Acquire);
+
+        unsafe {
+            // Drop all messages between head and tail and deallocate the heap-allocated blocks.
+            while head >> SHIFT != tail >> SHIFT {
+                let offset = (head >> SHIFT) % LAP;
+
+                if offset < BLOCK_CAP {
+                    // Drop the message in the slot.
+                    let slot = (*block).slots.get_unchecked(offset);
+                    slot.wait_write();
+                    let p = &mut *slot.msg.get();
+                    p.as_mut_ptr().drop_in_place();
+                } else {
+                    (*block).wait_next();
+                    // Deallocate the block and move to the next one.
+                    let next = (*block).next.load(Ordering::Acquire);
+                    drop(Box::from_raw(block));
+                    block = next;
+                }
+
+                head = head.wrapping_add(1 << SHIFT);
+            }
+
+            // Deallocate the last remaining block.
+            if !block.is_null() {
+                drop(Box::from_raw(block));
+            }
+        }
+        head &= !MARK_BIT;
+        self.head.block.store(ptr::null_mut(), Ordering::Release);
+        self.head.index.store(head, Ordering::Release);
+    }
+
+    /// Returns `true` if the channel is disconnected.
+    pub(crate) fn is_disconnected(&self) -> bool {
+        self.tail.index.load(Ordering::SeqCst) & MARK_BIT != 0
+    }
+
+    /// Returns `true` if the channel is empty.
+    pub(crate) fn is_empty(&self) -> bool {
+        let head = self.head.index.load(Ordering::SeqCst);
+        let tail = self.tail.index.load(Ordering::SeqCst);
+        head >> SHIFT == tail >> SHIFT
+    }
+
+    /// Returns `true` if the channel is full.
+    pub(crate) fn is_full(&self) -> bool {
+        false
+    }
+}
+
+impl<T> Drop for Channel<T> {
+    fn drop(&mut self) {
+        let mut head = self.head.index.load(Ordering::Relaxed);
+        let mut tail = self.tail.index.load(Ordering::Relaxed);
+        let mut block = self.head.block.load(Ordering::Relaxed);
+
+        // Erase the lower bits.
+        head &= !((1 << SHIFT) - 1);
+        tail &= !((1 << SHIFT) - 1);
+
+        unsafe {
+            // Drop all messages between head and tail and deallocate the heap-allocated blocks.
+            while head != tail {
+                let offset = (head >> SHIFT) % LAP;
+
+                if offset < BLOCK_CAP {
+                    // Drop the message in the slot.
+                    let slot = (*block).slots.get_unchecked(offset);
+                    let p = &mut *slot.msg.get();
+                    p.as_mut_ptr().drop_in_place();
+                } else {
+                    // Deallocate the block and move to the next one.
+                    let next = (*block).next.load(Ordering::Relaxed);
+                    drop(Box::from_raw(block));
+                    block = next;
+                }
+
+                head = head.wrapping_add(1 << SHIFT);
+            }
+
+            // Deallocate the last remaining block.
+            if !block.is_null() {
+                drop(Box::from_raw(block));
+            }
+        }
+    }
+}
diff --git a/library/std/src/sync/mpmc/mod.rs b/library/std/src/sync/mpmc/mod.rs
new file mode 100644 (file)
index 0000000..cef99c5
--- /dev/null
@@ -0,0 +1,430 @@
+//! Multi-producer multi-consumer channels.
+
+// This module is not currently exposed publicly, but is used
+// as the implementation for the channels in `sync::mpsc`. The
+// implementation comes from the crossbeam-channel crate:
+//
+// Copyright (c) 2019 The Crossbeam Project Developers
+//
+// Permission is hereby granted, free of charge, to any
+// person obtaining a copy of this software and associated
+// documentation files (the "Software"), to deal in the
+// Software without restriction, including without
+// limitation the rights to use, copy, modify, merge,
+// publish, distribute, sublicense, and/or sell copies of
+// the Software, and to permit persons to whom the Software
+// is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice
+// shall be included in all copies or substantial portions
+// of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+
+mod array;
+mod context;
+mod counter;
+mod error;
+mod list;
+mod select;
+mod utils;
+mod waker;
+mod zero;
+
+use crate::fmt;
+use crate::panic::{RefUnwindSafe, UnwindSafe};
+use crate::time::{Duration, Instant};
+use error::*;
+
+/// Creates a channel of unbounded capacity.
+///
+/// This channel has a growable buffer that can hold any number of messages at a time.
+pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
+    let (s, r) = counter::new(list::Channel::new());
+    let s = Sender { flavor: SenderFlavor::List(s) };
+    let r = Receiver { flavor: ReceiverFlavor::List(r) };
+    (s, r)
+}
+
+/// Creates a channel of bounded capacity.
+///
+/// This channel has a buffer that can hold at most `cap` messages at a time.
+///
+/// A special case is zero-capacity channel, which cannot hold any messages. Instead, send and
+/// receive operations must appear at the same time in order to pair up and pass the message over.
+pub fn sync_channel<T>(cap: usize) -> (Sender<T>, Receiver<T>) {
+    if cap == 0 {
+        let (s, r) = counter::new(zero::Channel::new());
+        let s = Sender { flavor: SenderFlavor::Zero(s) };
+        let r = Receiver { flavor: ReceiverFlavor::Zero(r) };
+        (s, r)
+    } else {
+        let (s, r) = counter::new(array::Channel::with_capacity(cap));
+        let s = Sender { flavor: SenderFlavor::Array(s) };
+        let r = Receiver { flavor: ReceiverFlavor::Array(r) };
+        (s, r)
+    }
+}
+
+/// The sending side of a channel.
+pub struct Sender<T> {
+    flavor: SenderFlavor<T>,
+}
+
+/// Sender flavors.
+enum SenderFlavor<T> {
+    /// Bounded channel based on a preallocated array.
+    Array(counter::Sender<array::Channel<T>>),
+
+    /// Unbounded channel implemented as a linked list.
+    List(counter::Sender<list::Channel<T>>),
+
+    /// Zero-capacity channel.
+    Zero(counter::Sender<zero::Channel<T>>),
+}
+
+unsafe impl<T: Send> Send for Sender<T> {}
+unsafe impl<T: Send> Sync for Sender<T> {}
+
+impl<T> UnwindSafe for Sender<T> {}
+impl<T> RefUnwindSafe for Sender<T> {}
+
+impl<T> Sender<T> {
+    /// Attempts to send a message into the channel without blocking.
+    ///
+    /// This method will either send a message into the channel immediately or return an error if
+    /// the channel is full or disconnected. The returned error contains the original message.
+    ///
+    /// If called on a zero-capacity channel, this method will send the message only if there
+    /// happens to be a receive operation on the other side of the channel at the same time.
+    pub fn try_send(&self, msg: T) -> Result<(), TrySendError<T>> {
+        match &self.flavor {
+            SenderFlavor::Array(chan) => chan.try_send(msg),
+            SenderFlavor::List(chan) => chan.try_send(msg),
+            SenderFlavor::Zero(chan) => chan.try_send(msg),
+        }
+    }
+
+    /// Blocks the current thread until a message is sent or the channel is disconnected.
+    ///
+    /// If the channel is full and not disconnected, this call will block until the send operation
+    /// can proceed. If the channel becomes disconnected, this call will wake up and return an
+    /// error. The returned error contains the original message.
+    ///
+    /// If called on a zero-capacity channel, this method will wait for a receive operation to
+    /// appear on the other side of the channel.
+    pub fn send(&self, msg: T) -> Result<(), SendError<T>> {
+        match &self.flavor {
+            SenderFlavor::Array(chan) => chan.send(msg, None),
+            SenderFlavor::List(chan) => chan.send(msg, None),
+            SenderFlavor::Zero(chan) => chan.send(msg, None),
+        }
+        .map_err(|err| match err {
+            SendTimeoutError::Disconnected(msg) => SendError(msg),
+            SendTimeoutError::Timeout(_) => unreachable!(),
+        })
+    }
+}
+
+// The methods below are not used by `sync::mpsc`, but
+// are useful and we'll likely want to expose them
+// eventually
+#[allow(unused)]
+impl<T> Sender<T> {
+    /// Waits for a message to be sent into the channel, but only for a limited time.
+    ///
+    /// If the channel is full and not disconnected, this call will block until the send operation
+    /// can proceed or the operation times out. If the channel becomes disconnected, this call will
+    /// wake up and return an error. The returned error contains the original message.
+    ///
+    /// If called on a zero-capacity channel, this method will wait for a receive operation to
+    /// appear on the other side of the channel.
+    pub fn send_timeout(&self, msg: T, timeout: Duration) -> Result<(), SendTimeoutError<T>> {
+        match Instant::now().checked_add(timeout) {
+            Some(deadline) => self.send_deadline(msg, deadline),
+            // So far in the future that it's practically the same as waiting indefinitely.
+            None => self.send(msg).map_err(SendTimeoutError::from),
+        }
+    }
+
+    /// Waits for a message to be sent into the channel, but only until a given deadline.
+    ///
+    /// If the channel is full and not disconnected, this call will block until the send operation
+    /// can proceed or the operation times out. If the channel becomes disconnected, this call will
+    /// wake up and return an error. The returned error contains the original message.
+    ///
+    /// If called on a zero-capacity channel, this method will wait for a receive operation to
+    /// appear on the other side of the channel.
+    pub fn send_deadline(&self, msg: T, deadline: Instant) -> Result<(), SendTimeoutError<T>> {
+        match &self.flavor {
+            SenderFlavor::Array(chan) => chan.send(msg, Some(deadline)),
+            SenderFlavor::List(chan) => chan.send(msg, Some(deadline)),
+            SenderFlavor::Zero(chan) => chan.send(msg, Some(deadline)),
+        }
+    }
+
+    /// Returns `true` if the channel is empty.
+    ///
+    /// Note: Zero-capacity channels are always empty.
+    pub fn is_empty(&self) -> bool {
+        match &self.flavor {
+            SenderFlavor::Array(chan) => chan.is_empty(),
+            SenderFlavor::List(chan) => chan.is_empty(),
+            SenderFlavor::Zero(chan) => chan.is_empty(),
+        }
+    }
+
+    /// Returns `true` if the channel is full.
+    ///
+    /// Note: Zero-capacity channels are always full.
+    pub fn is_full(&self) -> bool {
+        match &self.flavor {
+            SenderFlavor::Array(chan) => chan.is_full(),
+            SenderFlavor::List(chan) => chan.is_full(),
+            SenderFlavor::Zero(chan) => chan.is_full(),
+        }
+    }
+
+    /// Returns the number of messages in the channel.
+    pub fn len(&self) -> usize {
+        match &self.flavor {
+            SenderFlavor::Array(chan) => chan.len(),
+            SenderFlavor::List(chan) => chan.len(),
+            SenderFlavor::Zero(chan) => chan.len(),
+        }
+    }
+
+    /// If the channel is bounded, returns its capacity.
+    pub fn capacity(&self) -> Option<usize> {
+        match &self.flavor {
+            SenderFlavor::Array(chan) => chan.capacity(),
+            SenderFlavor::List(chan) => chan.capacity(),
+            SenderFlavor::Zero(chan) => chan.capacity(),
+        }
+    }
+
+    /// Returns `true` if senders belong to the same channel.
+    pub fn same_channel(&self, other: &Sender<T>) -> bool {
+        match (&self.flavor, &other.flavor) {
+            (SenderFlavor::Array(ref a), SenderFlavor::Array(ref b)) => a == b,
+            (SenderFlavor::List(ref a), SenderFlavor::List(ref b)) => a == b,
+            (SenderFlavor::Zero(ref a), SenderFlavor::Zero(ref b)) => a == b,
+            _ => false,
+        }
+    }
+}
+
+impl<T> Drop for Sender<T> {
+    fn drop(&mut self) {
+        unsafe {
+            match &self.flavor {
+                SenderFlavor::Array(chan) => chan.release(|c| c.disconnect()),
+                SenderFlavor::List(chan) => chan.release(|c| c.disconnect_senders()),
+                SenderFlavor::Zero(chan) => chan.release(|c| c.disconnect()),
+            }
+        }
+    }
+}
+
+impl<T> Clone for Sender<T> {
+    fn clone(&self) -> Self {
+        let flavor = match &self.flavor {
+            SenderFlavor::Array(chan) => SenderFlavor::Array(chan.acquire()),
+            SenderFlavor::List(chan) => SenderFlavor::List(chan.acquire()),
+            SenderFlavor::Zero(chan) => SenderFlavor::Zero(chan.acquire()),
+        };
+
+        Sender { flavor }
+    }
+}
+
+impl<T> fmt::Debug for Sender<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.pad("Sender { .. }")
+    }
+}
+
+/// The receiving side of a channel.
+pub struct Receiver<T> {
+    flavor: ReceiverFlavor<T>,
+}
+
+/// Receiver flavors.
+enum ReceiverFlavor<T> {
+    /// Bounded channel based on a preallocated array.
+    Array(counter::Receiver<array::Channel<T>>),
+
+    /// Unbounded channel implemented as a linked list.
+    List(counter::Receiver<list::Channel<T>>),
+
+    /// Zero-capacity channel.
+    Zero(counter::Receiver<zero::Channel<T>>),
+}
+
+unsafe impl<T: Send> Send for Receiver<T> {}
+unsafe impl<T: Send> Sync for Receiver<T> {}
+
+impl<T> UnwindSafe for Receiver<T> {}
+impl<T> RefUnwindSafe for Receiver<T> {}
+
+impl<T> Receiver<T> {
+    /// Attempts to receive a message from the channel without blocking.
+    ///
+    /// This method will either receive a message from the channel immediately or return an error
+    /// if the channel is empty.
+    ///
+    /// If called on a zero-capacity channel, this method will receive a message only if there
+    /// happens to be a send operation on the other side of the channel at the same time.
+    pub fn try_recv(&self) -> Result<T, TryRecvError> {
+        match &self.flavor {
+            ReceiverFlavor::Array(chan) => chan.try_recv(),
+            ReceiverFlavor::List(chan) => chan.try_recv(),
+            ReceiverFlavor::Zero(chan) => chan.try_recv(),
+        }
+    }
+
+    /// Blocks the current thread until a message is received or the channel is empty and
+    /// disconnected.
+    ///
+    /// If the channel is empty and not disconnected, this call will block until the receive
+    /// operation can proceed. If the channel is empty and becomes disconnected, this call will
+    /// wake up and return an error.
+    ///
+    /// If called on a zero-capacity channel, this method will wait for a send operation to appear
+    /// on the other side of the channel.
+    pub fn recv(&self) -> Result<T, RecvError> {
+        match &self.flavor {
+            ReceiverFlavor::Array(chan) => chan.recv(None),
+            ReceiverFlavor::List(chan) => chan.recv(None),
+            ReceiverFlavor::Zero(chan) => chan.recv(None),
+        }
+        .map_err(|_| RecvError)
+    }
+
+    /// Waits for a message to be received from the channel, but only for a limited time.
+    ///
+    /// If the channel is empty and not disconnected, this call will block until the receive
+    /// operation can proceed or the operation times out. If the channel is empty and becomes
+    /// disconnected, this call will wake up and return an error.
+    ///
+    /// If called on a zero-capacity channel, this method will wait for a send operation to appear
+    /// on the other side of the channel.
+    pub fn recv_timeout(&self, timeout: Duration) -> Result<T, RecvTimeoutError> {
+        match Instant::now().checked_add(timeout) {
+            Some(deadline) => self.recv_deadline(deadline),
+            // So far in the future that it's practically the same as waiting indefinitely.
+            None => self.recv().map_err(RecvTimeoutError::from),
+        }
+    }
+
+    /// Waits for a message to be received from the channel, but only for a limited time.
+    ///
+    /// If the channel is empty and not disconnected, this call will block until the receive
+    /// operation can proceed or the operation times out. If the channel is empty and becomes
+    /// disconnected, this call will wake up and return an error.
+    ///
+    /// If called on a zero-capacity channel, this method will wait for a send operation to appear
+    /// on the other side of the channel.
+    pub fn recv_deadline(&self, deadline: Instant) -> Result<T, RecvTimeoutError> {
+        match &self.flavor {
+            ReceiverFlavor::Array(chan) => chan.recv(Some(deadline)),
+            ReceiverFlavor::List(chan) => chan.recv(Some(deadline)),
+            ReceiverFlavor::Zero(chan) => chan.recv(Some(deadline)),
+        }
+    }
+}
+
+// The methods below are not used by `sync::mpsc`, but
+// are useful and we'll likely want to expose them
+// eventually
+#[allow(unused)]
+impl<T> Receiver<T> {
+    /// Returns `true` if the channel is empty.
+    ///
+    /// Note: Zero-capacity channels are always empty.
+    pub fn is_empty(&self) -> bool {
+        match &self.flavor {
+            ReceiverFlavor::Array(chan) => chan.is_empty(),
+            ReceiverFlavor::List(chan) => chan.is_empty(),
+            ReceiverFlavor::Zero(chan) => chan.is_empty(),
+        }
+    }
+
+    /// Returns `true` if the channel is full.
+    ///
+    /// Note: Zero-capacity channels are always full.
+    pub fn is_full(&self) -> bool {
+        match &self.flavor {
+            ReceiverFlavor::Array(chan) => chan.is_full(),
+            ReceiverFlavor::List(chan) => chan.is_full(),
+            ReceiverFlavor::Zero(chan) => chan.is_full(),
+        }
+    }
+
+    /// Returns the number of messages in the channel.
+    pub fn len(&self) -> usize {
+        match &self.flavor {
+            ReceiverFlavor::Array(chan) => chan.len(),
+            ReceiverFlavor::List(chan) => chan.len(),
+            ReceiverFlavor::Zero(chan) => chan.len(),
+        }
+    }
+
+    /// If the channel is bounded, returns its capacity.
+    pub fn capacity(&self) -> Option<usize> {
+        match &self.flavor {
+            ReceiverFlavor::Array(chan) => chan.capacity(),
+            ReceiverFlavor::List(chan) => chan.capacity(),
+            ReceiverFlavor::Zero(chan) => chan.capacity(),
+        }
+    }
+
+    /// Returns `true` if receivers belong to the same channel.
+    pub fn same_channel(&self, other: &Receiver<T>) -> bool {
+        match (&self.flavor, &other.flavor) {
+            (ReceiverFlavor::Array(a), ReceiverFlavor::Array(b)) => a == b,
+            (ReceiverFlavor::List(a), ReceiverFlavor::List(b)) => a == b,
+            (ReceiverFlavor::Zero(a), ReceiverFlavor::Zero(b)) => a == b,
+            _ => false,
+        }
+    }
+}
+
+impl<T> Drop for Receiver<T> {
+    fn drop(&mut self) {
+        unsafe {
+            match &self.flavor {
+                ReceiverFlavor::Array(chan) => chan.release(|c| c.disconnect()),
+                ReceiverFlavor::List(chan) => chan.release(|c| c.disconnect_receivers()),
+                ReceiverFlavor::Zero(chan) => chan.release(|c| c.disconnect()),
+            }
+        }
+    }
+}
+
+impl<T> Clone for Receiver<T> {
+    fn clone(&self) -> Self {
+        let flavor = match &self.flavor {
+            ReceiverFlavor::Array(chan) => ReceiverFlavor::Array(chan.acquire()),
+            ReceiverFlavor::List(chan) => ReceiverFlavor::List(chan.acquire()),
+            ReceiverFlavor::Zero(chan) => ReceiverFlavor::Zero(chan.acquire()),
+        };
+
+        Receiver { flavor }
+    }
+}
+
+impl<T> fmt::Debug for Receiver<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.pad("Receiver { .. }")
+    }
+}
diff --git a/library/std/src/sync/mpmc/select.rs b/library/std/src/sync/mpmc/select.rs
new file mode 100644 (file)
index 0000000..56a83fe
--- /dev/null
@@ -0,0 +1,71 @@
+/// Temporary data that gets initialized during a blocking operation, and is consumed by
+/// `read` or `write`.
+///
+/// Each field contains data associated with a specific channel flavor.
+#[derive(Debug, Default)]
+pub struct Token {
+    pub(crate) array: super::array::ArrayToken,
+    pub(crate) list: super::list::ListToken,
+    #[allow(dead_code)]
+    pub(crate) zero: super::zero::ZeroToken,
+}
+
+/// Identifier associated with an operation by a specific thread on a specific channel.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct Operation(usize);
+
+impl Operation {
+    /// Creates an operation identifier from a mutable reference.
+    ///
+    /// This function essentially just turns the address of the reference into a number. The
+    /// reference should point to a variable that is specific to the thread and the operation,
+    /// and is alive for the entire duration of a blocking operation.
+    #[inline]
+    pub fn hook<T>(r: &mut T) -> Operation {
+        let val = r as *mut T as usize;
+        // Make sure that the pointer address doesn't equal the numerical representation of
+        // `Selected::{Waiting, Aborted, Disconnected}`.
+        assert!(val > 2);
+        Operation(val)
+    }
+}
+
+/// Current state of a blocking operation.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum Selected {
+    /// Still waiting for an operation.
+    Waiting,
+
+    /// The attempt to block the current thread has been aborted.
+    Aborted,
+
+    /// An operation became ready because a channel is disconnected.
+    Disconnected,
+
+    /// An operation became ready because a message can be sent or received.
+    Operation(Operation),
+}
+
+impl From<usize> for Selected {
+    #[inline]
+    fn from(val: usize) -> Selected {
+        match val {
+            0 => Selected::Waiting,
+            1 => Selected::Aborted,
+            2 => Selected::Disconnected,
+            oper => Selected::Operation(Operation(oper)),
+        }
+    }
+}
+
+impl Into<usize> for Selected {
+    #[inline]
+    fn into(self) -> usize {
+        match self {
+            Selected::Waiting => 0,
+            Selected::Aborted => 1,
+            Selected::Disconnected => 2,
+            Selected::Operation(Operation(val)) => val,
+        }
+    }
+}
diff --git a/library/std/src/sync/mpmc/utils.rs b/library/std/src/sync/mpmc/utils.rs
new file mode 100644 (file)
index 0000000..d0904b4
--- /dev/null
@@ -0,0 +1,144 @@
+use crate::cell::Cell;
+use crate::ops::{Deref, DerefMut};
+
+/// Pads and aligns a value to the length of a cache line.
+#[derive(Clone, Copy, Default, Hash, PartialEq, Eq)]
+// Starting from Intel's Sandy Bridge, spatial prefetcher is now pulling pairs of 64-byte cache
+// lines at a time, so we have to align to 128 bytes rather than 64.
+//
+// Sources:
+// - https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-optimization-manual.pdf
+// - https://github.com/facebook/folly/blob/1b5288e6eea6df074758f877c849b6e73bbb9fbb/folly/lang/Align.h#L107
+//
+// ARM's big.LITTLE architecture has asymmetric cores and "big" cores have 128-byte cache line size.
+//
+// Sources:
+// - https://www.mono-project.com/news/2016/09/12/arm64-icache/
+//
+// powerpc64 has 128-byte cache line size.
+//
+// Sources:
+// - https://github.com/golang/go/blob/3dd58676054223962cd915bb0934d1f9f489d4d2/src/internal/cpu/cpu_ppc64x.go#L9
+#[cfg_attr(
+    any(target_arch = "x86_64", target_arch = "aarch64", target_arch = "powerpc64",),
+    repr(align(128))
+)]
+// arm, mips, mips64, and riscv64 have 32-byte cache line size.
+//
+// Sources:
+// - https://github.com/golang/go/blob/3dd58676054223962cd915bb0934d1f9f489d4d2/src/internal/cpu/cpu_arm.go#L7
+// - https://github.com/golang/go/blob/3dd58676054223962cd915bb0934d1f9f489d4d2/src/internal/cpu/cpu_mips.go#L7
+// - https://github.com/golang/go/blob/3dd58676054223962cd915bb0934d1f9f489d4d2/src/internal/cpu/cpu_mipsle.go#L7
+// - https://github.com/golang/go/blob/3dd58676054223962cd915bb0934d1f9f489d4d2/src/internal/cpu/cpu_mips64x.go#L9
+// - https://github.com/golang/go/blob/3dd58676054223962cd915bb0934d1f9f489d4d2/src/internal/cpu/cpu_riscv64.go#L7
+#[cfg_attr(
+    any(
+        target_arch = "arm",
+        target_arch = "mips",
+        target_arch = "mips64",
+        target_arch = "riscv64",
+    ),
+    repr(align(32))
+)]
+// s390x has 256-byte cache line size.
+//
+// Sources:
+// - https://github.com/golang/go/blob/3dd58676054223962cd915bb0934d1f9f489d4d2/src/internal/cpu/cpu_s390x.go#L7
+#[cfg_attr(target_arch = "s390x", repr(align(256)))]
+// x86 and wasm have 64-byte cache line size.
+//
+// Sources:
+// - https://github.com/golang/go/blob/dda2991c2ea0c5914714469c4defc2562a907230/src/internal/cpu/cpu_x86.go#L9
+// - https://github.com/golang/go/blob/3dd58676054223962cd915bb0934d1f9f489d4d2/src/internal/cpu/cpu_wasm.go#L7
+//
+// All others are assumed to have 64-byte cache line size.
+#[cfg_attr(
+    not(any(
+        target_arch = "x86_64",
+        target_arch = "aarch64",
+        target_arch = "powerpc64",
+        target_arch = "arm",
+        target_arch = "mips",
+        target_arch = "mips64",
+        target_arch = "riscv64",
+        target_arch = "s390x",
+    )),
+    repr(align(64))
+)]
+pub struct CachePadded<T> {
+    value: T,
+}
+
+impl<T> CachePadded<T> {
+    /// Pads and aligns a value to the length of a cache line.
+    pub fn new(value: T) -> CachePadded<T> {
+        CachePadded::<T> { value }
+    }
+}
+
+impl<T> Deref for CachePadded<T> {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        &self.value
+    }
+}
+
+impl<T> DerefMut for CachePadded<T> {
+    fn deref_mut(&mut self) -> &mut T {
+        &mut self.value
+    }
+}
+
+const SPIN_LIMIT: u32 = 6;
+const YIELD_LIMIT: u32 = 10;
+
+/// Performs exponential backoff in spin loops.
+pub struct Backoff {
+    step: Cell<u32>,
+}
+
+impl Backoff {
+    /// Creates a new `Backoff`.
+    pub fn new() -> Self {
+        Backoff { step: Cell::new(0) }
+    }
+
+    /// Backs off in a lock-free loop.
+    ///
+    /// This method should be used when we need to retry an operation because another thread made
+    /// progress.
+    #[inline]
+    pub fn spin(&self) {
+        let step = self.step.get().min(SPIN_LIMIT);
+        for _ in 0..step.pow(2) {
+            crate::hint::spin_loop();
+        }
+
+        if self.step.get() <= SPIN_LIMIT {
+            self.step.set(self.step.get() + 1);
+        }
+    }
+
+    /// Backs off in a blocking loop.
+    #[inline]
+    pub fn snooze(&self) {
+        if self.step.get() <= SPIN_LIMIT {
+            for _ in 0..self.step.get().pow(2) {
+                crate::hint::spin_loop()
+            }
+        } else {
+            crate::thread::yield_now();
+        }
+
+        if self.step.get() <= YIELD_LIMIT {
+            self.step.set(self.step.get() + 1);
+        }
+    }
+
+    /// Returns `true` if exponential backoff has completed and blocking the thread is advised.
+    #[inline]
+    pub fn is_completed(&self) -> bool {
+        self.step.get() > YIELD_LIMIT
+    }
+}
diff --git a/library/std/src/sync/mpmc/waker.rs b/library/std/src/sync/mpmc/waker.rs
new file mode 100644 (file)
index 0000000..4912ca4
--- /dev/null
@@ -0,0 +1,204 @@
+//! Waking mechanism for threads blocked on channel operations.
+
+use super::context::Context;
+use super::select::{Operation, Selected};
+
+use crate::ptr;
+use crate::sync::atomic::{AtomicBool, Ordering};
+use crate::sync::Mutex;
+
+/// Represents a thread blocked on a specific channel operation.
+pub(crate) struct Entry {
+    /// The operation.
+    pub(crate) oper: Operation,
+
+    /// Optional packet.
+    pub(crate) packet: *mut (),
+
+    /// Context associated with the thread owning this operation.
+    pub(crate) cx: Context,
+}
+
+/// A queue of threads blocked on channel operations.
+///
+/// This data structure is used by threads to register blocking operations and get woken up once
+/// an operation becomes ready.
+pub(crate) struct Waker {
+    /// A list of select operations.
+    selectors: Vec<Entry>,
+
+    /// A list of operations waiting to be ready.
+    observers: Vec<Entry>,
+}
+
+impl Waker {
+    /// Creates a new `Waker`.
+    #[inline]
+    pub(crate) fn new() -> Self {
+        Waker { selectors: Vec::new(), observers: Vec::new() }
+    }
+
+    /// Registers a select operation.
+    #[inline]
+    pub(crate) fn register(&mut self, oper: Operation, cx: &Context) {
+        self.register_with_packet(oper, ptr::null_mut(), cx);
+    }
+
+    /// Registers a select operation and a packet.
+    #[inline]
+    pub(crate) fn register_with_packet(&mut self, oper: Operation, packet: *mut (), cx: &Context) {
+        self.selectors.push(Entry { oper, packet, cx: cx.clone() });
+    }
+
+    /// Unregisters a select operation.
+    #[inline]
+    pub(crate) fn unregister(&mut self, oper: Operation) -> Option<Entry> {
+        if let Some((i, _)) =
+            self.selectors.iter().enumerate().find(|&(_, entry)| entry.oper == oper)
+        {
+            let entry = self.selectors.remove(i);
+            Some(entry)
+        } else {
+            None
+        }
+    }
+
+    /// Attempts to find another thread's entry, select the operation, and wake it up.
+    #[inline]
+    pub(crate) fn try_select(&mut self) -> Option<Entry> {
+        self.selectors
+            .iter()
+            .position(|selector| {
+                // Does the entry belong to a different thread?
+                selector.cx.thread_id() != current_thread_id()
+                    && selector // Try selecting this operation.
+                        .cx
+                        .try_select(Selected::Operation(selector.oper))
+                        .is_ok()
+                    && {
+                        // Provide the packet.
+                        selector.cx.store_packet(selector.packet);
+                        // Wake the thread up.
+                        selector.cx.unpark();
+                        true
+                    }
+            })
+            // Remove the entry from the queue to keep it clean and improve
+            // performance.
+            .map(|pos| self.selectors.remove(pos))
+    }
+
+    /// Notifies all operations waiting to be ready.
+    #[inline]
+    pub(crate) fn notify(&mut self) {
+        for entry in self.observers.drain(..) {
+            if entry.cx.try_select(Selected::Operation(entry.oper)).is_ok() {
+                entry.cx.unpark();
+            }
+        }
+    }
+
+    /// Notifies all registered operations that the channel is disconnected.
+    #[inline]
+    pub(crate) fn disconnect(&mut self) {
+        for entry in self.selectors.iter() {
+            if entry.cx.try_select(Selected::Disconnected).is_ok() {
+                // Wake the thread up.
+                //
+                // Here we don't remove the entry from the queue. Registered threads must
+                // unregister from the waker by themselves. They might also want to recover the
+                // packet value and destroy it, if necessary.
+                entry.cx.unpark();
+            }
+        }
+
+        self.notify();
+    }
+}
+
+impl Drop for Waker {
+    #[inline]
+    fn drop(&mut self) {
+        debug_assert_eq!(self.selectors.len(), 0);
+        debug_assert_eq!(self.observers.len(), 0);
+    }
+}
+
+/// A waker that can be shared among threads without locking.
+///
+/// This is a simple wrapper around `Waker` that internally uses a mutex for synchronization.
+pub(crate) struct SyncWaker {
+    /// The inner `Waker`.
+    inner: Mutex<Waker>,
+
+    /// `true` if the waker is empty.
+    is_empty: AtomicBool,
+}
+
+impl SyncWaker {
+    /// Creates a new `SyncWaker`.
+    #[inline]
+    pub(crate) fn new() -> Self {
+        SyncWaker { inner: Mutex::new(Waker::new()), is_empty: AtomicBool::new(true) }
+    }
+
+    /// Registers the current thread with an operation.
+    #[inline]
+    pub(crate) fn register(&self, oper: Operation, cx: &Context) {
+        let mut inner = self.inner.lock().unwrap();
+        inner.register(oper, cx);
+        self.is_empty
+            .store(inner.selectors.is_empty() && inner.observers.is_empty(), Ordering::SeqCst);
+    }
+
+    /// Unregisters an operation previously registered by the current thread.
+    #[inline]
+    pub(crate) fn unregister(&self, oper: Operation) -> Option<Entry> {
+        let mut inner = self.inner.lock().unwrap();
+        let entry = inner.unregister(oper);
+        self.is_empty
+            .store(inner.selectors.is_empty() && inner.observers.is_empty(), Ordering::SeqCst);
+        entry
+    }
+
+    /// Attempts to find one thread (not the current one), select its operation, and wake it up.
+    #[inline]
+    pub(crate) fn notify(&self) {
+        if !self.is_empty.load(Ordering::SeqCst) {
+            let mut inner = self.inner.lock().unwrap();
+            if !self.is_empty.load(Ordering::SeqCst) {
+                inner.try_select();
+                inner.notify();
+                self.is_empty.store(
+                    inner.selectors.is_empty() && inner.observers.is_empty(),
+                    Ordering::SeqCst,
+                );
+            }
+        }
+    }
+
+    /// Notifies all threads that the channel is disconnected.
+    #[inline]
+    pub(crate) fn disconnect(&self) {
+        let mut inner = self.inner.lock().unwrap();
+        inner.disconnect();
+        self.is_empty
+            .store(inner.selectors.is_empty() && inner.observers.is_empty(), Ordering::SeqCst);
+    }
+}
+
+impl Drop for SyncWaker {
+    #[inline]
+    fn drop(&mut self) {
+        debug_assert!(self.is_empty.load(Ordering::SeqCst));
+    }
+}
+
+/// Returns a unique id for the current thread.
+#[inline]
+pub fn current_thread_id() -> usize {
+    // `u8` is not drop so this variable will be available during thread destruction,
+    // whereas `thread::current()` would not be
+    thread_local! { static DUMMY: u8 = 0 }
+    DUMMY.with(|x| (x as *const u8).addr())
+}
diff --git a/library/std/src/sync/mpmc/zero.rs b/library/std/src/sync/mpmc/zero.rs
new file mode 100644 (file)
index 0000000..fccd6c2
--- /dev/null
@@ -0,0 +1,318 @@
+//! Zero-capacity channel.
+//!
+//! This kind of channel is also known as *rendezvous* channel.
+
+use super::context::Context;
+use super::error::*;
+use super::select::{Operation, Selected, Token};
+use super::utils::Backoff;
+use super::waker::Waker;
+
+use crate::cell::UnsafeCell;
+use crate::marker::PhantomData;
+use crate::sync::atomic::{AtomicBool, Ordering};
+use crate::sync::Mutex;
+use crate::time::Instant;
+use crate::{fmt, ptr};
+
+/// A pointer to a packet.
+pub(crate) struct ZeroToken(*mut ());
+
+impl Default for ZeroToken {
+    fn default() -> Self {
+        Self(ptr::null_mut())
+    }
+}
+
+impl fmt::Debug for ZeroToken {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Debug::fmt(&(self.0 as usize), f)
+    }
+}
+
+/// A slot for passing one message from a sender to a receiver.
+struct Packet<T> {
+    /// Equals `true` if the packet is allocated on the stack.
+    on_stack: bool,
+
+    /// Equals `true` once the packet is ready for reading or writing.
+    ready: AtomicBool,
+
+    /// The message.
+    msg: UnsafeCell<Option<T>>,
+}
+
+impl<T> Packet<T> {
+    /// Creates an empty packet on the stack.
+    fn empty_on_stack() -> Packet<T> {
+        Packet { on_stack: true, ready: AtomicBool::new(false), msg: UnsafeCell::new(None) }
+    }
+
+    /// Creates a packet on the stack, containing a message.
+    fn message_on_stack(msg: T) -> Packet<T> {
+        Packet { on_stack: true, ready: AtomicBool::new(false), msg: UnsafeCell::new(Some(msg)) }
+    }
+
+    /// Waits until the packet becomes ready for reading or writing.
+    fn wait_ready(&self) {
+        let backoff = Backoff::new();
+        while !self.ready.load(Ordering::Acquire) {
+            backoff.snooze();
+        }
+    }
+}
+
+/// Inner representation of a zero-capacity channel.
+struct Inner {
+    /// Senders waiting to pair up with a receive operation.
+    senders: Waker,
+
+    /// Receivers waiting to pair up with a send operation.
+    receivers: Waker,
+
+    /// Equals `true` when the channel is disconnected.
+    is_disconnected: bool,
+}
+
+/// Zero-capacity channel.
+pub(crate) struct Channel<T> {
+    /// Inner representation of the channel.
+    inner: Mutex<Inner>,
+
+    /// Indicates that dropping a `Channel<T>` may drop values of type `T`.
+    _marker: PhantomData<T>,
+}
+
+impl<T> Channel<T> {
+    /// Constructs a new zero-capacity channel.
+    pub(crate) fn new() -> Self {
+        Channel {
+            inner: Mutex::new(Inner {
+                senders: Waker::new(),
+                receivers: Waker::new(),
+                is_disconnected: false,
+            }),
+            _marker: PhantomData,
+        }
+    }
+
+    /// Writes a message into the packet.
+    pub(crate) unsafe fn write(&self, token: &mut Token, msg: T) -> Result<(), T> {
+        // If there is no packet, the channel is disconnected.
+        if token.zero.0.is_null() {
+            return Err(msg);
+        }
+
+        let packet = &*(token.zero.0 as *const Packet<T>);
+        packet.msg.get().write(Some(msg));
+        packet.ready.store(true, Ordering::Release);
+        Ok(())
+    }
+
+    /// Reads a message from the packet.
+    pub(crate) unsafe fn read(&self, token: &mut Token) -> Result<T, ()> {
+        // If there is no packet, the channel is disconnected.
+        if token.zero.0.is_null() {
+            return Err(());
+        }
+
+        let packet = &*(token.zero.0 as *const Packet<T>);
+
+        if packet.on_stack {
+            // The message has been in the packet from the beginning, so there is no need to wait
+            // for it. However, after reading the message, we need to set `ready` to `true` in
+            // order to signal that the packet can be destroyed.
+            let msg = packet.msg.get().replace(None).unwrap();
+            packet.ready.store(true, Ordering::Release);
+            Ok(msg)
+        } else {
+            // Wait until the message becomes available, then read it and destroy the
+            // heap-allocated packet.
+            packet.wait_ready();
+            let msg = packet.msg.get().replace(None).unwrap();
+            drop(Box::from_raw(token.zero.0 as *mut Packet<T>));
+            Ok(msg)
+        }
+    }
+
+    /// Attempts to send a message into the channel.
+    pub(crate) fn try_send(&self, msg: T) -> Result<(), TrySendError<T>> {
+        let token = &mut Token::default();
+        let mut inner = self.inner.lock().unwrap();
+
+        // If there's a waiting receiver, pair up with it.
+        if let Some(operation) = inner.receivers.try_select() {
+            token.zero.0 = operation.packet;
+            drop(inner);
+            unsafe {
+                self.write(token, msg).ok().unwrap();
+            }
+            Ok(())
+        } else if inner.is_disconnected {
+            Err(TrySendError::Disconnected(msg))
+        } else {
+            Err(TrySendError::Full(msg))
+        }
+    }
+
+    /// Sends a message into the channel.
+    pub(crate) fn send(
+        &self,
+        msg: T,
+        deadline: Option<Instant>,
+    ) -> Result<(), SendTimeoutError<T>> {
+        let token = &mut Token::default();
+        let mut inner = self.inner.lock().unwrap();
+
+        // If there's a waiting receiver, pair up with it.
+        if let Some(operation) = inner.receivers.try_select() {
+            token.zero.0 = operation.packet;
+            drop(inner);
+            unsafe {
+                self.write(token, msg).ok().unwrap();
+            }
+            return Ok(());
+        }
+
+        if inner.is_disconnected {
+            return Err(SendTimeoutError::Disconnected(msg));
+        }
+
+        Context::with(|cx| {
+            // Prepare for blocking until a receiver wakes us up.
+            let oper = Operation::hook(token);
+            let mut packet = Packet::<T>::message_on_stack(msg);
+            inner.senders.register_with_packet(oper, &mut packet as *mut Packet<T> as *mut (), cx);
+            inner.receivers.notify();
+            drop(inner);
+
+            // Block the current thread.
+            let sel = cx.wait_until(deadline);
+
+            match sel {
+                Selected::Waiting => unreachable!(),
+                Selected::Aborted => {
+                    self.inner.lock().unwrap().senders.unregister(oper).unwrap();
+                    let msg = unsafe { packet.msg.get().replace(None).unwrap() };
+                    Err(SendTimeoutError::Timeout(msg))
+                }
+                Selected::Disconnected => {
+                    self.inner.lock().unwrap().senders.unregister(oper).unwrap();
+                    let msg = unsafe { packet.msg.get().replace(None).unwrap() };
+                    Err(SendTimeoutError::Disconnected(msg))
+                }
+                Selected::Operation(_) => {
+                    // Wait until the message is read, then drop the packet.
+                    packet.wait_ready();
+                    Ok(())
+                }
+            }
+        })
+    }
+
+    /// Attempts to receive a message without blocking.
+    pub(crate) fn try_recv(&self) -> Result<T, TryRecvError> {
+        let token = &mut Token::default();
+        let mut inner = self.inner.lock().unwrap();
+
+        // If there's a waiting sender, pair up with it.
+        if let Some(operation) = inner.senders.try_select() {
+            token.zero.0 = operation.packet;
+            drop(inner);
+            unsafe { self.read(token).map_err(|_| TryRecvError::Disconnected) }
+        } else if inner.is_disconnected {
+            Err(TryRecvError::Disconnected)
+        } else {
+            Err(TryRecvError::Empty)
+        }
+    }
+
+    /// Receives a message from the channel.
+    pub(crate) fn recv(&self, deadline: Option<Instant>) -> Result<T, RecvTimeoutError> {
+        let token = &mut Token::default();
+        let mut inner = self.inner.lock().unwrap();
+
+        // If there's a waiting sender, pair up with it.
+        if let Some(operation) = inner.senders.try_select() {
+            token.zero.0 = operation.packet;
+            drop(inner);
+            unsafe {
+                return self.read(token).map_err(|_| RecvTimeoutError::Disconnected);
+            }
+        }
+
+        if inner.is_disconnected {
+            return Err(RecvTimeoutError::Disconnected);
+        }
+
+        Context::with(|cx| {
+            // Prepare for blocking until a sender wakes us up.
+            let oper = Operation::hook(token);
+            let mut packet = Packet::<T>::empty_on_stack();
+            inner.receivers.register_with_packet(
+                oper,
+                &mut packet as *mut Packet<T> as *mut (),
+                cx,
+            );
+            inner.senders.notify();
+            drop(inner);
+
+            // Block the current thread.
+            let sel = cx.wait_until(deadline);
+
+            match sel {
+                Selected::Waiting => unreachable!(),
+                Selected::Aborted => {
+                    self.inner.lock().unwrap().receivers.unregister(oper).unwrap();
+                    Err(RecvTimeoutError::Timeout)
+                }
+                Selected::Disconnected => {
+                    self.inner.lock().unwrap().receivers.unregister(oper).unwrap();
+                    Err(RecvTimeoutError::Disconnected)
+                }
+                Selected::Operation(_) => {
+                    // Wait until the message is provided, then read it.
+                    packet.wait_ready();
+                    unsafe { Ok(packet.msg.get().replace(None).unwrap()) }
+                }
+            }
+        })
+    }
+
+    /// Disconnects the channel and wakes up all blocked senders and receivers.
+    ///
+    /// Returns `true` if this call disconnected the channel.
+    pub(crate) fn disconnect(&self) -> bool {
+        let mut inner = self.inner.lock().unwrap();
+
+        if !inner.is_disconnected {
+            inner.is_disconnected = true;
+            inner.senders.disconnect();
+            inner.receivers.disconnect();
+            true
+        } else {
+            false
+        }
+    }
+
+    /// Returns the current number of messages inside the channel.
+    pub(crate) fn len(&self) -> usize {
+        0
+    }
+
+    /// Returns the capacity of the channel.
+    #[allow(clippy::unnecessary_wraps)] // This is intentional.
+    pub(crate) fn capacity(&self) -> Option<usize> {
+        Some(0)
+    }
+
+    /// Returns `true` if the channel is empty.
+    pub(crate) fn is_empty(&self) -> bool {
+        true
+    }
+
+    /// Returns `true` if the channel is full.
+    pub(crate) fn is_full(&self) -> bool {
+        true
+    }
+}
diff --git a/library/std/src/sync/mpsc/blocking.rs b/library/std/src/sync/mpsc/blocking.rs
deleted file mode 100644 (file)
index 021df7b..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-//! Generic support for building blocking abstractions.
-
-use crate::sync::atomic::{AtomicBool, Ordering};
-use crate::sync::Arc;
-use crate::thread::{self, Thread};
-use crate::time::Instant;
-
-struct Inner {
-    thread: Thread,
-    woken: AtomicBool,
-}
-
-unsafe impl Send for Inner {}
-unsafe impl Sync for Inner {}
-
-#[derive(Clone)]
-pub struct SignalToken {
-    inner: Arc<Inner>,
-}
-
-pub struct WaitToken {
-    inner: Arc<Inner>,
-}
-
-impl !Send for WaitToken {}
-
-impl !Sync for WaitToken {}
-
-pub fn tokens() -> (WaitToken, SignalToken) {
-    let inner = Arc::new(Inner { thread: thread::current(), woken: AtomicBool::new(false) });
-    let wait_token = WaitToken { inner: inner.clone() };
-    let signal_token = SignalToken { inner };
-    (wait_token, signal_token)
-}
-
-impl SignalToken {
-    pub fn signal(&self) -> bool {
-        let wake = self
-            .inner
-            .woken
-            .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
-            .is_ok();
-        if wake {
-            self.inner.thread.unpark();
-        }
-        wake
-    }
-
-    /// Converts to an unsafe raw pointer. Useful for storing in a pipe's state
-    /// flag.
-    #[inline]
-    pub unsafe fn to_raw(self) -> *mut u8 {
-        Arc::into_raw(self.inner) as *mut u8
-    }
-
-    /// Converts from an unsafe raw pointer. Useful for retrieving a pipe's state
-    /// flag.
-    #[inline]
-    pub unsafe fn from_raw(signal_ptr: *mut u8) -> SignalToken {
-        SignalToken { inner: Arc::from_raw(signal_ptr as *mut Inner) }
-    }
-}
-
-impl WaitToken {
-    pub fn wait(self) {
-        while !self.inner.woken.load(Ordering::SeqCst) {
-            thread::park()
-        }
-    }
-
-    /// Returns `true` if we wake up normally.
-    pub fn wait_max_until(self, end: Instant) -> bool {
-        while !self.inner.woken.load(Ordering::SeqCst) {
-            let now = Instant::now();
-            if now >= end {
-                return false;
-            }
-            thread::park_timeout(end - now)
-        }
-        true
-    }
-}
diff --git a/library/std/src/sync/mpsc/cache_aligned.rs b/library/std/src/sync/mpsc/cache_aligned.rs
deleted file mode 100644 (file)
index 9197f0d..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-use crate::ops::{Deref, DerefMut};
-
-#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
-#[cfg_attr(target_arch = "aarch64", repr(align(128)))]
-#[cfg_attr(not(target_arch = "aarch64"), repr(align(64)))]
-pub(super) struct CacheAligned<T>(pub T);
-
-impl<T> Deref for CacheAligned<T> {
-    type Target = T;
-    fn deref(&self) -> &Self::Target {
-        &self.0
-    }
-}
-
-impl<T> DerefMut for CacheAligned<T> {
-    fn deref_mut(&mut self) -> &mut Self::Target {
-        &mut self.0
-    }
-}
-
-impl<T> CacheAligned<T> {
-    pub(super) fn new(t: T) -> Self {
-        CacheAligned(t)
-    }
-}
index e85a87239651884e56c3deac672876cef1f362be..27fba761ada108c191ec9cbe9ddcea4c3b33ee95 100644 (file)
 #[cfg(all(test, not(target_os = "emscripten")))]
 mod sync_tests;
 
-// A description of how Rust's channel implementation works
-//
-// Channels are supposed to be the basic building block for all other
-// concurrent primitives that are used in Rust. As a result, the channel type
-// needs to be highly optimized, flexible, and broad enough for use everywhere.
-//
-// The choice of implementation of all channels is to be built on lock-free data
-// structures. The channels themselves are then consequently also lock-free data
-// structures. As always with lock-free code, this is a very "here be dragons"
-// territory, especially because I'm unaware of any academic papers that have
-// gone into great length about channels of these flavors.
-//
-// ## Flavors of channels
-//
-// From the perspective of a consumer of this library, there is only one flavor
-// of channel. This channel can be used as a stream and cloned to allow multiple
-// senders. Under the hood, however, there are actually three flavors of
-// channels in play.
-//
-// * Flavor::Oneshots - these channels are highly optimized for the one-send use
-//                      case. They contain as few atomics as possible and
-//                      involve one and exactly one allocation.
-// * Streams - these channels are optimized for the non-shared use case. They
-//             use a different concurrent queue that is more tailored for this
-//             use case. The initial allocation of this flavor of channel is not
-//             optimized.
-// * Shared - this is the most general form of channel that this module offers,
-//            a channel with multiple senders. This type is as optimized as it
-//            can be, but the previous two types mentioned are much faster for
-//            their use-cases.
-//
-// ## Concurrent queues
-//
-// The basic idea of Rust's Sender/Receiver types is that send() never blocks,
-// but recv() obviously blocks. This means that under the hood there must be
-// some shared and concurrent queue holding all of the actual data.
-//
-// With two flavors of channels, two flavors of queues are also used. We have
-// chosen to use queues from a well-known author that are abbreviated as SPSC
-// and MPSC (single producer, single consumer and multiple producer, single
-// consumer). SPSC queues are used for streams while MPSC queues are used for
-// shared channels.
-//
-// ### SPSC optimizations
-//
-// The SPSC queue found online is essentially a linked list of nodes where one
-// half of the nodes are the "queue of data" and the other half of nodes are a
-// cache of unused nodes. The unused nodes are used such that an allocation is
-// not required on every push() and a free doesn't need to happen on every
-// pop().
-//
-// As found online, however, the cache of nodes is of an infinite size. This
-// means that if a channel at one point in its life had 50k items in the queue,
-// then the queue will always have the capacity for 50k items. I believed that
-// this was an unnecessary limitation of the implementation, so I have altered
-// the queue to optionally have a bound on the cache size.
-//
-// By default, streams will have an unbounded SPSC queue with a small-ish cache
-// size. The hope is that the cache is still large enough to have very fast
-// send() operations while not too large such that millions of channels can
-// coexist at once.
-//
-// ### MPSC optimizations
-//
-// Right now the MPSC queue has not been optimized. Like the SPSC queue, it uses
-// a linked list under the hood to earn its unboundedness, but I have not put
-// forth much effort into having a cache of nodes similar to the SPSC queue.
-//
-// For now, I believe that this is "ok" because shared channels are not the most
-// common type, but soon we may wish to revisit this queue choice and determine
-// another candidate for backend storage of shared channels.
-//
-// ## Overview of the Implementation
-//
-// Now that there's a little background on the concurrent queues used, it's
-// worth going into much more detail about the channels themselves. The basic
-// pseudocode for a send/recv are:
-//
-//
-//      send(t)                             recv()
-//        queue.push(t)                       return if queue.pop()
-//        if increment() == -1                deschedule {
-//          wakeup()                            if decrement() > 0
-//                                                cancel_deschedule()
-//                                            }
-//                                            queue.pop()
-//
-// As mentioned before, there are no locks in this implementation, only atomic
-// instructions are used.
-//
-// ### The internal atomic counter
-//
-// Every channel has a shared counter with each half to keep track of the size
-// of the queue. This counter is used to abort descheduling by the receiver and
-// to know when to wake up on the sending side.
-//
-// As seen in the pseudocode, senders will increment this count and receivers
-// will decrement the count. The theory behind this is that if a sender sees a
-// -1 count, it will wake up the receiver, and if the receiver sees a 1+ count,
-// then it doesn't need to block.
-//
-// The recv() method has a beginning call to pop(), and if successful, it needs
-// to decrement the count. It is a crucial implementation detail that this
-// decrement does *not* happen to the shared counter. If this were the case,
-// then it would be possible for the counter to be very negative when there were
-// no receivers waiting, in which case the senders would have to determine when
-// it was actually appropriate to wake up a receiver.
-//
-// Instead, the "steal count" is kept track of separately (not atomically
-// because it's only used by receivers), and then the decrement() call when
-// descheduling will lump in all of the recent steals into one large decrement.
-//
-// The implication of this is that if a sender sees a -1 count, then there's
-// guaranteed to be a waiter waiting!
-//
-// ## Native Implementation
-//
-// A major goal of these channels is to work seamlessly on and off the runtime.
-// All of the previous race conditions have been worded in terms of
-// scheduler-isms (which is obviously not available without the runtime).
-//
-// For now, native usage of channels (off the runtime) will fall back onto
-// mutexes/cond vars for descheduling/atomic decisions. The no-contention path
-// is still entirely lock-free, the "deschedule" blocks above are surrounded by
-// a mutex and the "wakeup" blocks involve grabbing a mutex and signaling on a
-// condition variable.
-//
-// ## Select
-//
-// Being able to support selection over channels has greatly influenced this
-// design, and not only does selection need to work inside the runtime, but also
-// outside the runtime.
-//
-// The implementation is fairly straightforward. The goal of select() is not to
-// return some data, but only to return which channel can receive data without
-// blocking. The implementation is essentially the entire blocking procedure
-// followed by an increment as soon as its woken up. The cancellation procedure
-// involves an increment and swapping out of to_wake to acquire ownership of the
-// thread to unblock.
-//
-// Sadly this current implementation requires multiple allocations, so I have
-// seen the throughput of select() be much worse than it should be. I do not
-// believe that there is anything fundamental that needs to change about these
-// channels, however, in order to support a more efficient select().
-//
-// FIXME: Select is now removed, so these factors are ready to be cleaned up!
-//
-// # Conclusion
-//
-// And now that you've seen all the races that I found and attempted to fix,
-// here's the code for you to find some more!
-
-use crate::cell::UnsafeCell;
+// MPSC channels are built as a wrapper around MPMC channels, which
+// were ported from the `crossbeam-channel` crate. MPMC channels are
+// not exposed publicly, but if you are curious about the implementation,
+// that's where everything is.
+
 use crate::error;
 use crate::fmt;
-use crate::mem;
-use crate::sync::Arc;
+use crate::sync::mpmc;
 use crate::time::{Duration, Instant};
 
-mod blocking;
-mod mpsc_queue;
-mod oneshot;
-mod shared;
-mod spsc_queue;
-mod stream;
-mod sync;
-
-mod cache_aligned;
-
 /// The receiving half of Rust's [`channel`] (or [`sync_channel`]) type.
 /// This half can only be owned by one thread.
 ///
 #[stable(feature = "rust1", since = "1.0.0")]
 #[cfg_attr(not(test), rustc_diagnostic_item = "Receiver")]
 pub struct Receiver<T> {
-    inner: UnsafeCell<Flavor<T>>,
+    inner: mpmc::Receiver<T>,
 }
 
 // The receiver port can be sent from place to place, so long as it
@@ -498,7 +339,7 @@ pub struct IntoIter<T> {
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Sender<T> {
-    inner: UnsafeCell<Flavor<T>>,
+    inner: mpmc::Sender<T>,
 }
 
 // The send port can be sent from place to place, so long as it
@@ -557,7 +398,7 @@ impl<T> !Sync for Sender<T> {}
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct SyncSender<T> {
-    inner: Arc<sync::Packet<T>>,
+    inner: mpmc::Sender<T>,
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -643,34 +484,6 @@ pub enum TrySendError<T> {
     Disconnected(#[stable(feature = "rust1", since = "1.0.0")] T),
 }
 
-enum Flavor<T> {
-    Oneshot(Arc<oneshot::Packet<T>>),
-    Stream(Arc<stream::Packet<T>>),
-    Shared(Arc<shared::Packet<T>>),
-    Sync(Arc<sync::Packet<T>>),
-}
-
-#[doc(hidden)]
-trait UnsafeFlavor<T> {
-    fn inner_unsafe(&self) -> &UnsafeCell<Flavor<T>>;
-    unsafe fn inner_mut(&self) -> &mut Flavor<T> {
-        &mut *self.inner_unsafe().get()
-    }
-    unsafe fn inner(&self) -> &Flavor<T> {
-        &*self.inner_unsafe().get()
-    }
-}
-impl<T> UnsafeFlavor<T> for Sender<T> {
-    fn inner_unsafe(&self) -> &UnsafeCell<Flavor<T>> {
-        &self.inner
-    }
-}
-impl<T> UnsafeFlavor<T> for Receiver<T> {
-    fn inner_unsafe(&self) -> &UnsafeCell<Flavor<T>> {
-        &self.inner
-    }
-}
-
 /// Creates a new asynchronous channel, returning the sender/receiver halves.
 /// All data sent on the [`Sender`] will become available on the [`Receiver`] in
 /// the same order as it was sent, and no [`send`] will block the calling thread
@@ -711,8 +524,8 @@ fn inner_unsafe(&self) -> &UnsafeCell<Flavor<T>> {
 #[must_use]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
-    let a = Arc::new(oneshot::Packet::new());
-    (Sender::new(Flavor::Oneshot(a.clone())), Receiver::new(Flavor::Oneshot(a)))
+    let (tx, rx) = mpmc::channel();
+    (Sender { inner: tx }, Receiver { inner: rx })
 }
 
 /// Creates a new synchronous, bounded channel.
@@ -760,8 +573,8 @@ pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
 #[must_use]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn sync_channel<T>(bound: usize) -> (SyncSender<T>, Receiver<T>) {
-    let a = Arc::new(sync::Packet::new(bound));
-    (SyncSender::new(a.clone()), Receiver::new(Flavor::Sync(a)))
+    let (tx, rx) = mpmc::sync_channel(bound);
+    (SyncSender { inner: tx }, Receiver { inner: rx })
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -769,10 +582,6 @@ pub fn sync_channel<T>(bound: usize) -> (SyncSender<T>, Receiver<T>) {
 ////////////////////////////////////////////////////////////////////////////////
 
 impl<T> Sender<T> {
-    fn new(inner: Flavor<T>) -> Sender<T> {
-        Sender { inner: UnsafeCell::new(inner) }
-    }
-
     /// Attempts to send a value on this channel, returning it back if it could
     /// not be sent.
     ///
@@ -802,40 +611,7 @@ fn new(inner: Flavor<T>) -> Sender<T> {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn send(&self, t: T) -> Result<(), SendError<T>> {
-        let (new_inner, ret) = match *unsafe { self.inner() } {
-            Flavor::Oneshot(ref p) => {
-                if !p.sent() {
-                    return p.send(t).map_err(SendError);
-                } else {
-                    let a = Arc::new(stream::Packet::new());
-                    let rx = Receiver::new(Flavor::Stream(a.clone()));
-                    match p.upgrade(rx) {
-                        oneshot::UpSuccess => {
-                            let ret = a.send(t);
-                            (a, ret)
-                        }
-                        oneshot::UpDisconnected => (a, Err(t)),
-                        oneshot::UpWoke(token) => {
-                            // This send cannot panic because the thread is
-                            // asleep (we're looking at it), so the receiver
-                            // can't go away.
-                            a.send(t).ok().unwrap();
-                            token.signal();
-                            (a, Ok(()))
-                        }
-                    }
-                }
-            }
-            Flavor::Stream(ref p) => return p.send(t).map_err(SendError),
-            Flavor::Shared(ref p) => return p.send(t).map_err(SendError),
-            Flavor::Sync(..) => unreachable!(),
-        };
-
-        unsafe {
-            let tmp = Sender::new(Flavor::Stream(new_inner));
-            mem::swap(self.inner_mut(), tmp.inner_mut());
-        }
-        ret.map_err(SendError)
+        self.inner.send(t)
     }
 }
 
@@ -847,57 +623,14 @@ impl<T> Clone for Sender<T> {
     /// (including the original) need to be dropped in order for
     /// [`Receiver::recv`] to stop blocking.
     fn clone(&self) -> Sender<T> {
-        let packet = match *unsafe { self.inner() } {
-            Flavor::Oneshot(ref p) => {
-                let a = Arc::new(shared::Packet::new());
-                {
-                    let guard = a.postinit_lock();
-                    let rx = Receiver::new(Flavor::Shared(a.clone()));
-                    let sleeper = match p.upgrade(rx) {
-                        oneshot::UpSuccess | oneshot::UpDisconnected => None,
-                        oneshot::UpWoke(task) => Some(task),
-                    };
-                    a.inherit_blocker(sleeper, guard);
-                }
-                a
-            }
-            Flavor::Stream(ref p) => {
-                let a = Arc::new(shared::Packet::new());
-                {
-                    let guard = a.postinit_lock();
-                    let rx = Receiver::new(Flavor::Shared(a.clone()));
-                    let sleeper = match p.upgrade(rx) {
-                        stream::UpSuccess | stream::UpDisconnected => None,
-                        stream::UpWoke(task) => Some(task),
-                    };
-                    a.inherit_blocker(sleeper, guard);
-                }
-                a
-            }
-            Flavor::Shared(ref p) => {
-                p.clone_chan();
-                return Sender::new(Flavor::Shared(p.clone()));
-            }
-            Flavor::Sync(..) => unreachable!(),
-        };
-
-        unsafe {
-            let tmp = Sender::new(Flavor::Shared(packet.clone()));
-            mem::swap(self.inner_mut(), tmp.inner_mut());
-        }
-        Sender::new(Flavor::Shared(packet))
+        Sender { inner: self.inner.clone() }
     }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> Drop for Sender<T> {
     fn drop(&mut self) {
-        match *unsafe { self.inner() } {
-            Flavor::Oneshot(ref p) => p.drop_chan(),
-            Flavor::Stream(ref p) => p.drop_chan(),
-            Flavor::Shared(ref p) => p.drop_chan(),
-            Flavor::Sync(..) => unreachable!(),
-        }
+        let _ = self.inner;
     }
 }
 
@@ -913,10 +646,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 ////////////////////////////////////////////////////////////////////////////////
 
 impl<T> SyncSender<T> {
-    fn new(inner: Arc<sync::Packet<T>>) -> SyncSender<T> {
-        SyncSender { inner }
-    }
-
     /// Sends a value on this synchronous channel.
     ///
     /// This function will *block* until space in the internal buffer becomes
@@ -955,7 +684,7 @@ fn new(inner: Arc<sync::Packet<T>>) -> SyncSender<T> {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn send(&self, t: T) -> Result<(), SendError<T>> {
-        self.inner.send(t).map_err(SendError)
+        self.inner.send(t)
     }
 
     /// Attempts to send a value on this channel without blocking.
@@ -1016,15 +745,14 @@ pub fn try_send(&self, t: T) -> Result<(), TrySendError<T>> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> Clone for SyncSender<T> {
     fn clone(&self) -> SyncSender<T> {
-        self.inner.clone_chan();
-        SyncSender::new(self.inner.clone())
+        SyncSender { inner: self.inner.clone() }
     }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> Drop for SyncSender<T> {
     fn drop(&mut self) {
-        self.inner.drop_chan();
+        let _ = self.inner;
     }
 }
 
@@ -1040,10 +768,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 ////////////////////////////////////////////////////////////////////////////////
 
 impl<T> Receiver<T> {
-    fn new(inner: Flavor<T>) -> Receiver<T> {
-        Receiver { inner: UnsafeCell::new(inner) }
-    }
-
     /// Attempts to return a pending value on this receiver without blocking.
     ///
     /// This method will never block the caller in order to wait for data to
@@ -1069,35 +793,7 @@ fn new(inner: Flavor<T>) -> Receiver<T> {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn try_recv(&self) -> Result<T, TryRecvError> {
-        loop {
-            let new_port = match *unsafe { self.inner() } {
-                Flavor::Oneshot(ref p) => match p.try_recv() {
-                    Ok(t) => return Ok(t),
-                    Err(oneshot::Empty) => return Err(TryRecvError::Empty),
-                    Err(oneshot::Disconnected) => return Err(TryRecvError::Disconnected),
-                    Err(oneshot::Upgraded(rx)) => rx,
-                },
-                Flavor::Stream(ref p) => match p.try_recv() {
-                    Ok(t) => return Ok(t),
-                    Err(stream::Empty) => return Err(TryRecvError::Empty),
-                    Err(stream::Disconnected) => return Err(TryRecvError::Disconnected),
-                    Err(stream::Upgraded(rx)) => rx,
-                },
-                Flavor::Shared(ref p) => match p.try_recv() {
-                    Ok(t) => return Ok(t),
-                    Err(shared::Empty) => return Err(TryRecvError::Empty),
-                    Err(shared::Disconnected) => return Err(TryRecvError::Disconnected),
-                },
-                Flavor::Sync(ref p) => match p.try_recv() {
-                    Ok(t) => return Ok(t),
-                    Err(sync::Empty) => return Err(TryRecvError::Empty),
-                    Err(sync::Disconnected) => return Err(TryRecvError::Disconnected),
-                },
-            };
-            unsafe {
-                mem::swap(self.inner_mut(), new_port.inner_mut());
-            }
-        }
+        self.inner.try_recv()
     }
 
     /// Attempts to wait for a value on this receiver, returning an error if the
@@ -1156,31 +852,7 @@ pub fn try_recv(&self) -> Result<T, TryRecvError> {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn recv(&self) -> Result<T, RecvError> {
-        loop {
-            let new_port = match *unsafe { self.inner() } {
-                Flavor::Oneshot(ref p) => match p.recv(None) {
-                    Ok(t) => return Ok(t),
-                    Err(oneshot::Disconnected) => return Err(RecvError),
-                    Err(oneshot::Upgraded(rx)) => rx,
-                    Err(oneshot::Empty) => unreachable!(),
-                },
-                Flavor::Stream(ref p) => match p.recv(None) {
-                    Ok(t) => return Ok(t),
-                    Err(stream::Disconnected) => return Err(RecvError),
-                    Err(stream::Upgraded(rx)) => rx,
-                    Err(stream::Empty) => unreachable!(),
-                },
-                Flavor::Shared(ref p) => match p.recv(None) {
-                    Ok(t) => return Ok(t),
-                    Err(shared::Disconnected) => return Err(RecvError),
-                    Err(shared::Empty) => unreachable!(),
-                },
-                Flavor::Sync(ref p) => return p.recv(None).map_err(|_| RecvError),
-            };
-            unsafe {
-                mem::swap(self.inner_mut(), new_port.inner_mut());
-            }
-        }
+        self.inner.recv()
     }
 
     /// Attempts to wait for a value on this receiver, returning an error if the
@@ -1198,34 +870,6 @@ pub fn recv(&self) -> Result<T, RecvError> {
     /// However, since channels are buffered, messages sent before the disconnect
     /// will still be properly received.
     ///
-    /// # Known Issues
-    ///
-    /// There is currently a known issue (see [`#39364`]) that causes `recv_timeout`
-    /// to panic unexpectedly with the following example:
-    ///
-    /// ```no_run
-    /// use std::sync::mpsc::channel;
-    /// use std::thread;
-    /// use std::time::Duration;
-    ///
-    /// let (tx, rx) = channel::<String>();
-    ///
-    /// thread::spawn(move || {
-    ///     let d = Duration::from_millis(10);
-    ///     loop {
-    ///         println!("recv");
-    ///         let _r = rx.recv_timeout(d);
-    ///     }
-    /// });
-    ///
-    /// thread::sleep(Duration::from_millis(100));
-    /// let _c1 = tx.clone();
-    ///
-    /// thread::sleep(Duration::from_secs(1));
-    /// ```
-    ///
-    /// [`#39364`]: https://github.com/rust-lang/rust/issues/39364
-    ///
     /// # Examples
     ///
     /// Successfully receiving value before encountering timeout:
@@ -1268,17 +912,7 @@ pub fn recv(&self) -> Result<T, RecvError> {
     /// ```
     #[stable(feature = "mpsc_recv_timeout", since = "1.12.0")]
     pub fn recv_timeout(&self, timeout: Duration) -> Result<T, RecvTimeoutError> {
-        // Do an optimistic try_recv to avoid the performance impact of
-        // Instant::now() in the full-channel case.
-        match self.try_recv() {
-            Ok(result) => Ok(result),
-            Err(TryRecvError::Disconnected) => Err(RecvTimeoutError::Disconnected),
-            Err(TryRecvError::Empty) => match Instant::now().checked_add(timeout) {
-                Some(deadline) => self.recv_deadline(deadline),
-                // So far in the future that it's practically the same as waiting indefinitely.
-                None => self.recv().map_err(RecvTimeoutError::from),
-            },
-        }
+        self.inner.recv_timeout(timeout)
     }
 
     /// Attempts to wait for a value on this receiver, returning an error if the
@@ -1339,46 +973,7 @@ pub fn recv_timeout(&self, timeout: Duration) -> Result<T, RecvTimeoutError> {
     /// ```
     #[unstable(feature = "deadline_api", issue = "46316")]
     pub fn recv_deadline(&self, deadline: Instant) -> Result<T, RecvTimeoutError> {
-        use self::RecvTimeoutError::*;
-
-        loop {
-            let port_or_empty = match *unsafe { self.inner() } {
-                Flavor::Oneshot(ref p) => match p.recv(Some(deadline)) {
-                    Ok(t) => return Ok(t),
-                    Err(oneshot::Disconnected) => return Err(Disconnected),
-                    Err(oneshot::Upgraded(rx)) => Some(rx),
-                    Err(oneshot::Empty) => None,
-                },
-                Flavor::Stream(ref p) => match p.recv(Some(deadline)) {
-                    Ok(t) => return Ok(t),
-                    Err(stream::Disconnected) => return Err(Disconnected),
-                    Err(stream::Upgraded(rx)) => Some(rx),
-                    Err(stream::Empty) => None,
-                },
-                Flavor::Shared(ref p) => match p.recv(Some(deadline)) {
-                    Ok(t) => return Ok(t),
-                    Err(shared::Disconnected) => return Err(Disconnected),
-                    Err(shared::Empty) => None,
-                },
-                Flavor::Sync(ref p) => match p.recv(Some(deadline)) {
-                    Ok(t) => return Ok(t),
-                    Err(sync::Disconnected) => return Err(Disconnected),
-                    Err(sync::Empty) => None,
-                },
-            };
-
-            if let Some(new_port) = port_or_empty {
-                unsafe {
-                    mem::swap(self.inner_mut(), new_port.inner_mut());
-                }
-            }
-
-            // If we're already passed the deadline, and we're here without
-            // data, return a timeout, else try again.
-            if Instant::now() >= deadline {
-                return Err(Timeout);
-            }
-        }
+        self.inner.recv_deadline(deadline)
     }
 
     /// Returns an iterator that will block waiting for messages, but never
@@ -1500,12 +1095,7 @@ fn into_iter(self) -> IntoIter<T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> Drop for Receiver<T> {
     fn drop(&mut self) {
-        match *unsafe { self.inner() } {
-            Flavor::Oneshot(ref p) => p.drop_port(),
-            Flavor::Stream(ref p) => p.drop_port(),
-            Flavor::Shared(ref p) => p.drop_port(),
-            Flavor::Sync(ref p) => p.drop_port(),
-        }
+        let _ = self.inner;
     }
 }
 
diff --git a/library/std/src/sync/mpsc/mpsc_queue.rs b/library/std/src/sync/mpsc/mpsc_queue.rs
deleted file mode 100644 (file)
index cdd64a5..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-//! A mostly lock-free multi-producer, single consumer queue.
-//!
-//! This module contains an implementation of a concurrent MPSC queue. This
-//! queue can be used to share data between threads, and is also used as the
-//! building block of channels in rust.
-//!
-//! Note that the current implementation of this queue has a caveat of the `pop`
-//! method, and see the method for more information about it. Due to this
-//! caveat, this queue might not be appropriate for all use-cases.
-
-// https://www.1024cores.net/home/lock-free-algorithms
-//                          /queues/non-intrusive-mpsc-node-based-queue
-
-#[cfg(all(test, not(target_os = "emscripten")))]
-mod tests;
-
-pub use self::PopResult::*;
-
-use core::cell::UnsafeCell;
-use core::ptr;
-
-use crate::boxed::Box;
-use crate::sync::atomic::{AtomicPtr, Ordering};
-
-/// A result of the `pop` function.
-pub enum PopResult<T> {
-    /// Some data has been popped
-    Data(T),
-    /// The queue is empty
-    Empty,
-    /// The queue is in an inconsistent state. Popping data should succeed, but
-    /// some pushers have yet to make enough progress in order allow a pop to
-    /// succeed. It is recommended that a pop() occur "in the near future" in
-    /// order to see if the sender has made progress or not
-    Inconsistent,
-}
-
-struct Node<T> {
-    next: AtomicPtr<Node<T>>,
-    value: Option<T>,
-}
-
-/// The multi-producer single-consumer structure. This is not cloneable, but it
-/// may be safely shared so long as it is guaranteed that there is only one
-/// popper at a time (many pushers are allowed).
-pub struct Queue<T> {
-    head: AtomicPtr<Node<T>>,
-    tail: UnsafeCell<*mut Node<T>>,
-}
-
-unsafe impl<T: Send> Send for Queue<T> {}
-unsafe impl<T: Send> Sync for Queue<T> {}
-
-impl<T> Node<T> {
-    unsafe fn new(v: Option<T>) -> *mut Node<T> {
-        Box::into_raw(box Node { next: AtomicPtr::new(ptr::null_mut()), value: v })
-    }
-}
-
-impl<T> Queue<T> {
-    /// Creates a new queue that is safe to share among multiple producers and
-    /// one consumer.
-    pub fn new() -> Queue<T> {
-        let stub = unsafe { Node::new(None) };
-        Queue { head: AtomicPtr::new(stub), tail: UnsafeCell::new(stub) }
-    }
-
-    /// Pushes a new value onto this queue.
-    pub fn push(&self, t: T) {
-        unsafe {
-            let n = Node::new(Some(t));
-            let prev = self.head.swap(n, Ordering::AcqRel);
-            (*prev).next.store(n, Ordering::Release);
-        }
-    }
-
-    /// Pops some data from this queue.
-    ///
-    /// Note that the current implementation means that this function cannot
-    /// return `Option<T>`. It is possible for this queue to be in an
-    /// inconsistent state where many pushes have succeeded and completely
-    /// finished, but pops cannot return `Some(t)`. This inconsistent state
-    /// happens when a pusher is pre-empted at an inopportune moment.
-    ///
-    /// This inconsistent state means that this queue does indeed have data, but
-    /// it does not currently have access to it at this time.
-    pub fn pop(&self) -> PopResult<T> {
-        unsafe {
-            let tail = *self.tail.get();
-            let next = (*tail).next.load(Ordering::Acquire);
-
-            if !next.is_null() {
-                *self.tail.get() = next;
-                assert!((*tail).value.is_none());
-                assert!((*next).value.is_some());
-                let ret = (*next).value.take().unwrap();
-                let _: Box<Node<T>> = Box::from_raw(tail);
-                return Data(ret);
-            }
-
-            if self.head.load(Ordering::Acquire) == tail { Empty } else { Inconsistent }
-        }
-    }
-}
-
-impl<T> Drop for Queue<T> {
-    fn drop(&mut self) {
-        unsafe {
-            let mut cur = *self.tail.get();
-            while !cur.is_null() {
-                let next = (*cur).next.load(Ordering::Relaxed);
-                let _: Box<Node<T>> = Box::from_raw(cur);
-                cur = next;
-            }
-        }
-    }
-}
diff --git a/library/std/src/sync/mpsc/mpsc_queue/tests.rs b/library/std/src/sync/mpsc/mpsc_queue/tests.rs
deleted file mode 100644 (file)
index 34b2a9a..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-use super::{Data, Empty, Inconsistent, Queue};
-use crate::sync::mpsc::channel;
-use crate::sync::Arc;
-use crate::thread;
-
-#[test]
-fn test_full() {
-    let q: Queue<Box<_>> = Queue::new();
-    q.push(Box::new(1));
-    q.push(Box::new(2));
-}
-
-#[test]
-fn test() {
-    let nthreads = 8;
-    let nmsgs = if cfg!(miri) { 100 } else { 1000 };
-    let q = Queue::new();
-    match q.pop() {
-        Empty => {}
-        Inconsistent | Data(..) => panic!(),
-    }
-    let (tx, rx) = channel();
-    let q = Arc::new(q);
-
-    for _ in 0..nthreads {
-        let tx = tx.clone();
-        let q = q.clone();
-        thread::spawn(move || {
-            for i in 0..nmsgs {
-                q.push(i);
-            }
-            tx.send(()).unwrap();
-        });
-    }
-
-    let mut i = 0;
-    while i < nthreads * nmsgs {
-        match q.pop() {
-            Empty | Inconsistent => {}
-            Data(_) => i += 1,
-        }
-    }
-    drop(tx);
-    for _ in 0..nthreads {
-        rx.recv().unwrap();
-    }
-}
diff --git a/library/std/src/sync/mpsc/oneshot.rs b/library/std/src/sync/mpsc/oneshot.rs
deleted file mode 100644 (file)
index 0e259b8..0000000
+++ /dev/null
@@ -1,315 +0,0 @@
-/// Oneshot channels/ports
-///
-/// This is the initial flavor of channels/ports used for comm module. This is
-/// an optimization for the one-use case of a channel. The major optimization of
-/// this type is to have one and exactly one allocation when the chan/port pair
-/// is created.
-///
-/// Another possible optimization would be to not use an Arc box because
-/// in theory we know when the shared packet can be deallocated (no real need
-/// for the atomic reference counting), but I was having trouble how to destroy
-/// the data early in a drop of a Port.
-///
-/// # Implementation
-///
-/// Oneshots are implemented around one atomic usize variable. This variable
-/// indicates both the state of the port/chan but also contains any threads
-/// blocked on the port. All atomic operations happen on this one word.
-///
-/// In order to upgrade a oneshot channel, an upgrade is considered a disconnect
-/// on behalf of the channel side of things (it can be mentally thought of as
-/// consuming the port). This upgrade is then also stored in the shared packet.
-/// The one caveat to consider is that when a port sees a disconnected channel
-/// it must check for data because there is no "data plus upgrade" state.
-pub use self::Failure::*;
-use self::MyUpgrade::*;
-pub use self::UpgradeResult::*;
-
-use crate::cell::UnsafeCell;
-use crate::ptr;
-use crate::sync::atomic::{AtomicPtr, Ordering};
-use crate::sync::mpsc::blocking::{self, SignalToken};
-use crate::sync::mpsc::Receiver;
-use crate::time::Instant;
-
-// Various states you can find a port in.
-const EMPTY: *mut u8 = ptr::invalid_mut::<u8>(0); // initial state: no data, no blocked receiver
-const DATA: *mut u8 = ptr::invalid_mut::<u8>(1); // data ready for receiver to take
-const DISCONNECTED: *mut u8 = ptr::invalid_mut::<u8>(2); // channel is disconnected OR upgraded
-// Any other value represents a pointer to a SignalToken value. The
-// protocol ensures that when the state moves *to* a pointer,
-// ownership of the token is given to the packet, and when the state
-// moves *from* a pointer, ownership of the token is transferred to
-// whoever changed the state.
-
-pub struct Packet<T> {
-    // Internal state of the chan/port pair (stores the blocked thread as well)
-    state: AtomicPtr<u8>,
-    // One-shot data slot location
-    data: UnsafeCell<Option<T>>,
-    // when used for the second time, a oneshot channel must be upgraded, and
-    // this contains the slot for the upgrade
-    upgrade: UnsafeCell<MyUpgrade<T>>,
-}
-
-pub enum Failure<T> {
-    Empty,
-    Disconnected,
-    Upgraded(Receiver<T>),
-}
-
-pub enum UpgradeResult {
-    UpSuccess,
-    UpDisconnected,
-    UpWoke(SignalToken),
-}
-
-enum MyUpgrade<T> {
-    NothingSent,
-    SendUsed,
-    GoUp(Receiver<T>),
-}
-
-impl<T> Packet<T> {
-    pub fn new() -> Packet<T> {
-        Packet {
-            data: UnsafeCell::new(None),
-            upgrade: UnsafeCell::new(NothingSent),
-            state: AtomicPtr::new(EMPTY),
-        }
-    }
-
-    pub fn send(&self, t: T) -> Result<(), T> {
-        unsafe {
-            // Sanity check
-            match *self.upgrade.get() {
-                NothingSent => {}
-                _ => panic!("sending on a oneshot that's already sent on "),
-            }
-            assert!((*self.data.get()).is_none());
-            ptr::write(self.data.get(), Some(t));
-            ptr::write(self.upgrade.get(), SendUsed);
-
-            match self.state.swap(DATA, Ordering::SeqCst) {
-                // Sent the data, no one was waiting
-                EMPTY => Ok(()),
-
-                // Couldn't send the data, the port hung up first. Return the data
-                // back up the stack.
-                DISCONNECTED => {
-                    self.state.swap(DISCONNECTED, Ordering::SeqCst);
-                    ptr::write(self.upgrade.get(), NothingSent);
-                    Err((&mut *self.data.get()).take().unwrap())
-                }
-
-                // Not possible, these are one-use channels
-                DATA => unreachable!(),
-
-                // There is a thread waiting on the other end. We leave the 'DATA'
-                // state inside so it'll pick it up on the other end.
-                ptr => {
-                    SignalToken::from_raw(ptr).signal();
-                    Ok(())
-                }
-            }
-        }
-    }
-
-    // Just tests whether this channel has been sent on or not, this is only
-    // safe to use from the sender.
-    pub fn sent(&self) -> bool {
-        unsafe { !matches!(*self.upgrade.get(), NothingSent) }
-    }
-
-    pub fn recv(&self, deadline: Option<Instant>) -> Result<T, Failure<T>> {
-        // Attempt to not block the thread (it's a little expensive). If it looks
-        // like we're not empty, then immediately go through to `try_recv`.
-        if self.state.load(Ordering::SeqCst) == EMPTY {
-            let (wait_token, signal_token) = blocking::tokens();
-            let ptr = unsafe { signal_token.to_raw() };
-
-            // race with senders to enter the blocking state
-            if self.state.compare_exchange(EMPTY, ptr, Ordering::SeqCst, Ordering::SeqCst).is_ok() {
-                if let Some(deadline) = deadline {
-                    let timed_out = !wait_token.wait_max_until(deadline);
-                    // Try to reset the state
-                    if timed_out {
-                        self.abort_selection().map_err(Upgraded)?;
-                    }
-                } else {
-                    wait_token.wait();
-                    debug_assert!(self.state.load(Ordering::SeqCst) != EMPTY);
-                }
-            } else {
-                // drop the signal token, since we never blocked
-                drop(unsafe { SignalToken::from_raw(ptr) });
-            }
-        }
-
-        self.try_recv()
-    }
-
-    pub fn try_recv(&self) -> Result<T, Failure<T>> {
-        unsafe {
-            match self.state.load(Ordering::SeqCst) {
-                EMPTY => Err(Empty),
-
-                // We saw some data on the channel, but the channel can be used
-                // again to send us an upgrade. As a result, we need to re-insert
-                // into the channel that there's no data available (otherwise we'll
-                // just see DATA next time). This is done as a cmpxchg because if
-                // the state changes under our feet we'd rather just see that state
-                // change.
-                DATA => {
-                    let _ = self.state.compare_exchange(
-                        DATA,
-                        EMPTY,
-                        Ordering::SeqCst,
-                        Ordering::SeqCst,
-                    );
-                    match (&mut *self.data.get()).take() {
-                        Some(data) => Ok(data),
-                        None => unreachable!(),
-                    }
-                }
-
-                // There's no guarantee that we receive before an upgrade happens,
-                // and an upgrade flags the channel as disconnected, so when we see
-                // this we first need to check if there's data available and *then*
-                // we go through and process the upgrade.
-                DISCONNECTED => match (&mut *self.data.get()).take() {
-                    Some(data) => Ok(data),
-                    None => match ptr::replace(self.upgrade.get(), SendUsed) {
-                        SendUsed | NothingSent => Err(Disconnected),
-                        GoUp(upgrade) => Err(Upgraded(upgrade)),
-                    },
-                },
-
-                // We are the sole receiver; there cannot be a blocking
-                // receiver already.
-                _ => unreachable!(),
-            }
-        }
-    }
-
-    // Returns whether the upgrade was completed. If the upgrade wasn't
-    // completed, then the port couldn't get sent to the other half (it will
-    // never receive it).
-    pub fn upgrade(&self, up: Receiver<T>) -> UpgradeResult {
-        unsafe {
-            let prev = match *self.upgrade.get() {
-                NothingSent => NothingSent,
-                SendUsed => SendUsed,
-                _ => panic!("upgrading again"),
-            };
-            ptr::write(self.upgrade.get(), GoUp(up));
-
-            match self.state.swap(DISCONNECTED, Ordering::SeqCst) {
-                // If the channel is empty or has data on it, then we're good to go.
-                // Senders will check the data before the upgrade (in case we
-                // plastered over the DATA state).
-                DATA | EMPTY => UpSuccess,
-
-                // If the other end is already disconnected, then we failed the
-                // upgrade. Be sure to trash the port we were given.
-                DISCONNECTED => {
-                    ptr::replace(self.upgrade.get(), prev);
-                    UpDisconnected
-                }
-
-                // If someone's waiting, we gotta wake them up
-                ptr => UpWoke(SignalToken::from_raw(ptr)),
-            }
-        }
-    }
-
-    pub fn drop_chan(&self) {
-        match self.state.swap(DISCONNECTED, Ordering::SeqCst) {
-            DATA | DISCONNECTED | EMPTY => {}
-
-            // If someone's waiting, we gotta wake them up
-            ptr => unsafe {
-                SignalToken::from_raw(ptr).signal();
-            },
-        }
-    }
-
-    pub fn drop_port(&self) {
-        match self.state.swap(DISCONNECTED, Ordering::SeqCst) {
-            // An empty channel has nothing to do, and a remotely disconnected
-            // channel also has nothing to do b/c we're about to run the drop
-            // glue
-            DISCONNECTED | EMPTY => {}
-
-            // There's data on the channel, so make sure we destroy it promptly.
-            // This is why not using an arc is a little difficult (need the box
-            // to stay valid while we take the data).
-            DATA => unsafe {
-                (&mut *self.data.get()).take().unwrap();
-            },
-
-            // We're the only ones that can block on this port
-            _ => unreachable!(),
-        }
-    }
-
-    ////////////////////////////////////////////////////////////////////////////
-    // select implementation
-    ////////////////////////////////////////////////////////////////////////////
-
-    // Remove a previous selecting thread from this port. This ensures that the
-    // blocked thread will no longer be visible to any other threads.
-    //
-    // The return value indicates whether there's data on this port.
-    pub fn abort_selection(&self) -> Result<bool, Receiver<T>> {
-        let state = match self.state.load(Ordering::SeqCst) {
-            // Each of these states means that no further activity will happen
-            // with regard to abortion selection
-            s @ (EMPTY | DATA | DISCONNECTED) => s,
-
-            // If we've got a blocked thread, then use an atomic to gain ownership
-            // of it (may fail)
-            ptr => self
-                .state
-                .compare_exchange(ptr, EMPTY, Ordering::SeqCst, Ordering::SeqCst)
-                .unwrap_or_else(|x| x),
-        };
-
-        // Now that we've got ownership of our state, figure out what to do
-        // about it.
-        match state {
-            EMPTY => unreachable!(),
-            // our thread used for select was stolen
-            DATA => Ok(true),
-
-            // If the other end has hung up, then we have complete ownership
-            // of the port. First, check if there was data waiting for us. This
-            // is possible if the other end sent something and then hung up.
-            //
-            // We then need to check to see if there was an upgrade requested,
-            // and if so, the upgraded port needs to have its selection aborted.
-            DISCONNECTED => unsafe {
-                if (*self.data.get()).is_some() {
-                    Ok(true)
-                } else {
-                    match ptr::replace(self.upgrade.get(), SendUsed) {
-                        GoUp(port) => Err(port),
-                        _ => Ok(true),
-                    }
-                }
-            },
-
-            // We woke ourselves up from select.
-            ptr => unsafe {
-                drop(SignalToken::from_raw(ptr));
-                Ok(false)
-            },
-        }
-    }
-}
-
-impl<T> Drop for Packet<T> {
-    fn drop(&mut self) {
-        assert_eq!(self.state.load(Ordering::SeqCst), DISCONNECTED);
-    }
-}
diff --git a/library/std/src/sync/mpsc/shared.rs b/library/std/src/sync/mpsc/shared.rs
deleted file mode 100644 (file)
index 51917bd..0000000
+++ /dev/null
@@ -1,501 +0,0 @@
-/// Shared channels.
-///
-/// This is the flavor of channels which are not necessarily optimized for any
-/// particular use case, but are the most general in how they are used. Shared
-/// channels are cloneable allowing for multiple senders.
-///
-/// High level implementation details can be found in the comment of the parent
-/// module. You'll also note that the implementation of the shared and stream
-/// channels are quite similar, and this is no coincidence!
-pub use self::Failure::*;
-use self::StartResult::*;
-
-use core::cmp;
-use core::intrinsics::abort;
-
-use crate::cell::UnsafeCell;
-use crate::ptr;
-use crate::sync::atomic::{AtomicBool, AtomicIsize, AtomicPtr, AtomicUsize, Ordering};
-use crate::sync::mpsc::blocking::{self, SignalToken};
-use crate::sync::mpsc::mpsc_queue as mpsc;
-use crate::sync::{Mutex, MutexGuard};
-use crate::thread;
-use crate::time::Instant;
-
-const DISCONNECTED: isize = isize::MIN;
-const FUDGE: isize = 1024;
-const MAX_REFCOUNT: usize = (isize::MAX) as usize;
-#[cfg(test)]
-const MAX_STEALS: isize = 5;
-#[cfg(not(test))]
-const MAX_STEALS: isize = 1 << 20;
-const EMPTY: *mut u8 = ptr::null_mut(); // initial state: no data, no blocked receiver
-
-pub struct Packet<T> {
-    queue: mpsc::Queue<T>,
-    cnt: AtomicIsize,          // How many items are on this channel
-    steals: UnsafeCell<isize>, // How many times has a port received without blocking?
-    to_wake: AtomicPtr<u8>,    // SignalToken for wake up
-
-    // The number of channels which are currently using this packet.
-    channels: AtomicUsize,
-
-    // See the discussion in Port::drop and the channel send methods for what
-    // these are used for
-    port_dropped: AtomicBool,
-    sender_drain: AtomicIsize,
-
-    // this lock protects various portions of this implementation during
-    // select()
-    select_lock: Mutex<()>,
-}
-
-pub enum Failure {
-    Empty,
-    Disconnected,
-}
-
-#[derive(PartialEq, Eq)]
-enum StartResult {
-    Installed,
-    Abort,
-}
-
-impl<T> Packet<T> {
-    // Creation of a packet *must* be followed by a call to postinit_lock
-    // and later by inherit_blocker
-    pub fn new() -> Packet<T> {
-        Packet {
-            queue: mpsc::Queue::new(),
-            cnt: AtomicIsize::new(0),
-            steals: UnsafeCell::new(0),
-            to_wake: AtomicPtr::new(EMPTY),
-            channels: AtomicUsize::new(2),
-            port_dropped: AtomicBool::new(false),
-            sender_drain: AtomicIsize::new(0),
-            select_lock: Mutex::new(()),
-        }
-    }
-
-    // This function should be used after newly created Packet
-    // was wrapped with an Arc
-    // In other case mutex data will be duplicated while cloning
-    // and that could cause problems on platforms where it is
-    // represented by opaque data structure
-    pub fn postinit_lock(&self) -> MutexGuard<'_, ()> {
-        self.select_lock.lock().unwrap()
-    }
-
-    // This function is used at the creation of a shared packet to inherit a
-    // previously blocked thread. This is done to prevent spurious wakeups of
-    // threads in select().
-    //
-    // This can only be called at channel-creation time
-    pub fn inherit_blocker(&self, token: Option<SignalToken>, guard: MutexGuard<'_, ()>) {
-        if let Some(token) = token {
-            assert_eq!(self.cnt.load(Ordering::SeqCst), 0);
-            assert_eq!(self.to_wake.load(Ordering::SeqCst), EMPTY);
-            self.to_wake.store(unsafe { token.to_raw() }, Ordering::SeqCst);
-            self.cnt.store(-1, Ordering::SeqCst);
-
-            // This store is a little sketchy. What's happening here is that
-            // we're transferring a blocker from a oneshot or stream channel to
-            // this shared channel. In doing so, we never spuriously wake them
-            // up and rather only wake them up at the appropriate time. This
-            // implementation of shared channels assumes that any blocking
-            // recv() will undo the increment of steals performed in try_recv()
-            // once the recv is complete.  This thread that we're inheriting,
-            // however, is not in the middle of recv. Hence, the first time we
-            // wake them up, they're going to wake up from their old port, move
-            // on to the upgraded port, and then call the block recv() function.
-            //
-            // When calling this function, they'll find there's data immediately
-            // available, counting it as a steal. This in fact wasn't a steal
-            // because we appropriately blocked them waiting for data.
-            //
-            // To offset this bad increment, we initially set the steal count to
-            // -1. You'll find some special code in abort_selection() as well to
-            // ensure that this -1 steal count doesn't escape too far.
-            unsafe {
-                *self.steals.get() = -1;
-            }
-        }
-
-        // When the shared packet is constructed, we grabbed this lock. The
-        // purpose of this lock is to ensure that abort_selection() doesn't
-        // interfere with this method. After we unlock this lock, we're
-        // signifying that we're done modifying self.cnt and self.to_wake and
-        // the port is ready for the world to continue using it.
-        drop(guard);
-    }
-
-    pub fn send(&self, t: T) -> Result<(), T> {
-        // See Port::drop for what's going on
-        if self.port_dropped.load(Ordering::SeqCst) {
-            return Err(t);
-        }
-
-        // Note that the multiple sender case is a little trickier
-        // semantically than the single sender case. The logic for
-        // incrementing is "add and if disconnected store disconnected".
-        // This could end up leading some senders to believe that there
-        // wasn't a disconnect if in fact there was a disconnect. This means
-        // that while one thread is attempting to re-store the disconnected
-        // states, other threads could walk through merrily incrementing
-        // this very-negative disconnected count. To prevent senders from
-        // spuriously attempting to send when the channels is actually
-        // disconnected, the count has a ranged check here.
-        //
-        // This is also done for another reason. Remember that the return
-        // value of this function is:
-        //
-        //  `true` == the data *may* be received, this essentially has no
-        //            meaning
-        //  `false` == the data will *never* be received, this has a lot of
-        //             meaning
-        //
-        // In the SPSC case, we have a check of 'queue.is_empty()' to see
-        // whether the data was actually received, but this same condition
-        // means nothing in a multi-producer context. As a result, this
-        // preflight check serves as the definitive "this will never be
-        // received". Once we get beyond this check, we have permanently
-        // entered the realm of "this may be received"
-        if self.cnt.load(Ordering::SeqCst) < DISCONNECTED + FUDGE {
-            return Err(t);
-        }
-
-        self.queue.push(t);
-        match self.cnt.fetch_add(1, Ordering::SeqCst) {
-            -1 => {
-                self.take_to_wake().signal();
-            }
-
-            // In this case, we have possibly failed to send our data, and
-            // we need to consider re-popping the data in order to fully
-            // destroy it. We must arbitrate among the multiple senders,
-            // however, because the queues that we're using are
-            // single-consumer queues. In order to do this, all exiting
-            // pushers will use an atomic count in order to count those
-            // flowing through. Pushers who see 0 are required to drain as
-            // much as possible, and then can only exit when they are the
-            // only pusher (otherwise they must try again).
-            n if n < DISCONNECTED + FUDGE => {
-                // see the comment in 'try' for a shared channel for why this
-                // window of "not disconnected" is ok.
-                self.cnt.store(DISCONNECTED, Ordering::SeqCst);
-
-                if self.sender_drain.fetch_add(1, Ordering::SeqCst) == 0 {
-                    loop {
-                        // drain the queue, for info on the thread yield see the
-                        // discussion in try_recv
-                        loop {
-                            match self.queue.pop() {
-                                mpsc::Data(..) => {}
-                                mpsc::Empty => break,
-                                mpsc::Inconsistent => thread::yield_now(),
-                            }
-                        }
-                        // maybe we're done, if we're not the last ones
-                        // here, then we need to go try again.
-                        if self.sender_drain.fetch_sub(1, Ordering::SeqCst) == 1 {
-                            break;
-                        }
-                    }
-
-                    // At this point, there may still be data on the queue,
-                    // but only if the count hasn't been incremented and
-                    // some other sender hasn't finished pushing data just
-                    // yet. That sender in question will drain its own data.
-                }
-            }
-
-            // Can't make any assumptions about this case like in the SPSC case.
-            _ => {}
-        }
-
-        Ok(())
-    }
-
-    pub fn recv(&self, deadline: Option<Instant>) -> Result<T, Failure> {
-        // This code is essentially the exact same as that found in the stream
-        // case (see stream.rs)
-        match self.try_recv() {
-            Err(Empty) => {}
-            data => return data,
-        }
-
-        let (wait_token, signal_token) = blocking::tokens();
-        if self.decrement(signal_token) == Installed {
-            if let Some(deadline) = deadline {
-                let timed_out = !wait_token.wait_max_until(deadline);
-                if timed_out {
-                    self.abort_selection(false);
-                }
-            } else {
-                wait_token.wait();
-            }
-        }
-
-        match self.try_recv() {
-            data @ Ok(..) => unsafe {
-                *self.steals.get() -= 1;
-                data
-            },
-            data => data,
-        }
-    }
-
-    // Essentially the exact same thing as the stream decrement function.
-    // Returns true if blocking should proceed.
-    fn decrement(&self, token: SignalToken) -> StartResult {
-        unsafe {
-            assert_eq!(
-                self.to_wake.load(Ordering::SeqCst),
-                EMPTY,
-                "This is a known bug in the Rust standard library. See https://github.com/rust-lang/rust/issues/39364"
-            );
-            let ptr = token.to_raw();
-            self.to_wake.store(ptr, Ordering::SeqCst);
-
-            let steals = ptr::replace(self.steals.get(), 0);
-
-            match self.cnt.fetch_sub(1 + steals, Ordering::SeqCst) {
-                DISCONNECTED => {
-                    self.cnt.store(DISCONNECTED, Ordering::SeqCst);
-                }
-                // If we factor in our steals and notice that the channel has no
-                // data, we successfully sleep
-                n => {
-                    assert!(n >= 0);
-                    if n - steals <= 0 {
-                        return Installed;
-                    }
-                }
-            }
-
-            self.to_wake.store(EMPTY, Ordering::SeqCst);
-            drop(SignalToken::from_raw(ptr));
-            Abort
-        }
-    }
-
-    pub fn try_recv(&self) -> Result<T, Failure> {
-        let ret = match self.queue.pop() {
-            mpsc::Data(t) => Some(t),
-            mpsc::Empty => None,
-
-            // This is a bit of an interesting case. The channel is reported as
-            // having data available, but our pop() has failed due to the queue
-            // being in an inconsistent state.  This means that there is some
-            // pusher somewhere which has yet to complete, but we are guaranteed
-            // that a pop will eventually succeed. In this case, we spin in a
-            // yield loop because the remote sender should finish their enqueue
-            // operation "very quickly".
-            //
-            // Avoiding this yield loop would require a different queue
-            // abstraction which provides the guarantee that after M pushes have
-            // succeeded, at least M pops will succeed. The current queues
-            // guarantee that if there are N active pushes, you can pop N times
-            // once all N have finished.
-            mpsc::Inconsistent => {
-                let data;
-                loop {
-                    thread::yield_now();
-                    match self.queue.pop() {
-                        mpsc::Data(t) => {
-                            data = t;
-                            break;
-                        }
-                        mpsc::Empty => panic!("inconsistent => empty"),
-                        mpsc::Inconsistent => {}
-                    }
-                }
-                Some(data)
-            }
-        };
-        match ret {
-            // See the discussion in the stream implementation for why we
-            // might decrement steals.
-            Some(data) => unsafe {
-                if *self.steals.get() > MAX_STEALS {
-                    match self.cnt.swap(0, Ordering::SeqCst) {
-                        DISCONNECTED => {
-                            self.cnt.store(DISCONNECTED, Ordering::SeqCst);
-                        }
-                        n => {
-                            let m = cmp::min(n, *self.steals.get());
-                            *self.steals.get() -= m;
-                            self.bump(n - m);
-                        }
-                    }
-                    assert!(*self.steals.get() >= 0);
-                }
-                *self.steals.get() += 1;
-                Ok(data)
-            },
-
-            // See the discussion in the stream implementation for why we try
-            // again.
-            None => {
-                match self.cnt.load(Ordering::SeqCst) {
-                    n if n != DISCONNECTED => Err(Empty),
-                    _ => {
-                        match self.queue.pop() {
-                            mpsc::Data(t) => Ok(t),
-                            mpsc::Empty => Err(Disconnected),
-                            // with no senders, an inconsistency is impossible.
-                            mpsc::Inconsistent => unreachable!(),
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    // Prepares this shared packet for a channel clone, essentially just bumping
-    // a refcount.
-    pub fn clone_chan(&self) {
-        let old_count = self.channels.fetch_add(1, Ordering::SeqCst);
-
-        // See comments on Arc::clone() on why we do this (for `mem::forget`).
-        if old_count > MAX_REFCOUNT {
-            abort();
-        }
-    }
-
-    // Decrement the reference count on a channel. This is called whenever a
-    // Chan is dropped and may end up waking up a receiver. It's the receiver's
-    // responsibility on the other end to figure out that we've disconnected.
-    pub fn drop_chan(&self) {
-        match self.channels.fetch_sub(1, Ordering::SeqCst) {
-            1 => {}
-            n if n > 1 => return,
-            n => panic!("bad number of channels left {n}"),
-        }
-
-        match self.cnt.swap(DISCONNECTED, Ordering::SeqCst) {
-            -1 => {
-                self.take_to_wake().signal();
-            }
-            DISCONNECTED => {}
-            n => {
-                assert!(n >= 0);
-            }
-        }
-    }
-
-    // See the long discussion inside of stream.rs for why the queue is drained,
-    // and why it is done in this fashion.
-    pub fn drop_port(&self) {
-        self.port_dropped.store(true, Ordering::SeqCst);
-        let mut steals = unsafe { *self.steals.get() };
-        while {
-            match self.cnt.compare_exchange(
-                steals,
-                DISCONNECTED,
-                Ordering::SeqCst,
-                Ordering::SeqCst,
-            ) {
-                Ok(_) => false,
-                Err(old) => old != DISCONNECTED,
-            }
-        } {
-            // See the discussion in 'try_recv' for why we yield
-            // control of this thread.
-            loop {
-                match self.queue.pop() {
-                    mpsc::Data(..) => {
-                        steals += 1;
-                    }
-                    mpsc::Empty | mpsc::Inconsistent => break,
-                }
-            }
-        }
-    }
-
-    // Consumes ownership of the 'to_wake' field.
-    fn take_to_wake(&self) -> SignalToken {
-        let ptr = self.to_wake.load(Ordering::SeqCst);
-        self.to_wake.store(EMPTY, Ordering::SeqCst);
-        assert!(ptr != EMPTY);
-        unsafe { SignalToken::from_raw(ptr) }
-    }
-
-    ////////////////////////////////////////////////////////////////////////////
-    // select implementation
-    ////////////////////////////////////////////////////////////////////////////
-
-    // increment the count on the channel (used for selection)
-    fn bump(&self, amt: isize) -> isize {
-        match self.cnt.fetch_add(amt, Ordering::SeqCst) {
-            DISCONNECTED => {
-                self.cnt.store(DISCONNECTED, Ordering::SeqCst);
-                DISCONNECTED
-            }
-            n => n,
-        }
-    }
-
-    // Cancels a previous thread waiting on this port, returning whether there's
-    // data on the port.
-    //
-    // This is similar to the stream implementation (hence fewer comments), but
-    // uses a different value for the "steals" variable.
-    pub fn abort_selection(&self, _was_upgrade: bool) -> bool {
-        // Before we do anything else, we bounce on this lock. The reason for
-        // doing this is to ensure that any upgrade-in-progress is gone and
-        // done with. Without this bounce, we can race with inherit_blocker
-        // about looking at and dealing with to_wake. Once we have acquired the
-        // lock, we are guaranteed that inherit_blocker is done.
-        {
-            let _guard = self.select_lock.lock().unwrap();
-        }
-
-        // Like the stream implementation, we want to make sure that the count
-        // on the channel goes non-negative. We don't know how negative the
-        // stream currently is, so instead of using a steal value of 1, we load
-        // the channel count and figure out what we should do to make it
-        // positive.
-        let steals = {
-            let cnt = self.cnt.load(Ordering::SeqCst);
-            if cnt < 0 && cnt != DISCONNECTED { -cnt } else { 0 }
-        };
-        let prev = self.bump(steals + 1);
-
-        if prev == DISCONNECTED {
-            assert_eq!(self.to_wake.load(Ordering::SeqCst), EMPTY);
-            true
-        } else {
-            let cur = prev + steals + 1;
-            assert!(cur >= 0);
-            if prev < 0 {
-                drop(self.take_to_wake());
-            } else {
-                while self.to_wake.load(Ordering::SeqCst) != EMPTY {
-                    thread::yield_now();
-                }
-            }
-            unsafe {
-                // if the number of steals is -1, it was the pre-emptive -1 steal
-                // count from when we inherited a blocker. This is fine because
-                // we're just going to overwrite it with a real value.
-                let old = self.steals.get();
-                assert!(*old == 0 || *old == -1);
-                *old = steals;
-                prev >= 0
-            }
-        }
-    }
-}
-
-impl<T> Drop for Packet<T> {
-    fn drop(&mut self) {
-        // Note that this load is not only an assert for correctness about
-        // disconnection, but also a proper fence before the read of
-        // `to_wake`, so this assert cannot be removed with also removing
-        // the `to_wake` assert.
-        assert_eq!(self.cnt.load(Ordering::SeqCst), DISCONNECTED);
-        assert_eq!(self.to_wake.load(Ordering::SeqCst), EMPTY);
-        assert_eq!(self.channels.load(Ordering::SeqCst), 0);
-    }
-}
diff --git a/library/std/src/sync/mpsc/spsc_queue.rs b/library/std/src/sync/mpsc/spsc_queue.rs
deleted file mode 100644 (file)
index 7e745eb..0000000
+++ /dev/null
@@ -1,236 +0,0 @@
-//! A single-producer single-consumer concurrent queue
-//!
-//! This module contains the implementation of an SPSC queue which can be used
-//! concurrently between two threads. This data structure is safe to use and
-//! enforces the semantics that there is one pusher and one popper.
-
-// https://www.1024cores.net/home/lock-free-algorithms/queues/unbounded-spsc-queue
-
-#[cfg(all(test, not(target_os = "emscripten")))]
-mod tests;
-
-use core::cell::UnsafeCell;
-use core::ptr;
-
-use crate::boxed::Box;
-use crate::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
-
-use super::cache_aligned::CacheAligned;
-
-// Node within the linked list queue of messages to send
-struct Node<T> {
-    // FIXME: this could be an uninitialized T if we're careful enough, and
-    //      that would reduce memory usage (and be a bit faster).
-    //      is it worth it?
-    value: Option<T>,         // nullable for re-use of nodes
-    cached: bool,             // This node goes into the node cache
-    next: AtomicPtr<Node<T>>, // next node in the queue
-}
-
-/// The single-producer single-consumer queue. This structure is not cloneable,
-/// but it can be safely shared in an Arc if it is guaranteed that there
-/// is only one popper and one pusher touching the queue at any one point in
-/// time.
-pub struct Queue<T, ProducerAddition = (), ConsumerAddition = ()> {
-    // consumer fields
-    consumer: CacheAligned<Consumer<T, ConsumerAddition>>,
-
-    // producer fields
-    producer: CacheAligned<Producer<T, ProducerAddition>>,
-}
-
-struct Consumer<T, Addition> {
-    tail: UnsafeCell<*mut Node<T>>, // where to pop from
-    tail_prev: AtomicPtr<Node<T>>,  // where to pop from
-    cache_bound: usize,             // maximum cache size
-    cached_nodes: AtomicUsize,      // number of nodes marked as cacheable
-    addition: Addition,
-}
-
-struct Producer<T, Addition> {
-    head: UnsafeCell<*mut Node<T>>,      // where to push to
-    first: UnsafeCell<*mut Node<T>>,     // where to get new nodes from
-    tail_copy: UnsafeCell<*mut Node<T>>, // between first/tail
-    addition: Addition,
-}
-
-unsafe impl<T: Send, P: Send + Sync, C: Send + Sync> Send for Queue<T, P, C> {}
-
-unsafe impl<T: Send, P: Send + Sync, C: Send + Sync> Sync for Queue<T, P, C> {}
-
-impl<T> Node<T> {
-    fn new() -> *mut Node<T> {
-        Box::into_raw(box Node {
-            value: None,
-            cached: false,
-            next: AtomicPtr::new(ptr::null_mut::<Node<T>>()),
-        })
-    }
-}
-
-impl<T, ProducerAddition, ConsumerAddition> Queue<T, ProducerAddition, ConsumerAddition> {
-    /// Creates a new queue. With given additional elements in the producer and
-    /// consumer portions of the queue.
-    ///
-    /// Due to the performance implications of cache-contention,
-    /// we wish to keep fields used mainly by the producer on a separate cache
-    /// line than those used by the consumer.
-    /// Since cache lines are usually 64 bytes, it is unreasonably expensive to
-    /// allocate one for small fields, so we allow users to insert additional
-    /// fields into the cache lines already allocated by this for the producer
-    /// and consumer.
-    ///
-    /// This is unsafe as the type system doesn't enforce a single
-    /// consumer-producer relationship. It also allows the consumer to `pop`
-    /// items while there is a `peek` active due to all methods having a
-    /// non-mutable receiver.
-    ///
-    /// # Arguments
-    ///
-    ///   * `bound` - This queue implementation is implemented with a linked
-    ///               list, and this means that a push is always a malloc. In
-    ///               order to amortize this cost, an internal cache of nodes is
-    ///               maintained to prevent a malloc from always being
-    ///               necessary. This bound is the limit on the size of the
-    ///               cache (if desired). If the value is 0, then the cache has
-    ///               no bound. Otherwise, the cache will never grow larger than
-    ///               `bound` (although the queue itself could be much larger.
-    pub unsafe fn with_additions(
-        bound: usize,
-        producer_addition: ProducerAddition,
-        consumer_addition: ConsumerAddition,
-    ) -> Self {
-        let n1 = Node::new();
-        let n2 = Node::new();
-        (*n1).next.store(n2, Ordering::Relaxed);
-        Queue {
-            consumer: CacheAligned::new(Consumer {
-                tail: UnsafeCell::new(n2),
-                tail_prev: AtomicPtr::new(n1),
-                cache_bound: bound,
-                cached_nodes: AtomicUsize::new(0),
-                addition: consumer_addition,
-            }),
-            producer: CacheAligned::new(Producer {
-                head: UnsafeCell::new(n2),
-                first: UnsafeCell::new(n1),
-                tail_copy: UnsafeCell::new(n1),
-                addition: producer_addition,
-            }),
-        }
-    }
-
-    /// Pushes a new value onto this queue. Note that to use this function
-    /// safely, it must be externally guaranteed that there is only one pusher.
-    pub fn push(&self, t: T) {
-        unsafe {
-            // Acquire a node (which either uses a cached one or allocates a new
-            // one), and then append this to the 'head' node.
-            let n = self.alloc();
-            assert!((*n).value.is_none());
-            (*n).value = Some(t);
-            (*n).next.store(ptr::null_mut(), Ordering::Relaxed);
-            (**self.producer.head.get()).next.store(n, Ordering::Release);
-            *(&self.producer.head).get() = n;
-        }
-    }
-
-    unsafe fn alloc(&self) -> *mut Node<T> {
-        // First try to see if we can consume the 'first' node for our uses.
-        if *self.producer.first.get() != *self.producer.tail_copy.get() {
-            let ret = *self.producer.first.get();
-            *self.producer.0.first.get() = (*ret).next.load(Ordering::Relaxed);
-            return ret;
-        }
-        // If the above fails, then update our copy of the tail and try
-        // again.
-        *self.producer.0.tail_copy.get() = self.consumer.tail_prev.load(Ordering::Acquire);
-        if *self.producer.first.get() != *self.producer.tail_copy.get() {
-            let ret = *self.producer.first.get();
-            *self.producer.0.first.get() = (*ret).next.load(Ordering::Relaxed);
-            return ret;
-        }
-        // If all of that fails, then we have to allocate a new node
-        // (there's nothing in the node cache).
-        Node::new()
-    }
-
-    /// Attempts to pop a value from this queue. Remember that to use this type
-    /// safely you must ensure that there is only one popper at a time.
-    pub fn pop(&self) -> Option<T> {
-        unsafe {
-            // The `tail` node is not actually a used node, but rather a
-            // sentinel from where we should start popping from. Hence, look at
-            // tail's next field and see if we can use it. If we do a pop, then
-            // the current tail node is a candidate for going into the cache.
-            let tail = *self.consumer.tail.get();
-            let next = (*tail).next.load(Ordering::Acquire);
-            if next.is_null() {
-                return None;
-            }
-            assert!((*next).value.is_some());
-            let ret = (*next).value.take();
-
-            *self.consumer.0.tail.get() = next;
-            if self.consumer.cache_bound == 0 {
-                self.consumer.tail_prev.store(tail, Ordering::Release);
-            } else {
-                let cached_nodes = self.consumer.cached_nodes.load(Ordering::Relaxed);
-                if cached_nodes < self.consumer.cache_bound && !(*tail).cached {
-                    self.consumer.cached_nodes.store(cached_nodes, Ordering::Relaxed);
-                    (*tail).cached = true;
-                }
-
-                if (*tail).cached {
-                    self.consumer.tail_prev.store(tail, Ordering::Release);
-                } else {
-                    (*self.consumer.tail_prev.load(Ordering::Relaxed))
-                        .next
-                        .store(next, Ordering::Relaxed);
-                    // We have successfully erased all references to 'tail', so
-                    // now we can safely drop it.
-                    let _: Box<Node<T>> = Box::from_raw(tail);
-                }
-            }
-            ret
-        }
-    }
-
-    /// Attempts to peek at the head of the queue, returning `None` if the queue
-    /// has no data currently
-    ///
-    /// # Warning
-    /// The reference returned is invalid if it is not used before the consumer
-    /// pops the value off the queue. If the producer then pushes another value
-    /// onto the queue, it will overwrite the value pointed to by the reference.
-    pub fn peek(&self) -> Option<&mut T> {
-        // This is essentially the same as above with all the popping bits
-        // stripped out.
-        unsafe {
-            let tail = *self.consumer.tail.get();
-            let next = (*tail).next.load(Ordering::Acquire);
-            if next.is_null() { None } else { (*next).value.as_mut() }
-        }
-    }
-
-    pub fn producer_addition(&self) -> &ProducerAddition {
-        &self.producer.addition
-    }
-
-    pub fn consumer_addition(&self) -> &ConsumerAddition {
-        &self.consumer.addition
-    }
-}
-
-impl<T, ProducerAddition, ConsumerAddition> Drop for Queue<T, ProducerAddition, ConsumerAddition> {
-    fn drop(&mut self) {
-        unsafe {
-            let mut cur = *self.producer.first.get();
-            while !cur.is_null() {
-                let next = (*cur).next.load(Ordering::Relaxed);
-                let _n: Box<Node<T>> = Box::from_raw(cur);
-                cur = next;
-            }
-        }
-    }
-}
diff --git a/library/std/src/sync/mpsc/spsc_queue/tests.rs b/library/std/src/sync/mpsc/spsc_queue/tests.rs
deleted file mode 100644 (file)
index eb6d5c2..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-use super::Queue;
-use crate::sync::mpsc::channel;
-use crate::sync::Arc;
-use crate::thread;
-
-#[test]
-fn smoke() {
-    unsafe {
-        let queue = Queue::with_additions(0, (), ());
-        queue.push(1);
-        queue.push(2);
-        assert_eq!(queue.pop(), Some(1));
-        assert_eq!(queue.pop(), Some(2));
-        assert_eq!(queue.pop(), None);
-        queue.push(3);
-        queue.push(4);
-        assert_eq!(queue.pop(), Some(3));
-        assert_eq!(queue.pop(), Some(4));
-        assert_eq!(queue.pop(), None);
-    }
-}
-
-#[test]
-fn peek() {
-    unsafe {
-        let queue = Queue::with_additions(0, (), ());
-        queue.push(vec![1]);
-
-        // Ensure the borrowchecker works
-        match queue.peek() {
-            Some(vec) => {
-                assert_eq!(&*vec, &[1]);
-            }
-            None => unreachable!(),
-        }
-
-        match queue.pop() {
-            Some(vec) => {
-                assert_eq!(&*vec, &[1]);
-            }
-            None => unreachable!(),
-        }
-    }
-}
-
-#[test]
-fn drop_full() {
-    unsafe {
-        let q: Queue<Box<_>> = Queue::with_additions(0, (), ());
-        q.push(Box::new(1));
-        q.push(Box::new(2));
-    }
-}
-
-#[test]
-fn smoke_bound() {
-    unsafe {
-        let q = Queue::with_additions(0, (), ());
-        q.push(1);
-        q.push(2);
-        assert_eq!(q.pop(), Some(1));
-        assert_eq!(q.pop(), Some(2));
-        assert_eq!(q.pop(), None);
-        q.push(3);
-        q.push(4);
-        assert_eq!(q.pop(), Some(3));
-        assert_eq!(q.pop(), Some(4));
-        assert_eq!(q.pop(), None);
-    }
-}
-
-#[test]
-fn stress() {
-    unsafe {
-        stress_bound(0);
-        stress_bound(1);
-    }
-
-    unsafe fn stress_bound(bound: usize) {
-        let count = if cfg!(miri) { 1000 } else { 100000 };
-        let q = Arc::new(Queue::with_additions(bound, (), ()));
-
-        let (tx, rx) = channel();
-        let q2 = q.clone();
-        let _t = thread::spawn(move || {
-            for _ in 0..count {
-                loop {
-                    match q2.pop() {
-                        Some(1) => break,
-                        Some(_) => panic!(),
-                        None => {}
-                    }
-                }
-            }
-            tx.send(()).unwrap();
-        });
-        for _ in 0..count {
-            q.push(1);
-        }
-        rx.recv().unwrap();
-    }
-}
diff --git a/library/std/src/sync/mpsc/stream.rs b/library/std/src/sync/mpsc/stream.rs
deleted file mode 100644 (file)
index 4592e91..0000000
+++ /dev/null
@@ -1,457 +0,0 @@
-/// Stream channels
-///
-/// This is the flavor of channels which are optimized for one sender and one
-/// receiver. The sender will be upgraded to a shared channel if the channel is
-/// cloned.
-///
-/// High level implementation details can be found in the comment of the parent
-/// module.
-pub use self::Failure::*;
-use self::Message::*;
-pub use self::UpgradeResult::*;
-
-use core::cmp;
-
-use crate::cell::UnsafeCell;
-use crate::ptr;
-use crate::thread;
-use crate::time::Instant;
-
-use crate::sync::atomic::{AtomicBool, AtomicIsize, AtomicPtr, Ordering};
-use crate::sync::mpsc::blocking::{self, SignalToken};
-use crate::sync::mpsc::spsc_queue as spsc;
-use crate::sync::mpsc::Receiver;
-
-const DISCONNECTED: isize = isize::MIN;
-#[cfg(test)]
-const MAX_STEALS: isize = 5;
-#[cfg(not(test))]
-const MAX_STEALS: isize = 1 << 20;
-const EMPTY: *mut u8 = ptr::null_mut(); // initial state: no data, no blocked receiver
-
-pub struct Packet<T> {
-    // internal queue for all messages
-    queue: spsc::Queue<Message<T>, ProducerAddition, ConsumerAddition>,
-}
-
-struct ProducerAddition {
-    cnt: AtomicIsize,       // How many items are on this channel
-    to_wake: AtomicPtr<u8>, // SignalToken for the blocked thread to wake up
-
-    port_dropped: AtomicBool, // flag if the channel has been destroyed.
-}
-
-struct ConsumerAddition {
-    steals: UnsafeCell<isize>, // How many times has a port received without blocking?
-}
-
-pub enum Failure<T> {
-    Empty,
-    Disconnected,
-    Upgraded(Receiver<T>),
-}
-
-pub enum UpgradeResult {
-    UpSuccess,
-    UpDisconnected,
-    UpWoke(SignalToken),
-}
-
-// Any message could contain an "upgrade request" to a new shared port, so the
-// internal queue it's a queue of T, but rather Message<T>
-enum Message<T> {
-    Data(T),
-    GoUp(Receiver<T>),
-}
-
-impl<T> Packet<T> {
-    pub fn new() -> Packet<T> {
-        Packet {
-            queue: unsafe {
-                spsc::Queue::with_additions(
-                    128,
-                    ProducerAddition {
-                        cnt: AtomicIsize::new(0),
-                        to_wake: AtomicPtr::new(EMPTY),
-
-                        port_dropped: AtomicBool::new(false),
-                    },
-                    ConsumerAddition { steals: UnsafeCell::new(0) },
-                )
-            },
-        }
-    }
-
-    pub fn send(&self, t: T) -> Result<(), T> {
-        // If the other port has deterministically gone away, then definitely
-        // must return the data back up the stack. Otherwise, the data is
-        // considered as being sent.
-        if self.queue.producer_addition().port_dropped.load(Ordering::SeqCst) {
-            return Err(t);
-        }
-
-        match self.do_send(Data(t)) {
-            UpSuccess | UpDisconnected => {}
-            UpWoke(token) => {
-                token.signal();
-            }
-        }
-        Ok(())
-    }
-
-    pub fn upgrade(&self, up: Receiver<T>) -> UpgradeResult {
-        // If the port has gone away, then there's no need to proceed any
-        // further.
-        if self.queue.producer_addition().port_dropped.load(Ordering::SeqCst) {
-            return UpDisconnected;
-        }
-
-        self.do_send(GoUp(up))
-    }
-
-    fn do_send(&self, t: Message<T>) -> UpgradeResult {
-        self.queue.push(t);
-        match self.queue.producer_addition().cnt.fetch_add(1, Ordering::SeqCst) {
-            // As described in the mod's doc comment, -1 == wakeup
-            -1 => UpWoke(self.take_to_wake()),
-            // As described before, SPSC queues must be >= -2
-            -2 => UpSuccess,
-
-            // Be sure to preserve the disconnected state, and the return value
-            // in this case is going to be whether our data was received or not.
-            // This manifests itself on whether we have an empty queue or not.
-            //
-            // Primarily, are required to drain the queue here because the port
-            // will never remove this data. We can only have at most one item to
-            // drain (the port drains the rest).
-            DISCONNECTED => {
-                self.queue.producer_addition().cnt.store(DISCONNECTED, Ordering::SeqCst);
-                let first = self.queue.pop();
-                let second = self.queue.pop();
-                assert!(second.is_none());
-
-                match first {
-                    Some(..) => UpSuccess,  // we failed to send the data
-                    None => UpDisconnected, // we successfully sent data
-                }
-            }
-
-            // Otherwise we just sent some data on a non-waiting queue, so just
-            // make sure the world is sane and carry on!
-            n => {
-                assert!(n >= 0);
-                UpSuccess
-            }
-        }
-    }
-
-    // Consumes ownership of the 'to_wake' field.
-    fn take_to_wake(&self) -> SignalToken {
-        let ptr = self.queue.producer_addition().to_wake.load(Ordering::SeqCst);
-        self.queue.producer_addition().to_wake.store(EMPTY, Ordering::SeqCst);
-        assert!(ptr != EMPTY);
-        unsafe { SignalToken::from_raw(ptr) }
-    }
-
-    // Decrements the count on the channel for a sleeper, returning the sleeper
-    // back if it shouldn't sleep. Note that this is the location where we take
-    // steals into account.
-    fn decrement(&self, token: SignalToken) -> Result<(), SignalToken> {
-        assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), EMPTY);
-        let ptr = unsafe { token.to_raw() };
-        self.queue.producer_addition().to_wake.store(ptr, Ordering::SeqCst);
-
-        let steals = unsafe { ptr::replace(self.queue.consumer_addition().steals.get(), 0) };
-
-        match self.queue.producer_addition().cnt.fetch_sub(1 + steals, Ordering::SeqCst) {
-            DISCONNECTED => {
-                self.queue.producer_addition().cnt.store(DISCONNECTED, Ordering::SeqCst);
-            }
-            // If we factor in our steals and notice that the channel has no
-            // data, we successfully sleep
-            n => {
-                assert!(n >= 0);
-                if n - steals <= 0 {
-                    return Ok(());
-                }
-            }
-        }
-
-        self.queue.producer_addition().to_wake.store(EMPTY, Ordering::SeqCst);
-        Err(unsafe { SignalToken::from_raw(ptr) })
-    }
-
-    pub fn recv(&self, deadline: Option<Instant>) -> Result<T, Failure<T>> {
-        // Optimistic preflight check (scheduling is expensive).
-        match self.try_recv() {
-            Err(Empty) => {}
-            data => return data,
-        }
-
-        // Welp, our channel has no data. Deschedule the current thread and
-        // initiate the blocking protocol.
-        let (wait_token, signal_token) = blocking::tokens();
-        if self.decrement(signal_token).is_ok() {
-            if let Some(deadline) = deadline {
-                let timed_out = !wait_token.wait_max_until(deadline);
-                if timed_out {
-                    self.abort_selection(/* was_upgrade = */ false).map_err(Upgraded)?;
-                }
-            } else {
-                wait_token.wait();
-            }
-        }
-
-        match self.try_recv() {
-            // Messages which actually popped from the queue shouldn't count as
-            // a steal, so offset the decrement here (we already have our
-            // "steal" factored into the channel count above).
-            data @ (Ok(..) | Err(Upgraded(..))) => unsafe {
-                *self.queue.consumer_addition().steals.get() -= 1;
-                data
-            },
-
-            data => data,
-        }
-    }
-
-    pub fn try_recv(&self) -> Result<T, Failure<T>> {
-        match self.queue.pop() {
-            // If we stole some data, record to that effect (this will be
-            // factored into cnt later on).
-            //
-            // Note that we don't allow steals to grow without bound in order to
-            // prevent eventual overflow of either steals or cnt as an overflow
-            // would have catastrophic results. Sometimes, steals > cnt, but
-            // other times cnt > steals, so we don't know the relation between
-            // steals and cnt. This code path is executed only rarely, so we do
-            // a pretty slow operation, of swapping 0 into cnt, taking steals
-            // down as much as possible (without going negative), and then
-            // adding back in whatever we couldn't factor into steals.
-            Some(data) => unsafe {
-                if *self.queue.consumer_addition().steals.get() > MAX_STEALS {
-                    match self.queue.producer_addition().cnt.swap(0, Ordering::SeqCst) {
-                        DISCONNECTED => {
-                            self.queue
-                                .producer_addition()
-                                .cnt
-                                .store(DISCONNECTED, Ordering::SeqCst);
-                        }
-                        n => {
-                            let m = cmp::min(n, *self.queue.consumer_addition().steals.get());
-                            *self.queue.consumer_addition().steals.get() -= m;
-                            self.bump(n - m);
-                        }
-                    }
-                    assert!(*self.queue.consumer_addition().steals.get() >= 0);
-                }
-                *self.queue.consumer_addition().steals.get() += 1;
-                match data {
-                    Data(t) => Ok(t),
-                    GoUp(up) => Err(Upgraded(up)),
-                }
-            },
-
-            None => {
-                match self.queue.producer_addition().cnt.load(Ordering::SeqCst) {
-                    n if n != DISCONNECTED => Err(Empty),
-
-                    // This is a little bit of a tricky case. We failed to pop
-                    // data above, and then we have viewed that the channel is
-                    // disconnected. In this window more data could have been
-                    // sent on the channel. It doesn't really make sense to
-                    // return that the channel is disconnected when there's
-                    // actually data on it, so be extra sure there's no data by
-                    // popping one more time.
-                    //
-                    // We can ignore steals because the other end is
-                    // disconnected and we'll never need to really factor in our
-                    // steals again.
-                    _ => match self.queue.pop() {
-                        Some(Data(t)) => Ok(t),
-                        Some(GoUp(up)) => Err(Upgraded(up)),
-                        None => Err(Disconnected),
-                    },
-                }
-            }
-        }
-    }
-
-    pub fn drop_chan(&self) {
-        // Dropping a channel is pretty simple, we just flag it as disconnected
-        // and then wakeup a blocker if there is one.
-        match self.queue.producer_addition().cnt.swap(DISCONNECTED, Ordering::SeqCst) {
-            -1 => {
-                self.take_to_wake().signal();
-            }
-            DISCONNECTED => {}
-            n => {
-                assert!(n >= 0);
-            }
-        }
-    }
-
-    pub fn drop_port(&self) {
-        // Dropping a port seems like a fairly trivial thing. In theory all we
-        // need to do is flag that we're disconnected and then everything else
-        // can take over (we don't have anyone to wake up).
-        //
-        // The catch for Ports is that we want to drop the entire contents of
-        // the queue. There are multiple reasons for having this property, the
-        // largest of which is that if another chan is waiting in this channel
-        // (but not received yet), then waiting on that port will cause a
-        // deadlock.
-        //
-        // So if we accept that we must now destroy the entire contents of the
-        // queue, this code may make a bit more sense. The tricky part is that
-        // we can't let any in-flight sends go un-dropped, we have to make sure
-        // *everything* is dropped and nothing new will come onto the channel.
-
-        // The first thing we do is set a flag saying that we're done for. All
-        // sends are gated on this flag, so we're immediately guaranteed that
-        // there are a bounded number of active sends that we'll have to deal
-        // with.
-        self.queue.producer_addition().port_dropped.store(true, Ordering::SeqCst);
-
-        // Now that we're guaranteed to deal with a bounded number of senders,
-        // we need to drain the queue. This draining process happens atomically
-        // with respect to the "count" of the channel. If the count is nonzero
-        // (with steals taken into account), then there must be data on the
-        // channel. In this case we drain everything and then try again. We will
-        // continue to fail while active senders send data while we're dropping
-        // data, but eventually we're guaranteed to break out of this loop
-        // (because there is a bounded number of senders).
-        let mut steals = unsafe { *self.queue.consumer_addition().steals.get() };
-        while {
-            match self.queue.producer_addition().cnt.compare_exchange(
-                steals,
-                DISCONNECTED,
-                Ordering::SeqCst,
-                Ordering::SeqCst,
-            ) {
-                Ok(_) => false,
-                Err(old) => old != DISCONNECTED,
-            }
-        } {
-            while self.queue.pop().is_some() {
-                steals += 1;
-            }
-        }
-
-        // At this point in time, we have gated all future senders from sending,
-        // and we have flagged the channel as being disconnected. The senders
-        // still have some responsibility, however, because some sends might not
-        // complete until after we flag the disconnection. There are more
-        // details in the sending methods that see DISCONNECTED
-    }
-
-    ////////////////////////////////////////////////////////////////////////////
-    // select implementation
-    ////////////////////////////////////////////////////////////////////////////
-
-    // increment the count on the channel (used for selection)
-    fn bump(&self, amt: isize) -> isize {
-        match self.queue.producer_addition().cnt.fetch_add(amt, Ordering::SeqCst) {
-            DISCONNECTED => {
-                self.queue.producer_addition().cnt.store(DISCONNECTED, Ordering::SeqCst);
-                DISCONNECTED
-            }
-            n => n,
-        }
-    }
-
-    // Removes a previous thread from being blocked in this port
-    pub fn abort_selection(&self, was_upgrade: bool) -> Result<bool, Receiver<T>> {
-        // If we're aborting selection after upgrading from a oneshot, then
-        // we're guarantee that no one is waiting. The only way that we could
-        // have seen the upgrade is if data was actually sent on the channel
-        // half again. For us, this means that there is guaranteed to be data on
-        // this channel. Furthermore, we're guaranteed that there was no
-        // start_selection previously, so there's no need to modify `self.cnt`
-        // at all.
-        //
-        // Hence, because of these invariants, we immediately return `Ok(true)`.
-        // Note that the data might not actually be sent on the channel just yet.
-        // The other end could have flagged the upgrade but not sent data to
-        // this end. This is fine because we know it's a small bounded windows
-        // of time until the data is actually sent.
-        if was_upgrade {
-            assert_eq!(unsafe { *self.queue.consumer_addition().steals.get() }, 0);
-            assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), EMPTY);
-            return Ok(true);
-        }
-
-        // We want to make sure that the count on the channel goes non-negative,
-        // and in the stream case we can have at most one steal, so just assume
-        // that we had one steal.
-        let steals = 1;
-        let prev = self.bump(steals + 1);
-
-        // If we were previously disconnected, then we know for sure that there
-        // is no thread in to_wake, so just keep going
-        let has_data = if prev == DISCONNECTED {
-            assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), EMPTY);
-            true // there is data, that data is that we're disconnected
-        } else {
-            let cur = prev + steals + 1;
-            assert!(cur >= 0);
-
-            // If the previous count was negative, then we just made things go
-            // positive, hence we passed the -1 boundary and we're responsible
-            // for removing the to_wake() field and trashing it.
-            //
-            // If the previous count was positive then we're in a tougher
-            // situation. A possible race is that a sender just incremented
-            // through -1 (meaning it's going to try to wake a thread up), but it
-            // hasn't yet read the to_wake. In order to prevent a future recv()
-            // from waking up too early (this sender picking up the plastered
-            // over to_wake), we spin loop here waiting for to_wake to be 0.
-            // Note that this entire select() implementation needs an overhaul,
-            // and this is *not* the worst part of it, so this is not done as a
-            // final solution but rather out of necessity for now to get
-            // something working.
-            if prev < 0 {
-                drop(self.take_to_wake());
-            } else {
-                while self.queue.producer_addition().to_wake.load(Ordering::SeqCst) != EMPTY {
-                    thread::yield_now();
-                }
-            }
-            unsafe {
-                assert_eq!(*self.queue.consumer_addition().steals.get(), 0);
-                *self.queue.consumer_addition().steals.get() = steals;
-            }
-
-            // if we were previously positive, then there's surely data to
-            // receive
-            prev >= 0
-        };
-
-        // Now that we've determined that this queue "has data", we peek at the
-        // queue to see if the data is an upgrade or not. If it's an upgrade,
-        // then we need to destroy this port and abort selection on the
-        // upgraded port.
-        if has_data {
-            match self.queue.peek() {
-                Some(&mut GoUp(..)) => match self.queue.pop() {
-                    Some(GoUp(port)) => Err(port),
-                    _ => unreachable!(),
-                },
-                _ => Ok(true),
-            }
-        } else {
-            Ok(false)
-        }
-    }
-}
-
-impl<T> Drop for Packet<T> {
-    fn drop(&mut self) {
-        // Note that this load is not only an assert for correctness about
-        // disconnection, but also a proper fence before the read of
-        // `to_wake`, so this assert cannot be removed with also removing
-        // the `to_wake` assert.
-        assert_eq!(self.queue.producer_addition().cnt.load(Ordering::SeqCst), DISCONNECTED);
-        assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), EMPTY);
-    }
-}
diff --git a/library/std/src/sync/mpsc/sync.rs b/library/std/src/sync/mpsc/sync.rs
deleted file mode 100644 (file)
index 7337616..0000000
+++ /dev/null
@@ -1,495 +0,0 @@
-use self::Blocker::*;
-/// Synchronous channels/ports
-///
-/// This channel implementation differs significantly from the asynchronous
-/// implementations found next to it (oneshot/stream/share). This is an
-/// implementation of a synchronous, bounded buffer channel.
-///
-/// Each channel is created with some amount of backing buffer, and sends will
-/// *block* until buffer space becomes available. A buffer size of 0 is valid,
-/// which means that every successful send is paired with a successful recv.
-///
-/// This flavor of channels defines a new `send_opt` method for channels which
-/// is the method by which a message is sent but the thread does not panic if it
-/// cannot be delivered.
-///
-/// Another major difference is that send() will *always* return back the data
-/// if it couldn't be sent. This is because it is deterministically known when
-/// the data is received and when it is not received.
-///
-/// Implementation-wise, it can all be summed up with "use a mutex plus some
-/// logic". The mutex used here is an OS native mutex, meaning that no user code
-/// is run inside of the mutex (to prevent context switching). This
-/// implementation shares almost all code for the buffered and unbuffered cases
-/// of a synchronous channel. There are a few branches for the unbuffered case,
-/// but they're mostly just relevant to blocking senders.
-pub use self::Failure::*;
-
-use core::intrinsics::abort;
-use core::mem;
-use core::ptr;
-
-use crate::sync::atomic::{AtomicUsize, Ordering};
-use crate::sync::mpsc::blocking::{self, SignalToken, WaitToken};
-use crate::sync::{Mutex, MutexGuard};
-use crate::time::Instant;
-
-const MAX_REFCOUNT: usize = (isize::MAX) as usize;
-
-pub struct Packet<T> {
-    /// Only field outside of the mutex. Just done for kicks, but mainly because
-    /// the other shared channel already had the code implemented
-    channels: AtomicUsize,
-
-    lock: Mutex<State<T>>,
-}
-
-unsafe impl<T: Send> Send for Packet<T> {}
-
-unsafe impl<T: Send> Sync for Packet<T> {}
-
-struct State<T> {
-    disconnected: bool, // Is the channel disconnected yet?
-    queue: Queue,       // queue of senders waiting to send data
-    blocker: Blocker,   // currently blocked thread on this channel
-    buf: Buffer<T>,     // storage for buffered messages
-    cap: usize,         // capacity of this channel
-
-    /// A curious flag used to indicate whether a sender failed or succeeded in
-    /// blocking. This is used to transmit information back to the thread that it
-    /// must dequeue its message from the buffer because it was not received.
-    /// This is only relevant in the 0-buffer case. This obviously cannot be
-    /// safely constructed, but it's guaranteed to always have a valid pointer
-    /// value.
-    canceled: Option<&'static mut bool>,
-}
-
-unsafe impl<T: Send> Send for State<T> {}
-
-/// Possible flavors of threads who can be blocked on this channel.
-enum Blocker {
-    BlockedSender(SignalToken),
-    BlockedReceiver(SignalToken),
-    NoneBlocked,
-}
-
-/// Simple queue for threading threads together. Nodes are stack-allocated, so
-/// this structure is not safe at all
-struct Queue {
-    head: *mut Node,
-    tail: *mut Node,
-}
-
-struct Node {
-    token: Option<SignalToken>,
-    next: *mut Node,
-}
-
-unsafe impl Send for Node {}
-
-/// A simple ring-buffer
-struct Buffer<T> {
-    buf: Vec<Option<T>>,
-    start: usize,
-    size: usize,
-}
-
-#[derive(Debug)]
-pub enum Failure {
-    Empty,
-    Disconnected,
-}
-
-/// Atomically blocks the current thread, placing it into `slot`, unlocking `lock`
-/// in the meantime. This re-locks the mutex upon returning.
-fn wait<'a, 'b, T>(
-    lock: &'a Mutex<State<T>>,
-    mut guard: MutexGuard<'b, State<T>>,
-    f: fn(SignalToken) -> Blocker,
-) -> MutexGuard<'a, State<T>> {
-    let (wait_token, signal_token) = blocking::tokens();
-    match mem::replace(&mut guard.blocker, f(signal_token)) {
-        NoneBlocked => {}
-        _ => unreachable!(),
-    }
-    drop(guard); // unlock
-    wait_token.wait(); // block
-    lock.lock().unwrap() // relock
-}
-
-/// Same as wait, but waiting at most until `deadline`.
-fn wait_timeout_receiver<'a, 'b, T>(
-    lock: &'a Mutex<State<T>>,
-    deadline: Instant,
-    mut guard: MutexGuard<'b, State<T>>,
-    success: &mut bool,
-) -> MutexGuard<'a, State<T>> {
-    let (wait_token, signal_token) = blocking::tokens();
-    match mem::replace(&mut guard.blocker, BlockedReceiver(signal_token)) {
-        NoneBlocked => {}
-        _ => unreachable!(),
-    }
-    drop(guard); // unlock
-    *success = wait_token.wait_max_until(deadline); // block
-    let mut new_guard = lock.lock().unwrap(); // relock
-    if !*success {
-        abort_selection(&mut new_guard);
-    }
-    new_guard
-}
-
-fn abort_selection<T>(guard: &mut MutexGuard<'_, State<T>>) -> bool {
-    match mem::replace(&mut guard.blocker, NoneBlocked) {
-        NoneBlocked => true,
-        BlockedSender(token) => {
-            guard.blocker = BlockedSender(token);
-            true
-        }
-        BlockedReceiver(token) => {
-            drop(token);
-            false
-        }
-    }
-}
-
-/// Wakes up a thread, dropping the lock at the correct time
-fn wakeup<T>(token: SignalToken, guard: MutexGuard<'_, State<T>>) {
-    // We need to be careful to wake up the waiting thread *outside* of the mutex
-    // in case it incurs a context switch.
-    drop(guard);
-    token.signal();
-}
-
-impl<T> Packet<T> {
-    pub fn new(capacity: usize) -> Packet<T> {
-        Packet {
-            channels: AtomicUsize::new(1),
-            lock: Mutex::new(State {
-                disconnected: false,
-                blocker: NoneBlocked,
-                cap: capacity,
-                canceled: None,
-                queue: Queue { head: ptr::null_mut(), tail: ptr::null_mut() },
-                buf: Buffer {
-                    buf: (0..capacity + if capacity == 0 { 1 } else { 0 }).map(|_| None).collect(),
-                    start: 0,
-                    size: 0,
-                },
-            }),
-        }
-    }
-
-    // wait until a send slot is available, returning locked access to
-    // the channel state.
-    fn acquire_send_slot(&self) -> MutexGuard<'_, State<T>> {
-        let mut node = Node { token: None, next: ptr::null_mut() };
-        loop {
-            let mut guard = self.lock.lock().unwrap();
-            // are we ready to go?
-            if guard.disconnected || guard.buf.size() < guard.buf.capacity() {
-                return guard;
-            }
-            // no room; actually block
-            let wait_token = guard.queue.enqueue(&mut node);
-            drop(guard);
-            wait_token.wait();
-        }
-    }
-
-    pub fn send(&self, t: T) -> Result<(), T> {
-        let mut guard = self.acquire_send_slot();
-        if guard.disconnected {
-            return Err(t);
-        }
-        guard.buf.enqueue(t);
-
-        match mem::replace(&mut guard.blocker, NoneBlocked) {
-            // if our capacity is 0, then we need to wait for a receiver to be
-            // available to take our data. After waiting, we check again to make
-            // sure the port didn't go away in the meantime. If it did, we need
-            // to hand back our data.
-            NoneBlocked if guard.cap == 0 => {
-                let mut canceled = false;
-                assert!(guard.canceled.is_none());
-                guard.canceled = Some(unsafe { mem::transmute(&mut canceled) });
-                let mut guard = wait(&self.lock, guard, BlockedSender);
-                if canceled { Err(guard.buf.dequeue()) } else { Ok(()) }
-            }
-
-            // success, we buffered some data
-            NoneBlocked => Ok(()),
-
-            // success, someone's about to receive our buffered data.
-            BlockedReceiver(token) => {
-                wakeup(token, guard);
-                Ok(())
-            }
-
-            BlockedSender(..) => panic!("lolwut"),
-        }
-    }
-
-    pub fn try_send(&self, t: T) -> Result<(), super::TrySendError<T>> {
-        let mut guard = self.lock.lock().unwrap();
-        if guard.disconnected {
-            Err(super::TrySendError::Disconnected(t))
-        } else if guard.buf.size() == guard.buf.capacity() {
-            Err(super::TrySendError::Full(t))
-        } else if guard.cap == 0 {
-            // With capacity 0, even though we have buffer space we can't
-            // transfer the data unless there's a receiver waiting.
-            match mem::replace(&mut guard.blocker, NoneBlocked) {
-                NoneBlocked => Err(super::TrySendError::Full(t)),
-                BlockedSender(..) => unreachable!(),
-                BlockedReceiver(token) => {
-                    guard.buf.enqueue(t);
-                    wakeup(token, guard);
-                    Ok(())
-                }
-            }
-        } else {
-            // If the buffer has some space and the capacity isn't 0, then we
-            // just enqueue the data for later retrieval, ensuring to wake up
-            // any blocked receiver if there is one.
-            assert!(guard.buf.size() < guard.buf.capacity());
-            guard.buf.enqueue(t);
-            match mem::replace(&mut guard.blocker, NoneBlocked) {
-                BlockedReceiver(token) => wakeup(token, guard),
-                NoneBlocked => {}
-                BlockedSender(..) => unreachable!(),
-            }
-            Ok(())
-        }
-    }
-
-    // Receives a message from this channel
-    //
-    // When reading this, remember that there can only ever be one receiver at
-    // time.
-    pub fn recv(&self, deadline: Option<Instant>) -> Result<T, Failure> {
-        let mut guard = self.lock.lock().unwrap();
-
-        let mut woke_up_after_waiting = false;
-        // Wait for the buffer to have something in it. No need for a
-        // while loop because we're the only receiver.
-        if !guard.disconnected && guard.buf.size() == 0 {
-            if let Some(deadline) = deadline {
-                guard =
-                    wait_timeout_receiver(&self.lock, deadline, guard, &mut woke_up_after_waiting);
-            } else {
-                guard = wait(&self.lock, guard, BlockedReceiver);
-                woke_up_after_waiting = true;
-            }
-        }
-
-        // N.B., channel could be disconnected while waiting, so the order of
-        // these conditionals is important.
-        if guard.disconnected && guard.buf.size() == 0 {
-            return Err(Disconnected);
-        }
-
-        // Pick up the data, wake up our neighbors, and carry on
-        assert!(guard.buf.size() > 0 || (deadline.is_some() && !woke_up_after_waiting));
-
-        if guard.buf.size() == 0 {
-            return Err(Empty);
-        }
-
-        let ret = guard.buf.dequeue();
-        self.wakeup_senders(woke_up_after_waiting, guard);
-        Ok(ret)
-    }
-
-    pub fn try_recv(&self) -> Result<T, Failure> {
-        let mut guard = self.lock.lock().unwrap();
-
-        // Easy cases first
-        if guard.disconnected && guard.buf.size() == 0 {
-            return Err(Disconnected);
-        }
-        if guard.buf.size() == 0 {
-            return Err(Empty);
-        }
-
-        // Be sure to wake up neighbors
-        let ret = Ok(guard.buf.dequeue());
-        self.wakeup_senders(false, guard);
-        ret
-    }
-
-    // Wake up pending senders after some data has been received
-    //
-    // * `waited` - flag if the receiver blocked to receive some data, or if it
-    //              just picked up some data on the way out
-    // * `guard` - the lock guard that is held over this channel's lock
-    fn wakeup_senders(&self, waited: bool, mut guard: MutexGuard<'_, State<T>>) {
-        let pending_sender1: Option<SignalToken> = guard.queue.dequeue();
-
-        // If this is a no-buffer channel (cap == 0), then if we didn't wait we
-        // need to ACK the sender. If we waited, then the sender waking us up
-        // was already the ACK.
-        let pending_sender2 = if guard.cap == 0 && !waited {
-            match mem::replace(&mut guard.blocker, NoneBlocked) {
-                NoneBlocked => None,
-                BlockedReceiver(..) => unreachable!(),
-                BlockedSender(token) => {
-                    guard.canceled.take();
-                    Some(token)
-                }
-            }
-        } else {
-            None
-        };
-        mem::drop(guard);
-
-        // only outside of the lock do we wake up the pending threads
-        if let Some(token) = pending_sender1 {
-            token.signal();
-        }
-        if let Some(token) = pending_sender2 {
-            token.signal();
-        }
-    }
-
-    // Prepares this shared packet for a channel clone, essentially just bumping
-    // a refcount.
-    pub fn clone_chan(&self) {
-        let old_count = self.channels.fetch_add(1, Ordering::SeqCst);
-
-        // See comments on Arc::clone() on why we do this (for `mem::forget`).
-        if old_count > MAX_REFCOUNT {
-            abort();
-        }
-    }
-
-    pub fn drop_chan(&self) {
-        // Only flag the channel as disconnected if we're the last channel
-        match self.channels.fetch_sub(1, Ordering::SeqCst) {
-            1 => {}
-            _ => return,
-        }
-
-        // Not much to do other than wake up a receiver if one's there
-        let mut guard = self.lock.lock().unwrap();
-        if guard.disconnected {
-            return;
-        }
-        guard.disconnected = true;
-        match mem::replace(&mut guard.blocker, NoneBlocked) {
-            NoneBlocked => {}
-            BlockedSender(..) => unreachable!(),
-            BlockedReceiver(token) => wakeup(token, guard),
-        }
-    }
-
-    pub fn drop_port(&self) {
-        let mut guard = self.lock.lock().unwrap();
-
-        if guard.disconnected {
-            return;
-        }
-        guard.disconnected = true;
-
-        // If the capacity is 0, then the sender may want its data back after
-        // we're disconnected. Otherwise it's now our responsibility to destroy
-        // the buffered data. As with many other portions of this code, this
-        // needs to be careful to destroy the data *outside* of the lock to
-        // prevent deadlock.
-        let _data = if guard.cap != 0 { mem::take(&mut guard.buf.buf) } else { Vec::new() };
-        let mut queue =
-            mem::replace(&mut guard.queue, Queue { head: ptr::null_mut(), tail: ptr::null_mut() });
-
-        let waiter = match mem::replace(&mut guard.blocker, NoneBlocked) {
-            NoneBlocked => None,
-            BlockedSender(token) => {
-                *guard.canceled.take().unwrap() = true;
-                Some(token)
-            }
-            BlockedReceiver(..) => unreachable!(),
-        };
-        mem::drop(guard);
-
-        while let Some(token) = queue.dequeue() {
-            token.signal();
-        }
-        if let Some(token) = waiter {
-            token.signal();
-        }
-    }
-}
-
-impl<T> Drop for Packet<T> {
-    fn drop(&mut self) {
-        assert_eq!(self.channels.load(Ordering::SeqCst), 0);
-        let mut guard = self.lock.lock().unwrap();
-        assert!(guard.queue.dequeue().is_none());
-        assert!(guard.canceled.is_none());
-    }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Buffer, a simple ring buffer backed by Vec<T>
-////////////////////////////////////////////////////////////////////////////////
-
-impl<T> Buffer<T> {
-    fn enqueue(&mut self, t: T) {
-        let pos = (self.start + self.size) % self.buf.len();
-        self.size += 1;
-        let prev = mem::replace(&mut self.buf[pos], Some(t));
-        assert!(prev.is_none());
-    }
-
-    fn dequeue(&mut self) -> T {
-        let start = self.start;
-        self.size -= 1;
-        self.start = (self.start + 1) % self.buf.len();
-        let result = &mut self.buf[start];
-        result.take().unwrap()
-    }
-
-    fn size(&self) -> usize {
-        self.size
-    }
-    fn capacity(&self) -> usize {
-        self.buf.len()
-    }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Queue, a simple queue to enqueue threads with (stack-allocated nodes)
-////////////////////////////////////////////////////////////////////////////////
-
-impl Queue {
-    fn enqueue(&mut self, node: &mut Node) -> WaitToken {
-        let (wait_token, signal_token) = blocking::tokens();
-        node.token = Some(signal_token);
-        node.next = ptr::null_mut();
-
-        if self.tail.is_null() {
-            self.head = node as *mut Node;
-            self.tail = node as *mut Node;
-        } else {
-            unsafe {
-                (*self.tail).next = node as *mut Node;
-                self.tail = node as *mut Node;
-            }
-        }
-
-        wait_token
-    }
-
-    fn dequeue(&mut self) -> Option<SignalToken> {
-        if self.head.is_null() {
-            return None;
-        }
-        let node = self.head;
-        self.head = unsafe { (*node).next };
-        if self.head.is_null() {
-            self.tail = ptr::null_mut();
-        }
-        unsafe {
-            (*node).next = ptr::null_mut();
-            Some((*node).token.take().unwrap())
-        }
-    }
-}
index f6d0796f604fa9c2a4aa3ad65a202fa9d491a932..82c52eb4fef45b6e2cc48bc4e893e2f08d50ee8d 100644 (file)
@@ -706,3 +706,17 @@ fn issue_32114() {
     let _ = tx.send(123);
     assert_eq!(tx.send(123), Err(SendError(123)));
 }
+
+#[test]
+fn issue_39364() {
+    let (tx, rx) = channel::<()>();
+    let t = thread::spawn(move || {
+        thread::sleep(Duration::from_millis(300));
+        let _ = tx.clone();
+        crate::mem::forget(tx);
+    });
+
+    let _ = rx.recv_timeout(Duration::from_millis(500));
+    t.join().unwrap();
+    let _ = rx.recv_timeout(Duration::from_millis(500));
+}
index de851c8fbbed51743776477b338dda1677fd925a..065045f442069feaa75a5d6b46e7b5a707af2b33 100644 (file)
@@ -5,7 +5,7 @@
 use crate::fmt;
 use crate::ops::{Deref, DerefMut};
 use crate::sync::{poison, LockResult, TryLockError, TryLockResult};
-use crate::sys_common::mutex as sys;
+use crate::sys::locks as sys;
 
 /// A mutual exclusion primitive useful for protecting shared data
 ///
 #[stable(feature = "rust1", since = "1.0.0")]
 #[cfg_attr(not(test), rustc_diagnostic_item = "Mutex")]
 pub struct Mutex<T: ?Sized> {
-    inner: sys::MovableMutex,
+    inner: sys::Mutex,
     poison: poison::Flag,
     data: UnsafeCell<T>,
 }
@@ -217,11 +217,7 @@ impl<T> Mutex<T> {
     #[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
     #[inline]
     pub const fn new(t: T) -> Mutex<T> {
-        Mutex {
-            inner: sys::MovableMutex::new(),
-            poison: poison::Flag::new(),
-            data: UnsafeCell::new(t),
-        }
+        Mutex { inner: sys::Mutex::new(), poison: poison::Flag::new(), data: UnsafeCell::new(t) }
     }
 }
 
@@ -264,7 +260,7 @@ impl<T: ?Sized> Mutex<T> {
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn lock(&self) -> LockResult<MutexGuard<'_, T>> {
         unsafe {
-            self.inner.raw_lock();
+            self.inner.lock();
             MutexGuard::new(self)
         }
     }
@@ -526,7 +522,7 @@ impl<T: ?Sized> Drop for MutexGuard<'_, T> {
     fn drop(&mut self) {
         unsafe {
             self.lock.poison.done(&self.poison);
-            self.lock.inner.raw_unlock();
+            self.lock.inner.unlock();
         }
     }
 }
@@ -545,7 +541,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
-pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::MovableMutex {
+pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex {
     &guard.lock.inner
 }
 
index 8b387760768c5603334616b0b5a77b0d36c5152d..7c409cb3e9776e62aab48049f830d81105ff707d 100644 (file)
@@ -6,7 +6,7 @@
 use crate::ops::{Deref, DerefMut};
 use crate::ptr::NonNull;
 use crate::sync::{poison, LockResult, TryLockError, TryLockResult};
-use crate::sys_common::rwlock as sys;
+use crate::sys::locks as sys;
 
 /// A reader-writer lock
 ///
@@ -78,7 +78,7 @@
 #[stable(feature = "rust1", since = "1.0.0")]
 #[cfg_attr(not(test), rustc_diagnostic_item = "RwLock")]
 pub struct RwLock<T: ?Sized> {
-    inner: sys::MovableRwLock,
+    inner: sys::RwLock,
     poison: poison::Flag,
     data: UnsafeCell<T>,
 }
@@ -109,7 +109,7 @@ pub struct RwLockReadGuard<'a, T: ?Sized + 'a> {
     // `NonNull` is also covariant over `T`, just like we would have with `&T`. `NonNull`
     // is preferable over `const* T` to allow for niche optimization.
     data: NonNull<T>,
-    inner_lock: &'a sys::MovableRwLock,
+    inner_lock: &'a sys::RwLock,
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -158,11 +158,7 @@ impl<T> RwLock<T> {
     #[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
     #[inline]
     pub const fn new(t: T) -> RwLock<T> {
-        RwLock {
-            inner: sys::MovableRwLock::new(),
-            poison: poison::Flag::new(),
-            data: UnsafeCell::new(t),
-        }
+        RwLock { inner: sys::RwLock::new(), poison: poison::Flag::new(), data: UnsafeCell::new(t) }
     }
 }
 
index e6534df8938eb531e4ba148dda1f12f600b974ce..6811fadb0188cd5d922e67803262f7676ce81c8a 100644 (file)
@@ -51,9 +51,9 @@ pub mod locks {
     mod futex_condvar;
     mod futex_mutex;
     mod futex_rwlock;
-    pub(crate) use futex_condvar::MovableCondvar;
-    pub(crate) use futex_mutex::{MovableMutex, Mutex};
-    pub(crate) use futex_rwlock::{MovableRwLock, RwLock};
+    pub(crate) use futex_condvar::Condvar;
+    pub(crate) use futex_mutex::Mutex;
+    pub(crate) use futex_rwlock::RwLock;
 }
 
 use crate::io::ErrorKind;
index 008cd8fb1e3926f3dbe5c65bde43afda92ddc31c..f70aa434e48348b3b5289a52cdbc632d2f625b2e 100644 (file)
@@ -12,18 +12,13 @@ pub struct Condvar {
 unsafe impl Send for Condvar {}
 unsafe impl Sync for Condvar {}
 
-pub type MovableCondvar = Condvar;
-
 impl Condvar {
     #[inline]
     pub const fn new() -> Condvar {
         Condvar { waiters: SpinMutex::new(waiter_queue::WaiterQueue::new()) }
     }
 
-    #[inline]
-    pub unsafe fn init(&mut self) {}
-
-    pub unsafe fn notify_one(&self) {
+    pub fn notify_one(&self) {
         self.waiters.with_locked(|waiters| {
             if let Some(task) = waiters.pop_front() {
                 // Unpark the task
@@ -39,7 +34,7 @@ pub unsafe fn notify_one(&self) {
         });
     }
 
-    pub unsafe fn notify_all(&self) {
+    pub fn notify_all(&self) {
         self.waiters.with_locked(|waiters| {
             while let Some(task) = waiters.pop_front() {
                 // Unpark the task
index 085662e6d44b86f55755a8c58b70a9e1d346bf44..f2eed8e771c40ece6fd04b090ae918c3843f694b 100644 (file)
@@ -11,8 +11,6 @@ pub struct Mutex {
     mtx: SpinIdOnceCell<()>,
 }
 
-pub type MovableMutex = Mutex;
-
 /// Create a mutex object. This function never panics.
 fn new_mtx() -> Result<abi::ID, ItronError> {
     ItronError::err_if_negative(unsafe {
@@ -39,7 +37,7 @@ fn raw(&self) -> abi::ID {
         }
     }
 
-    pub unsafe fn lock(&self) {
+    pub fn lock(&self) {
         let mtx = self.raw();
         expect_success(unsafe { abi::loc_mtx(mtx) }, &"loc_mtx");
     }
@@ -49,7 +47,7 @@ pub unsafe fn unlock(&self) {
         expect_success_aborting(unsafe { abi::unl_mtx(mtx) }, &"unl_mtx");
     }
 
-    pub unsafe fn try_lock(&self) -> bool {
+    pub fn try_lock(&self) -> bool {
         let mtx = self.raw();
         match unsafe { abi::ploc_mtx(mtx) } {
             abi::E_TMOUT => false,
index 36534e0eff3fd91595f559ac011de1077a50f53d..aa1174664aeb0966deae0b3343ee063f01e0e6ab 100644 (file)
@@ -4,42 +4,43 @@
 
 use super::waitqueue::{SpinMutex, WaitQueue, WaitVariable};
 
+/// FIXME: `UnsafeList` is not movable.
+struct AllocatedCondvar(SpinMutex<WaitVariable<()>>);
+
 pub struct Condvar {
-    inner: SpinMutex<WaitVariable<()>>,
+    inner: LazyBox<AllocatedCondvar>,
 }
 
-pub(crate) type MovableCondvar = LazyBox<Condvar>;
-
-impl LazyInit for Condvar {
+impl LazyInit for AllocatedCondvar {
     fn init() -> Box<Self> {
-        Box::new(Self::new())
+        Box::new(AllocatedCondvar(SpinMutex::new(WaitVariable::new(()))))
     }
 }
 
 impl Condvar {
     pub const fn new() -> Condvar {
-        Condvar { inner: SpinMutex::new(WaitVariable::new(())) }
+        Condvar { inner: LazyBox::new() }
     }
 
     #[inline]
-    pub unsafe fn notify_one(&self) {
-        let _ = WaitQueue::notify_one(self.inner.lock());
+    pub fn notify_one(&self) {
+        let _ = WaitQueue::notify_one(self.inner.0.lock());
     }
 
     #[inline]
-    pub unsafe fn notify_all(&self) {
-        let _ = WaitQueue::notify_all(self.inner.lock());
+    pub fn notify_all(&self) {
+        let _ = WaitQueue::notify_all(self.inner.0.lock());
     }
 
     pub unsafe fn wait(&self, mutex: &Mutex) {
-        let guard = self.inner.lock();
+        let guard = self.inner.0.lock();
         WaitQueue::wait(guard, || unsafe { mutex.unlock() });
-        unsafe { mutex.lock() }
+        mutex.lock()
     }
 
     pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
-        let success = WaitQueue::wait_timeout(&self.inner, dur, || unsafe { mutex.unlock() });
-        unsafe { mutex.lock() };
+        let success = WaitQueue::wait_timeout(&self.inner.0, dur, || unsafe { mutex.unlock() });
+        mutex.lock();
         success
     }
 }
index aa747d56b0d3bf2b353ee3683c323e2f2e6ef12f..0dbf020ebe06af53bd12e53de14d655aa89001a4 100644 (file)
@@ -1,28 +1,28 @@
 use super::waitqueue::{try_lock_or_false, SpinMutex, WaitQueue, WaitVariable};
 use crate::sys_common::lazy_box::{LazyBox, LazyInit};
 
+/// FIXME: `UnsafeList` is not movable.
+struct AllocatedMutex(SpinMutex<WaitVariable<bool>>);
+
 pub struct Mutex {
-    inner: SpinMutex<WaitVariable<bool>>,
+    inner: LazyBox<AllocatedMutex>,
 }
 
-// not movable: see UnsafeList implementation
-pub(crate) type MovableMutex = LazyBox<Mutex>;
-
-impl LazyInit for Mutex {
+impl LazyInit for AllocatedMutex {
     fn init() -> Box<Self> {
-        Box::new(Self::new())
+        Box::new(AllocatedMutex(SpinMutex::new(WaitVariable::new(false))))
     }
 }
 
 // Implementation according to “Operating Systems: Three Easy Pieces”, chapter 28
 impl Mutex {
     pub const fn new() -> Mutex {
-        Mutex { inner: SpinMutex::new(WaitVariable::new(false)) }
+        Mutex { inner: LazyBox::new() }
     }
 
     #[inline]
-    pub unsafe fn lock(&self) {
-        let mut guard = self.inner.lock();
+    pub fn lock(&self) {
+        let mut guard = self.inner.0.lock();
         if *guard.lock_var() {
             // Another thread has the lock, wait
             WaitQueue::wait(guard, || {})
@@ -35,7 +35,7 @@ pub unsafe fn lock(&self) {
 
     #[inline]
     pub unsafe fn unlock(&self) {
-        let guard = self.inner.lock();
+        let guard = self.inner.0.lock();
         if let Err(mut guard) = WaitQueue::notify_one(guard) {
             // No other waiters, unlock
             *guard.lock_var_mut() = false;
@@ -45,8 +45,8 @@ pub unsafe fn unlock(&self) {
     }
 
     #[inline]
-    pub unsafe fn try_lock(&self) -> bool {
-        let mut guard = try_lock_or_false!(self.inner);
+    pub fn try_lock(&self) -> bool {
+        let mut guard = try_lock_or_false!(self.inner.0);
         if *guard.lock_var() {
             // Another thread has the lock
             false
index a97fb9ab026f02d57cc3f347ac5d62ac891d4c96..d89de18ca5ff8f8295c5e958a655091b3a5aaf1a 100644 (file)
@@ -7,42 +7,45 @@
 use super::waitqueue::{
     try_lock_or_false, NotifiedTcs, SpinMutex, SpinMutexGuard, WaitQueue, WaitVariable,
 };
-use crate::mem;
+use crate::alloc::Layout;
 
-pub struct RwLock {
+struct AllocatedRwLock {
     readers: SpinMutex<WaitVariable<Option<NonZeroUsize>>>,
     writer: SpinMutex<WaitVariable<bool>>,
 }
 
-pub(crate) type MovableRwLock = LazyBox<RwLock>;
+pub struct RwLock {
+    inner: LazyBox<AllocatedRwLock>,
+}
 
-impl LazyInit for RwLock {
+impl LazyInit for AllocatedRwLock {
     fn init() -> Box<Self> {
-        Box::new(Self::new())
+        Box::new(AllocatedRwLock {
+            readers: SpinMutex::new(WaitVariable::new(None)),
+            writer: SpinMutex::new(WaitVariable::new(false)),
+        })
     }
 }
 
-// Check at compile time that RwLock size matches C definition (see test_c_rwlock_initializer below)
-//
-// # Safety
-// Never called, as it is a compile time check.
-#[allow(dead_code)]
-unsafe fn rw_lock_size_assert(r: RwLock) {
-    unsafe { mem::transmute::<RwLock, [u8; 144]>(r) };
-}
+// Check at compile time that RwLock's size and alignment matches the C definition
+// in libunwind (see also `test_c_rwlock_initializer` in `tests`).
+const _: () = {
+    let rust = Layout::new::<RwLock>();
+    let c = Layout::new::<*mut ()>();
+    assert!(rust.size() == c.size());
+    assert!(rust.align() == c.align());
+};
 
 impl RwLock {
     pub const fn new() -> RwLock {
-        RwLock {
-            readers: SpinMutex::new(WaitVariable::new(None)),
-            writer: SpinMutex::new(WaitVariable::new(false)),
-        }
+        RwLock { inner: LazyBox::new() }
     }
 
     #[inline]
-    pub unsafe fn read(&self) {
-        let mut rguard = self.readers.lock();
-        let wguard = self.writer.lock();
+    pub fn read(&self) {
+        let lock = &*self.inner;
+        let mut rguard = lock.readers.lock();
+        let wguard = lock.writer.lock();
         if *wguard.lock_var() || !wguard.queue_empty() {
             // Another thread has or is waiting for the write lock, wait
             drop(wguard);
@@ -57,8 +60,9 @@ pub unsafe fn read(&self) {
 
     #[inline]
     pub unsafe fn try_read(&self) -> bool {
-        let mut rguard = try_lock_or_false!(self.readers);
-        let wguard = try_lock_or_false!(self.writer);
+        let lock = &*self.inner;
+        let mut rguard = try_lock_or_false!(lock.readers);
+        let wguard = try_lock_or_false!(lock.writer);
         if *wguard.lock_var() || !wguard.queue_empty() {
             // Another thread has or is waiting for the write lock
             false
@@ -71,9 +75,10 @@ pub unsafe fn try_read(&self) -> bool {
     }
 
     #[inline]
-    pub unsafe fn write(&self) {
-        let rguard = self.readers.lock();
-        let mut wguard = self.writer.lock();
+    pub fn write(&self) {
+        let lock = &*self.inner;
+        let rguard = lock.readers.lock();
+        let mut wguard = lock.writer.lock();
         if *wguard.lock_var() || rguard.lock_var().is_some() {
             // Another thread has the lock, wait
             drop(rguard);
@@ -86,9 +91,10 @@ pub unsafe fn write(&self) {
     }
 
     #[inline]
-    pub unsafe fn try_write(&self) -> bool {
-        let rguard = try_lock_or_false!(self.readers);
-        let mut wguard = try_lock_or_false!(self.writer);
+    pub fn try_write(&self) -> bool {
+        let lock = &*self.inner;
+        let rguard = try_lock_or_false!(lock.readers);
+        let mut wguard = try_lock_or_false!(lock.writer);
         if *wguard.lock_var() || rguard.lock_var().is_some() {
             // Another thread has the lock
             false
@@ -122,8 +128,9 @@ unsafe fn __read_unlock(
 
     #[inline]
     pub unsafe fn read_unlock(&self) {
-        let rguard = self.readers.lock();
-        let wguard = self.writer.lock();
+        let lock = &*self.inner;
+        let rguard = lock.readers.lock();
+        let wguard = lock.writer.lock();
         unsafe { self.__read_unlock(rguard, wguard) };
     }
 
@@ -158,8 +165,9 @@ unsafe fn __write_unlock(
 
     #[inline]
     pub unsafe fn write_unlock(&self) {
-        let rguard = self.readers.lock();
-        let wguard = self.writer.lock();
+        let lock = &*self.inner;
+        let rguard = lock.readers.lock();
+        let wguard = lock.writer.lock();
         unsafe { self.__write_unlock(rguard, wguard) };
     }
 
@@ -167,8 +175,9 @@ pub unsafe fn write_unlock(&self) {
     #[inline]
     #[cfg_attr(test, allow(dead_code))]
     unsafe fn unlock(&self) {
-        let rguard = self.readers.lock();
-        let wguard = self.writer.lock();
+        let lock = &*self.inner;
+        let rguard = lock.readers.lock();
+        let wguard = lock.writer.lock();
         if *wguard.lock_var() == true {
             unsafe { self.__write_unlock(rguard, wguard) };
         } else {
@@ -201,6 +210,7 @@ unsafe fn unlock(&self) {
     unsafe { (*p).write() };
     return 0;
 }
+
 #[cfg(not(test))]
 #[no_mangle]
 pub unsafe extern "C" fn __rust_rwlock_unlock(p: *mut RwLock) -> i32 {
index 4799961154a475730938d1c42b62ef54c3feb6ef..5fd6670afd4356db2de86376bbd38a00d5d54850 100644 (file)
@@ -1,22 +1,12 @@
 use super::*;
+use crate::ptr;
 
 // Verify that the byte pattern libunwind uses to initialize an RwLock is
 // equivalent to the value of RwLock::new(). If the value changes,
 // `src/UnwindRustSgx.h` in libunwind needs to be changed too.
 #[test]
 fn test_c_rwlock_initializer() {
-    #[rustfmt::skip]
-    const C_RWLOCK_INIT: &[u8] = &[
-        /* 0x00 */ 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
-        /* 0x10 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
-        /* 0x20 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
-        /* 0x30 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
-        /* 0x40 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
-        /* 0x50 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
-        /* 0x60 */ 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
-        /* 0x70 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
-        /* 0x80 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
-    ];
+    const C_RWLOCK_INIT: *mut () = ptr::null_mut();
 
     // For the test to work, we need the padding/unused bytes in RwLock to be
     // initialized as 0. In practice, this is the case with statics.
@@ -26,6 +16,6 @@ fn test_c_rwlock_initializer() {
         // If the assertion fails, that not necessarily an issue with the value
         // of C_RWLOCK_INIT. It might just be an issue with the way padding
         // bytes are initialized in the test code.
-        assert_eq!(&crate::mem::transmute_copy::<_, [u8; 144]>(&RUST_RWLOCK_INIT), C_RWLOCK_INIT);
+        assert_eq!(crate::mem::transmute_copy::<_, *mut ()>(&RUST_RWLOCK_INIT), C_RWLOCK_INIT);
     };
 }
index 0a770cf03f2f5aa17afa9b12b761e26b45905623..ecb4eb83b9b05efa66e40fe48f3e98c9af930585 100644 (file)
@@ -12,8 +12,6 @@ pub struct RwLock {
     rwl: SpinIdOnceCell<()>,
 }
 
-pub type MovableRwLock = RwLock;
-
 // Safety: `num_readers` is protected by `mtx_num_readers`
 unsafe impl Send for RwLock {}
 unsafe impl Sync for RwLock {}
@@ -37,13 +35,13 @@ fn raw(&self) -> abi::ID {
     }
 
     #[inline]
-    pub unsafe fn read(&self) {
+    pub fn read(&self) {
         let rwl = self.raw();
         expect_success(unsafe { abi::rwl_loc_rdl(rwl) }, &"rwl_loc_rdl");
     }
 
     #[inline]
-    pub unsafe fn try_read(&self) -> bool {
+    pub fn try_read(&self) -> bool {
         let rwl = self.raw();
         match unsafe { abi::rwl_ploc_rdl(rwl) } {
             abi::E_TMOUT => false,
@@ -55,13 +53,13 @@ pub unsafe fn try_read(&self) -> bool {
     }
 
     #[inline]
-    pub unsafe fn write(&self) {
+    pub fn write(&self) {
         let rwl = self.raw();
         expect_success(unsafe { abi::rwl_loc_wrl(rwl) }, &"rwl_loc_wrl");
     }
 
     #[inline]
-    pub unsafe fn try_write(&self) -> bool {
+    pub fn try_write(&self) -> bool {
         let rwl = self.raw();
         match unsafe { abi::rwl_ploc_wrl(rwl) } {
             abi::E_TMOUT => false,
index 117611ce43f2490c891112fb79e727edc588166d..5d89e5a13fd366fec28cd38e7d02c3c1b7ec0720 100644 (file)
@@ -53,8 +53,6 @@
 // This can never be a valid `zx_handle_t`.
 const UNLOCKED: u32 = 0;
 
-pub type MovableMutex = Mutex;
-
 pub struct Mutex {
     futex: AtomicU32,
 }
@@ -86,23 +84,27 @@ pub const fn new() -> Mutex {
     }
 
     #[inline]
-    pub unsafe fn try_lock(&self) -> bool {
-        let thread_self = zx_thread_self();
+    pub fn try_lock(&self) -> bool {
+        let thread_self = unsafe { zx_thread_self() };
         self.futex.compare_exchange(UNLOCKED, to_state(thread_self), Acquire, Relaxed).is_ok()
     }
 
     #[inline]
-    pub unsafe fn lock(&self) {
-        let thread_self = zx_thread_self();
+    pub fn lock(&self) {
+        let thread_self = unsafe { zx_thread_self() };
         if let Err(state) =
             self.futex.compare_exchange(UNLOCKED, to_state(thread_self), Acquire, Relaxed)
         {
-            self.lock_contested(state, thread_self);
+            unsafe {
+                self.lock_contested(state, thread_self);
+            }
         }
     }
 
+    /// # Safety
+    /// `thread_self` must be the handle for the current thread.
     #[cold]
-    fn lock_contested(&self, mut state: u32, thread_self: zx_handle_t) {
+    unsafe fn lock_contested(&self, mut state: u32, thread_self: zx_handle_t) {
         let owned_state = mark_contested(to_state(thread_self));
         loop {
             // Mark the mutex as contested if it is not already.
index c0576c17880e1127f94add57997e2c9862c33b68..4bd65dd25c2921c5a91a05013b3ce99346f247f6 100644 (file)
@@ -3,8 +3,6 @@
 use crate::sys::futex::{futex_wait, futex_wake, futex_wake_all};
 use crate::time::Duration;
 
-pub type MovableCondvar = Condvar;
-
 pub struct Condvar {
     // The value of this atomic is simply incremented on every notification.
     // This is used by `.wait()` to not miss any notifications after
@@ -21,12 +19,12 @@ pub const fn new() -> Self {
     // All the memory orderings here are `Relaxed`,
     // because synchronization is done by unlocking and locking the mutex.
 
-    pub unsafe fn notify_one(&self) {
+    pub fn notify_one(&self) {
         self.futex.fetch_add(1, Relaxed);
         futex_wake(&self.futex);
     }
 
-    pub unsafe fn notify_all(&self) {
+    pub fn notify_all(&self) {
         self.futex.fetch_add(1, Relaxed);
         futex_wake_all(&self.futex);
     }
index 33b13dad4d65d08a17941bf1a1209cd5913a76a2..c01229586c30201c51cad01cbd328f1986f330f2 100644 (file)
@@ -4,8 +4,6 @@
 };
 use crate::sys::futex::{futex_wait, futex_wake};
 
-pub type MovableMutex = Mutex;
-
 pub struct Mutex {
     /// 0: unlocked
     /// 1: locked, no other threads waiting
@@ -20,12 +18,12 @@ pub const fn new() -> Self {
     }
 
     #[inline]
-    pub unsafe fn try_lock(&self) -> bool {
+    pub fn try_lock(&self) -> bool {
         self.futex.compare_exchange(0, 1, Acquire, Relaxed).is_ok()
     }
 
     #[inline]
-    pub unsafe fn lock(&self) {
+    pub fn lock(&self) {
         if self.futex.compare_exchange(0, 1, Acquire, Relaxed).is_err() {
             self.lock_contended();
         }
index 0cc92244ecad3a195e2eecb5d18a6792ebf5146a..aa0de900238f5466bb664ada645da0b066982779 100644 (file)
@@ -4,8 +4,6 @@
 };
 use crate::sys::futex::{futex_wait, futex_wake, futex_wake_all};
 
-pub type MovableRwLock = RwLock;
-
 pub struct RwLock {
     // The state consists of a 30-bit reader counter, a 'readers waiting' flag, and a 'writers waiting' flag.
     // Bits 0..30:
@@ -70,14 +68,14 @@ pub const fn new() -> Self {
     }
 
     #[inline]
-    pub unsafe fn try_read(&self) -> bool {
+    pub fn try_read(&self) -> bool {
         self.state
             .fetch_update(Acquire, Relaxed, |s| is_read_lockable(s).then(|| s + READ_LOCKED))
             .is_ok()
     }
 
     #[inline]
-    pub unsafe fn read(&self) {
+    pub fn read(&self) {
         let state = self.state.load(Relaxed);
         if !is_read_lockable(state)
             || self
@@ -144,14 +142,14 @@ fn read_contended(&self) {
     }
 
     #[inline]
-    pub unsafe fn try_write(&self) -> bool {
+    pub fn try_write(&self) -> bool {
         self.state
             .fetch_update(Acquire, Relaxed, |s| is_unlocked(s).then(|| s + WRITE_LOCKED))
             .is_ok()
     }
 
     #[inline]
-    pub unsafe fn write(&self) {
+    pub fn write(&self) {
         if self.state.compare_exchange_weak(0, WRITE_LOCKED, Acquire, Relaxed).is_err() {
             self.write_contended();
         }
index 9bb314b7010a572686bd3a0e116356f39cd57e6b..b2e0e49ad736d6e00a3e394d998d9c6a8e59e547 100644 (file)
         mod futex_mutex;
         mod futex_rwlock;
         mod futex_condvar;
-        pub(crate) use futex_mutex::{Mutex, MovableMutex};
-        pub(crate) use futex_rwlock::MovableRwLock;
-        pub(crate) use futex_condvar::MovableCondvar;
+        pub(crate) use futex_mutex::Mutex;
+        pub(crate) use futex_rwlock::RwLock;
+        pub(crate) use futex_condvar::Condvar;
     } else if #[cfg(target_os = "fuchsia")] {
         mod fuchsia_mutex;
         mod futex_rwlock;
         mod futex_condvar;
-        pub(crate) use fuchsia_mutex::{Mutex, MovableMutex};
-        pub(crate) use futex_rwlock::MovableRwLock;
-        pub(crate) use futex_condvar::MovableCondvar;
+        pub(crate) use fuchsia_mutex::Mutex;
+        pub(crate) use futex_rwlock::RwLock;
+        pub(crate) use futex_condvar::Condvar;
     } else {
         mod pthread_mutex;
         mod pthread_rwlock;
         mod pthread_condvar;
-        pub(crate) use pthread_mutex::{Mutex, MovableMutex};
-        pub(crate) use pthread_rwlock::MovableRwLock;
-        pub(crate) use pthread_condvar::MovableCondvar;
+        pub(crate) use pthread_mutex::Mutex;
+        pub(crate) use pthread_rwlock::RwLock;
+        pub(crate) use pthread_condvar::Condvar;
     }
 }
index 4741c0c6736e37f1a28c6a1b9468df1eceeabe84..1ddb09905db2cfa0f3002535eb8729c3400310b9 100644 (file)
@@ -1,17 +1,17 @@
 use crate::cell::UnsafeCell;
+use crate::ptr;
+use crate::sync::atomic::{AtomicPtr, Ordering::Relaxed};
 use crate::sys::locks::{pthread_mutex, Mutex};
 use crate::sys_common::lazy_box::{LazyBox, LazyInit};
 use crate::time::Duration;
 
+struct AllocatedCondvar(UnsafeCell<libc::pthread_cond_t>);
+
 pub struct Condvar {
-    inner: UnsafeCell<libc::pthread_cond_t>,
+    inner: LazyBox<AllocatedCondvar>,
+    mutex: AtomicPtr<libc::pthread_mutex_t>,
 }
 
-pub(crate) type MovableCondvar = LazyBox<Condvar>;
-
-unsafe impl Send for Condvar {}
-unsafe impl Sync for Condvar {}
-
 const TIMESPEC_MAX: libc::timespec =
     libc::timespec { tv_sec: <libc::time_t>::MAX, tv_nsec: 1_000_000_000 - 1 };
 
@@ -19,81 +19,104 @@ fn saturating_cast_to_time_t(value: u64) -> libc::time_t {
     if value > <libc::time_t>::MAX as u64 { <libc::time_t>::MAX } else { value as libc::time_t }
 }
 
-impl LazyInit for Condvar {
+#[inline]
+fn raw(c: &Condvar) -> *mut libc::pthread_cond_t {
+    c.inner.0.get()
+}
+
+unsafe impl Send for AllocatedCondvar {}
+unsafe impl Sync for AllocatedCondvar {}
+
+impl LazyInit for AllocatedCondvar {
     fn init() -> Box<Self> {
-        let mut condvar = Box::new(Self::new());
-        unsafe { condvar.init() };
+        let condvar = Box::new(AllocatedCondvar(UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER)));
+
+        cfg_if::cfg_if! {
+            if #[cfg(any(
+                target_os = "macos",
+                target_os = "ios",
+                target_os = "watchos",
+                target_os = "l4re",
+                target_os = "android",
+                target_os = "redox"
+            ))] {
+                // `pthread_condattr_setclock` is unfortunately not supported on these platforms.
+            } else if #[cfg(any(target_os = "espidf", target_os = "horizon"))] {
+                // NOTE: ESP-IDF's PTHREAD_COND_INITIALIZER support is not released yet
+                // So on that platform, init() should always be called
+                // Moreover, that platform does not have pthread_condattr_setclock support,
+                // hence that initialization should be skipped as well
+                //
+                // Similar story for the 3DS (horizon).
+                let r = unsafe { libc::pthread_cond_init(condvar.0.get(), crate::ptr::null()) };
+                assert_eq!(r, 0);
+            } else {
+                use crate::mem::MaybeUninit;
+                let mut attr = MaybeUninit::<libc::pthread_condattr_t>::uninit();
+                let r = unsafe { libc::pthread_condattr_init(attr.as_mut_ptr()) };
+                assert_eq!(r, 0);
+                let r = unsafe { libc::pthread_condattr_setclock(attr.as_mut_ptr(), libc::CLOCK_MONOTONIC) };
+                assert_eq!(r, 0);
+                let r = unsafe { libc::pthread_cond_init(condvar.0.get(), attr.as_ptr()) };
+                assert_eq!(r, 0);
+                let r = unsafe { libc::pthread_condattr_destroy(attr.as_mut_ptr()) };
+                assert_eq!(r, 0);
+            }
+        }
+
         condvar
     }
 }
 
-impl Condvar {
-    pub const fn new() -> Condvar {
-        // Might be moved and address is changing it is better to avoid
-        // initialization of potentially opaque OS data before it landed
-        Condvar { inner: UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER) }
+impl Drop for AllocatedCondvar {
+    #[inline]
+    fn drop(&mut self) {
+        let r = unsafe { libc::pthread_cond_destroy(self.0.get()) };
+        if cfg!(target_os = "dragonfly") {
+            // On DragonFly pthread_cond_destroy() returns EINVAL if called on
+            // a condvar that was just initialized with
+            // libc::PTHREAD_COND_INITIALIZER. Once it is used or
+            // pthread_cond_init() is called, this behaviour no longer occurs.
+            debug_assert!(r == 0 || r == libc::EINVAL);
+        } else {
+            debug_assert_eq!(r, 0);
+        }
     }
+}
 
-    #[cfg(any(
-        target_os = "macos",
-        target_os = "ios",
-        target_os = "watchos",
-        target_os = "l4re",
-        target_os = "android",
-        target_os = "redox"
-    ))]
-    unsafe fn init(&mut self) {}
-
-    // NOTE: ESP-IDF's PTHREAD_COND_INITIALIZER support is not released yet
-    // So on that platform, init() should always be called
-    // Moreover, that platform does not have pthread_condattr_setclock support,
-    // hence that initialization should be skipped as well
-    //
-    // Similar story for the 3DS (horizon).
-    #[cfg(any(target_os = "espidf", target_os = "horizon"))]
-    unsafe fn init(&mut self) {
-        let r = libc::pthread_cond_init(self.inner.get(), crate::ptr::null());
-        assert_eq!(r, 0);
+impl Condvar {
+    pub const fn new() -> Condvar {
+        Condvar { inner: LazyBox::new(), mutex: AtomicPtr::new(ptr::null_mut()) }
     }
 
-    #[cfg(not(any(
-        target_os = "macos",
-        target_os = "ios",
-        target_os = "watchos",
-        target_os = "l4re",
-        target_os = "android",
-        target_os = "redox",
-        target_os = "espidf",
-        target_os = "horizon"
-    )))]
-    unsafe fn init(&mut self) {
-        use crate::mem::MaybeUninit;
-        let mut attr = MaybeUninit::<libc::pthread_condattr_t>::uninit();
-        let r = libc::pthread_condattr_init(attr.as_mut_ptr());
-        assert_eq!(r, 0);
-        let r = libc::pthread_condattr_setclock(attr.as_mut_ptr(), libc::CLOCK_MONOTONIC);
-        assert_eq!(r, 0);
-        let r = libc::pthread_cond_init(self.inner.get(), attr.as_ptr());
-        assert_eq!(r, 0);
-        let r = libc::pthread_condattr_destroy(attr.as_mut_ptr());
-        assert_eq!(r, 0);
+    #[inline]
+    fn verify(&self, mutex: *mut libc::pthread_mutex_t) {
+        // Relaxed is okay here because we never read through `self.addr`, and only use it to
+        // compare addresses.
+        match self.mutex.compare_exchange(ptr::null_mut(), mutex, Relaxed, Relaxed) {
+            Ok(_) => {}                // Stored the address
+            Err(n) if n == mutex => {} // Lost a race to store the same address
+            _ => panic!("attempted to use a condition variable with two mutexes"),
+        }
     }
 
     #[inline]
-    pub unsafe fn notify_one(&self) {
-        let r = libc::pthread_cond_signal(self.inner.get());
+    pub fn notify_one(&self) {
+        let r = unsafe { libc::pthread_cond_signal(raw(self)) };
         debug_assert_eq!(r, 0);
     }
 
     #[inline]
-    pub unsafe fn notify_all(&self) {
-        let r = libc::pthread_cond_broadcast(self.inner.get());
+    pub fn notify_all(&self) {
+        let r = unsafe { libc::pthread_cond_broadcast(raw(self)) };
         debug_assert_eq!(r, 0);
     }
 
     #[inline]
     pub unsafe fn wait(&self, mutex: &Mutex) {
-        let r = libc::pthread_cond_wait(self.inner.get(), pthread_mutex::raw(mutex));
+        let mutex = pthread_mutex::raw(mutex);
+        self.verify(mutex);
+        let r = libc::pthread_cond_wait(raw(self), mutex);
         debug_assert_eq!(r, 0);
     }
 
@@ -112,6 +135,9 @@ pub unsafe fn wait(&self, mutex: &Mutex) {
     pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
         use crate::mem;
 
+        let mutex = pthread_mutex::raw(mutex);
+        self.verify(mutex);
+
         let mut now: libc::timespec = mem::zeroed();
         let r = libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut now);
         assert_eq!(r, 0);
@@ -127,7 +153,7 @@ pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
         let timeout =
             sec.map(|s| libc::timespec { tv_sec: s, tv_nsec: nsec as _ }).unwrap_or(TIMESPEC_MAX);
 
-        let r = libc::pthread_cond_timedwait(self.inner.get(), pthread_mutex::raw(mutex), &timeout);
+        let r = libc::pthread_cond_timedwait(raw(self), mutex, &timeout);
         assert!(r == libc::ETIMEDOUT || r == 0);
         r == 0
     }
@@ -144,9 +170,11 @@ pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
         target_os = "horizon"
     ))]
     pub unsafe fn wait_timeout(&self, mutex: &Mutex, mut dur: Duration) -> bool {
-        use crate::ptr;
         use crate::time::Instant;
 
+        let mutex = pthread_mutex::raw(mutex);
+        self.verify(mutex);
+
         // 1000 years
         let max_dur = Duration::from_secs(1000 * 365 * 86400);
 
@@ -187,36 +215,11 @@ pub unsafe fn wait_timeout(&self, mutex: &Mutex, mut dur: Duration) -> bool {
             .unwrap_or(TIMESPEC_MAX);
 
         // And wait!
-        let r = libc::pthread_cond_timedwait(self.inner.get(), pthread_mutex::raw(mutex), &timeout);
+        let r = libc::pthread_cond_timedwait(raw(self), mutex, &timeout);
         debug_assert!(r == libc::ETIMEDOUT || r == 0);
 
         // ETIMEDOUT is not a totally reliable method of determining timeout due
         // to clock shifts, so do the check ourselves
         stable_now.elapsed() < dur
     }
-
-    #[inline]
-    #[cfg(not(target_os = "dragonfly"))]
-    unsafe fn destroy(&mut self) {
-        let r = libc::pthread_cond_destroy(self.inner.get());
-        debug_assert_eq!(r, 0);
-    }
-
-    #[inline]
-    #[cfg(target_os = "dragonfly")]
-    unsafe fn destroy(&mut self) {
-        let r = libc::pthread_cond_destroy(self.inner.get());
-        // On DragonFly pthread_cond_destroy() returns EINVAL if called on
-        // a condvar that was just initialized with
-        // libc::PTHREAD_COND_INITIALIZER. Once it is used or
-        // pthread_cond_init() is called, this behaviour no longer occurs.
-        debug_assert!(r == 0 || r == libc::EINVAL);
-    }
-}
-
-impl Drop for Condvar {
-    #[inline]
-    fn drop(&mut self) {
-        unsafe { self.destroy() };
-    }
 }
index 5964935ddb541527c783f9fc551584d873f67d42..8a78bc1fd739904141deda9cafaba58b91a8f624 100644 (file)
@@ -3,56 +3,24 @@
 use crate::sys::cvt_nz;
 use crate::sys_common::lazy_box::{LazyBox, LazyInit};
 
+struct AllocatedMutex(UnsafeCell<libc::pthread_mutex_t>);
+
 pub struct Mutex {
-    inner: UnsafeCell<libc::pthread_mutex_t>,
+    inner: LazyBox<AllocatedMutex>,
 }
 
-pub(crate) type MovableMutex = LazyBox<Mutex>;
-
 #[inline]
 pub unsafe fn raw(m: &Mutex) -> *mut libc::pthread_mutex_t {
-    m.inner.get()
+    m.inner.0.get()
 }
 
-unsafe impl Send for Mutex {}
-unsafe impl Sync for Mutex {}
+unsafe impl Send for AllocatedMutex {}
+unsafe impl Sync for AllocatedMutex {}
 
-impl LazyInit for Mutex {
+impl LazyInit for AllocatedMutex {
     fn init() -> Box<Self> {
-        let mut mutex = Box::new(Self::new());
-        unsafe { mutex.init() };
-        mutex
-    }
-
-    fn destroy(mutex: Box<Self>) {
-        // We're not allowed to pthread_mutex_destroy a locked mutex,
-        // so check first if it's unlocked.
-        if unsafe { mutex.try_lock() } {
-            unsafe { mutex.unlock() };
-            drop(mutex);
-        } else {
-            // The mutex is locked. This happens if a MutexGuard is leaked.
-            // In this case, we just leak the Mutex too.
-            forget(mutex);
-        }
-    }
-
-    fn cancel_init(_: Box<Self>) {
-        // In this case, we can just drop it without any checks,
-        // since it cannot have been locked yet.
-    }
-}
+        let mutex = Box::new(AllocatedMutex(UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER)));
 
-impl Mutex {
-    pub const fn new() -> Mutex {
-        // Might be moved to a different address, so it is better to avoid
-        // initialization of potentially opaque OS data before it landed.
-        // Be very careful using this newly constructed `Mutex`, reentrant
-        // locking is undefined behavior until `init` is called!
-        Mutex { inner: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER) }
-    }
-    #[inline]
-    unsafe fn init(&mut self) {
         // Issue #33770
         //
         // A pthread mutex initialized with PTHREAD_MUTEX_INITIALIZER will have
@@ -77,49 +45,77 @@ unsafe fn init(&mut self) {
         // references, we instead create the mutex with type
         // PTHREAD_MUTEX_NORMAL which is guaranteed to deadlock if we try to
         // re-lock it from the same thread, thus avoiding undefined behavior.
-        let mut attr = MaybeUninit::<libc::pthread_mutexattr_t>::uninit();
-        cvt_nz(libc::pthread_mutexattr_init(attr.as_mut_ptr())).unwrap();
-        let attr = PthreadMutexAttr(&mut attr);
-        cvt_nz(libc::pthread_mutexattr_settype(attr.0.as_mut_ptr(), libc::PTHREAD_MUTEX_NORMAL))
+        unsafe {
+            let mut attr = MaybeUninit::<libc::pthread_mutexattr_t>::uninit();
+            cvt_nz(libc::pthread_mutexattr_init(attr.as_mut_ptr())).unwrap();
+            let attr = PthreadMutexAttr(&mut attr);
+            cvt_nz(libc::pthread_mutexattr_settype(
+                attr.0.as_mut_ptr(),
+                libc::PTHREAD_MUTEX_NORMAL,
+            ))
             .unwrap();
-        cvt_nz(libc::pthread_mutex_init(self.inner.get(), attr.0.as_ptr())).unwrap();
+            cvt_nz(libc::pthread_mutex_init(mutex.0.get(), attr.0.as_ptr())).unwrap();
+        }
+
+        mutex
     }
-    #[inline]
-    pub unsafe fn lock(&self) {
-        let r = libc::pthread_mutex_lock(self.inner.get());
-        debug_assert_eq!(r, 0);
+
+    fn destroy(mutex: Box<Self>) {
+        // We're not allowed to pthread_mutex_destroy a locked mutex,
+        // so check first if it's unlocked.
+        if unsafe { libc::pthread_mutex_trylock(mutex.0.get()) == 0 } {
+            unsafe { libc::pthread_mutex_unlock(mutex.0.get()) };
+            drop(mutex);
+        } else {
+            // The mutex is locked. This happens if a MutexGuard is leaked.
+            // In this case, we just leak the Mutex too.
+            forget(mutex);
+        }
     }
+
+    fn cancel_init(_: Box<Self>) {
+        // In this case, we can just drop it without any checks,
+        // since it cannot have been locked yet.
+    }
+}
+
+impl Drop for AllocatedMutex {
     #[inline]
-    pub unsafe fn unlock(&self) {
-        let r = libc::pthread_mutex_unlock(self.inner.get());
-        debug_assert_eq!(r, 0);
+    fn drop(&mut self) {
+        let r = unsafe { libc::pthread_mutex_destroy(self.0.get()) };
+        if cfg!(target_os = "dragonfly") {
+            // On DragonFly pthread_mutex_destroy() returns EINVAL if called on a
+            // mutex that was just initialized with libc::PTHREAD_MUTEX_INITIALIZER.
+            // Once it is used (locked/unlocked) or pthread_mutex_init() is called,
+            // this behaviour no longer occurs.
+            debug_assert!(r == 0 || r == libc::EINVAL);
+        } else {
+            debug_assert_eq!(r, 0);
+        }
     }
+}
+
+impl Mutex {
     #[inline]
-    pub unsafe fn try_lock(&self) -> bool {
-        libc::pthread_mutex_trylock(self.inner.get()) == 0
+    pub const fn new() -> Mutex {
+        Mutex { inner: LazyBox::new() }
     }
+
     #[inline]
-    #[cfg(not(target_os = "dragonfly"))]
-    unsafe fn destroy(&mut self) {
-        let r = libc::pthread_mutex_destroy(self.inner.get());
+    pub unsafe fn lock(&self) {
+        let r = libc::pthread_mutex_lock(raw(self));
         debug_assert_eq!(r, 0);
     }
+
     #[inline]
-    #[cfg(target_os = "dragonfly")]
-    unsafe fn destroy(&mut self) {
-        let r = libc::pthread_mutex_destroy(self.inner.get());
-        // On DragonFly pthread_mutex_destroy() returns EINVAL if called on a
-        // mutex that was just initialized with libc::PTHREAD_MUTEX_INITIALIZER.
-        // Once it is used (locked/unlocked) or pthread_mutex_init() is called,
-        // this behaviour no longer occurs.
-        debug_assert!(r == 0 || r == libc::EINVAL);
+    pub unsafe fn unlock(&self) {
+        let r = libc::pthread_mutex_unlock(raw(self));
+        debug_assert_eq!(r, 0);
     }
-}
 
-impl Drop for Mutex {
     #[inline]
-    fn drop(&mut self) {
-        unsafe { self.destroy() };
+    pub unsafe fn try_lock(&self) -> bool {
+        libc::pthread_mutex_trylock(raw(self)) == 0
     }
 }
 
index adfe2a88338f55bbca7f7052254d9d5bfeb5d072..04662be9d8275e514d61cf7126e17bfdda1a9b20 100644 (file)
@@ -3,20 +3,26 @@
 use crate::sync::atomic::{AtomicUsize, Ordering};
 use crate::sys_common::lazy_box::{LazyBox, LazyInit};
 
-pub struct RwLock {
+struct AllocatedRwLock {
     inner: UnsafeCell<libc::pthread_rwlock_t>,
     write_locked: UnsafeCell<bool>, // guarded by the `inner` RwLock
     num_readers: AtomicUsize,
 }
 
-pub(crate) type MovableRwLock = LazyBox<RwLock>;
+unsafe impl Send for AllocatedRwLock {}
+unsafe impl Sync for AllocatedRwLock {}
 
-unsafe impl Send for RwLock {}
-unsafe impl Sync for RwLock {}
+pub struct RwLock {
+    inner: LazyBox<AllocatedRwLock>,
+}
 
-impl LazyInit for RwLock {
+impl LazyInit for AllocatedRwLock {
     fn init() -> Box<Self> {
-        Box::new(Self::new())
+        Box::new(AllocatedRwLock {
+            inner: UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER),
+            write_locked: UnsafeCell::new(false),
+            num_readers: AtomicUsize::new(0),
+        })
     }
 
     fn destroy(mut rwlock: Box<Self>) {
@@ -35,17 +41,39 @@ fn cancel_init(_: Box<Self>) {
     }
 }
 
+impl AllocatedRwLock {
+    #[inline]
+    unsafe fn raw_unlock(&self) {
+        let r = libc::pthread_rwlock_unlock(self.inner.get());
+        debug_assert_eq!(r, 0);
+    }
+}
+
+impl Drop for AllocatedRwLock {
+    fn drop(&mut self) {
+        let r = unsafe { libc::pthread_rwlock_destroy(self.inner.get()) };
+        // On DragonFly pthread_rwlock_destroy() returns EINVAL if called on a
+        // rwlock that was just initialized with
+        // libc::PTHREAD_RWLOCK_INITIALIZER. Once it is used (locked/unlocked)
+        // or pthread_rwlock_init() is called, this behaviour no longer occurs.
+        if cfg!(target_os = "dragonfly") {
+            debug_assert!(r == 0 || r == libc::EINVAL);
+        } else {
+            debug_assert_eq!(r, 0);
+        }
+    }
+}
+
 impl RwLock {
+    #[inline]
     pub const fn new() -> RwLock {
-        RwLock {
-            inner: UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER),
-            write_locked: UnsafeCell::new(false),
-            num_readers: AtomicUsize::new(0),
-        }
+        RwLock { inner: LazyBox::new() }
     }
+
     #[inline]
-    pub unsafe fn read(&self) {
-        let r = libc::pthread_rwlock_rdlock(self.inner.get());
+    pub fn read(&self) {
+        let lock = &*self.inner;
+        let r = unsafe { libc::pthread_rwlock_rdlock(lock.inner.get()) };
 
         // According to POSIX, when a thread tries to acquire this read lock
         // while it already holds the write lock
@@ -62,51 +90,61 @@ pub unsafe fn read(&self) {
         // got the write lock more than once, or got a read and a write lock.
         if r == libc::EAGAIN {
             panic!("rwlock maximum reader count exceeded");
-        } else if r == libc::EDEADLK || (r == 0 && *self.write_locked.get()) {
+        } else if r == libc::EDEADLK || (r == 0 && unsafe { *lock.write_locked.get() }) {
             // Above, we make sure to only access `write_locked` when `r == 0` to avoid
             // data races.
             if r == 0 {
                 // `pthread_rwlock_rdlock` succeeded when it should not have.
-                self.raw_unlock();
+                unsafe {
+                    lock.raw_unlock();
+                }
             }
             panic!("rwlock read lock would result in deadlock");
         } else {
             // POSIX does not make guarantees about all the errors that may be returned.
             // See issue #94705 for more details.
             assert_eq!(r, 0, "unexpected error during rwlock read lock: {:?}", r);
-            self.num_readers.fetch_add(1, Ordering::Relaxed);
+            lock.num_readers.fetch_add(1, Ordering::Relaxed);
         }
     }
+
     #[inline]
-    pub unsafe fn try_read(&self) -> bool {
-        let r = libc::pthread_rwlock_tryrdlock(self.inner.get());
+    pub fn try_read(&self) -> bool {
+        let lock = &*self.inner;
+        let r = unsafe { libc::pthread_rwlock_tryrdlock(lock.inner.get()) };
         if r == 0 {
-            if *self.write_locked.get() {
+            if unsafe { *lock.write_locked.get() } {
                 // `pthread_rwlock_tryrdlock` succeeded when it should not have.
-                self.raw_unlock();
+                unsafe {
+                    lock.raw_unlock();
+                }
                 false
             } else {
-                self.num_readers.fetch_add(1, Ordering::Relaxed);
+                lock.num_readers.fetch_add(1, Ordering::Relaxed);
                 true
             }
         } else {
             false
         }
     }
+
     #[inline]
-    pub unsafe fn write(&self) {
-        let r = libc::pthread_rwlock_wrlock(self.inner.get());
+    pub fn write(&self) {
+        let lock = &*self.inner;
+        let r = unsafe { libc::pthread_rwlock_wrlock(lock.inner.get()) };
         // See comments above for why we check for EDEADLK and write_locked. For the same reason,
         // we also need to check that there are no readers (tracked in `num_readers`).
         if r == libc::EDEADLK
-            || (r == 0 && *self.write_locked.get())
-            || self.num_readers.load(Ordering::Relaxed) != 0
+            || (r == 0 && unsafe { *lock.write_locked.get() })
+            || lock.num_readers.load(Ordering::Relaxed) != 0
         {
             // Above, we make sure to only access `write_locked` when `r == 0` to avoid
             // data races.
             if r == 0 {
                 // `pthread_rwlock_wrlock` succeeded when it should not have.
-                self.raw_unlock();
+                unsafe {
+                    lock.raw_unlock();
+                }
             }
             panic!("rwlock write lock would result in deadlock");
         } else {
@@ -114,60 +152,44 @@ pub unsafe fn write(&self) {
             // return EDEADLK or 0. We rely on that.
             debug_assert_eq!(r, 0);
         }
-        *self.write_locked.get() = true;
+
+        unsafe {
+            *lock.write_locked.get() = true;
+        }
     }
+
     #[inline]
     pub unsafe fn try_write(&self) -> bool {
-        let r = libc::pthread_rwlock_trywrlock(self.inner.get());
+        let lock = &*self.inner;
+        let r = libc::pthread_rwlock_trywrlock(lock.inner.get());
         if r == 0 {
-            if *self.write_locked.get() || self.num_readers.load(Ordering::Relaxed) != 0 {
+            if *lock.write_locked.get() || lock.num_readers.load(Ordering::Relaxed) != 0 {
                 // `pthread_rwlock_trywrlock` succeeded when it should not have.
-                self.raw_unlock();
+                lock.raw_unlock();
                 false
             } else {
-                *self.write_locked.get() = true;
+                *lock.write_locked.get() = true;
                 true
             }
         } else {
             false
         }
     }
-    #[inline]
-    unsafe fn raw_unlock(&self) {
-        let r = libc::pthread_rwlock_unlock(self.inner.get());
-        debug_assert_eq!(r, 0);
-    }
+
     #[inline]
     pub unsafe fn read_unlock(&self) {
-        debug_assert!(!*self.write_locked.get());
-        self.num_readers.fetch_sub(1, Ordering::Relaxed);
-        self.raw_unlock();
-    }
-    #[inline]
-    pub unsafe fn write_unlock(&self) {
-        debug_assert_eq!(self.num_readers.load(Ordering::Relaxed), 0);
-        debug_assert!(*self.write_locked.get());
-        *self.write_locked.get() = false;
-        self.raw_unlock();
+        let lock = &*self.inner;
+        debug_assert!(!*lock.write_locked.get());
+        lock.num_readers.fetch_sub(1, Ordering::Relaxed);
+        lock.raw_unlock();
     }
-    #[inline]
-    unsafe fn destroy(&mut self) {
-        let r = libc::pthread_rwlock_destroy(self.inner.get());
-        // On DragonFly pthread_rwlock_destroy() returns EINVAL if called on a
-        // rwlock that was just initialized with
-        // libc::PTHREAD_RWLOCK_INITIALIZER. Once it is used (locked/unlocked)
-        // or pthread_rwlock_init() is called, this behaviour no longer occurs.
-        if cfg!(target_os = "dragonfly") {
-            debug_assert!(r == 0 || r == libc::EINVAL);
-        } else {
-            debug_assert_eq!(r, 0);
-        }
-    }
-}
 
-impl Drop for RwLock {
     #[inline]
-    fn drop(&mut self) {
-        unsafe { self.destroy() };
+    pub unsafe fn write_unlock(&self) {
+        let lock = &*self.inner;
+        debug_assert_eq!(lock.num_readers.load(Ordering::Relaxed), 0);
+        debug_assert!(*lock.write_locked.get());
+        *lock.write_locked.get() = false;
+        lock.raw_unlock();
     }
 }
index 527a26a12bcecb87bb087a5be20f2d8ccc74129f..3f0943b50ee4d98160947d7f85baa6f9a449c73f 100644 (file)
@@ -3,8 +3,6 @@
 
 pub struct Condvar {}
 
-pub type MovableCondvar = Condvar;
-
 impl Condvar {
     #[inline]
     #[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
@@ -13,10 +11,10 @@ pub const fn new() -> Condvar {
     }
 
     #[inline]
-    pub unsafe fn notify_one(&self) {}
+    pub fn notify_one(&self) {}
 
     #[inline]
-    pub unsafe fn notify_all(&self) {}
+    pub fn notify_all(&self) {}
 
     pub unsafe fn wait(&self, _mutex: &Mutex) {
         panic!("condvar wait not supported")
index 602a2d6231a292befbfe7559874ce3e07e4f28b7..0e0f9eccb213704b10f8766eaa434c1b82d49eb5 100644 (file)
@@ -1,6 +1,6 @@
 mod condvar;
 mod mutex;
 mod rwlock;
-pub use condvar::{Condvar, MovableCondvar};
-pub use mutex::{MovableMutex, Mutex};
-pub use rwlock::MovableRwLock;
+pub use condvar::Condvar;
+pub use mutex::Mutex;
+pub use rwlock::RwLock;
index 87ea475c6e3eb62f80b8f106a56d00335db53d61..4a13c55fb8bec01e47ec413bbc2f1f8af97ddbd9 100644 (file)
@@ -5,8 +5,6 @@ pub struct Mutex {
     locked: Cell<bool>,
 }
 
-pub type MovableMutex = Mutex;
-
 unsafe impl Send for Mutex {}
 unsafe impl Sync for Mutex {} // no threads on this platform
 
@@ -18,7 +16,7 @@ pub const fn new() -> Mutex {
     }
 
     #[inline]
-    pub unsafe fn lock(&self) {
+    pub fn lock(&self) {
         assert_eq!(self.locked.replace(true), false, "cannot recursively acquire mutex");
     }
 
@@ -28,7 +26,7 @@ pub unsafe fn unlock(&self) {
     }
 
     #[inline]
-    pub unsafe fn try_lock(&self) -> bool {
+    pub fn try_lock(&self) -> bool {
         self.locked.replace(true) == false
     }
 }
index 5292691b9555749b69712f580e9e08ea0b1251c5..789ef9b29e52a3dc55a9c809dfc294db78530c32 100644 (file)
@@ -5,8 +5,6 @@ pub struct RwLock {
     mode: Cell<isize>,
 }
 
-pub type MovableRwLock = RwLock;
-
 unsafe impl Send for RwLock {}
 unsafe impl Sync for RwLock {} // no threads on this platform
 
@@ -18,7 +16,7 @@ pub const fn new() -> RwLock {
     }
 
     #[inline]
-    pub unsafe fn read(&self) {
+    pub fn read(&self) {
         let m = self.mode.get();
         if m >= 0 {
             self.mode.set(m + 1);
@@ -28,7 +26,7 @@ pub unsafe fn read(&self) {
     }
 
     #[inline]
-    pub unsafe fn try_read(&self) -> bool {
+    pub fn try_read(&self) -> bool {
         let m = self.mode.get();
         if m >= 0 {
             self.mode.set(m + 1);
@@ -39,14 +37,14 @@ pub unsafe fn try_read(&self) -> bool {
     }
 
     #[inline]
-    pub unsafe fn write(&self) {
+    pub fn write(&self) {
         if self.mode.replace(-1) != 0 {
             rtabort!("rwlock locked for reading")
         }
     }
 
     #[inline]
-    pub unsafe fn try_write(&self) -> bool {
+    pub fn try_write(&self) -> bool {
         if self.mode.get() == 0 {
             self.mode.set(-1);
             true
index 93838390bee6e673411518befb232ed76138f103..d68c3e5f1dfbfaf281d0139c40bc2d337672b661 100644 (file)
@@ -55,9 +55,9 @@ pub mod locks {
             mod futex_condvar;
             mod futex_mutex;
             mod futex_rwlock;
-            pub(crate) use futex_condvar::{Condvar, MovableCondvar};
-            pub(crate) use futex_mutex::{Mutex, MovableMutex};
-            pub(crate) use futex_rwlock::MovableRwLock;
+            pub(crate) use futex_condvar::Condvar;
+            pub(crate) use futex_mutex::Mutex;
+            pub(crate) use futex_rwlock::RwLock;
         }
         #[path = "atomics/futex.rs"]
         pub mod futex;
index be9a2abbe35d9a525a598487cca17f788e2f9062..66fafa2c00b00fdc50ba41a7fe58d8465427c9bc 100644 (file)
@@ -8,8 +8,6 @@ pub struct Condvar {
     inner: UnsafeCell<c::CONDITION_VARIABLE>,
 }
 
-pub type MovableCondvar = Condvar;
-
 unsafe impl Send for Condvar {}
 unsafe impl Sync for Condvar {}
 
@@ -41,12 +39,12 @@ pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
     }
 
     #[inline]
-    pub unsafe fn notify_one(&self) {
-        c::WakeConditionVariable(self.inner.get())
+    pub fn notify_one(&self) {
+        unsafe { c::WakeConditionVariable(self.inner.get()) }
     }
 
     #[inline]
-    pub unsafe fn notify_all(&self) {
-        c::WakeAllConditionVariable(self.inner.get())
+    pub fn notify_all(&self) {
+        unsafe { c::WakeAllConditionVariable(self.inner.get()) }
     }
 }
index 602a2d6231a292befbfe7559874ce3e07e4f28b7..0e0f9eccb213704b10f8766eaa434c1b82d49eb5 100644 (file)
@@ -1,6 +1,6 @@
 mod condvar;
 mod mutex;
 mod rwlock;
-pub use condvar::{Condvar, MovableCondvar};
-pub use mutex::{MovableMutex, Mutex};
-pub use rwlock::MovableRwLock;
+pub use condvar::Condvar;
+pub use mutex::Mutex;
+pub use rwlock::RwLock;
index 91207f5f4665894349d4595a919e56ff8ee75cb8..ef2f84082cd5ce8da5d6d390947872c27b9a6dc9 100644 (file)
@@ -21,9 +21,6 @@ pub struct Mutex {
     srwlock: UnsafeCell<c::SRWLOCK>,
 }
 
-// Windows SRW Locks are movable (while not borrowed).
-pub type MovableMutex = Mutex;
-
 unsafe impl Send for Mutex {}
 unsafe impl Sync for Mutex {}
 
@@ -39,13 +36,15 @@ pub const fn new() -> Mutex {
     }
 
     #[inline]
-    pub unsafe fn lock(&self) {
-        c::AcquireSRWLockExclusive(raw(self));
+    pub fn lock(&self) {
+        unsafe {
+            c::AcquireSRWLockExclusive(raw(self));
+        }
     }
 
     #[inline]
-    pub unsafe fn try_lock(&self) -> bool {
-        c::TryAcquireSRWLockExclusive(raw(self)) != 0
+    pub fn try_lock(&self) -> bool {
+        unsafe { c::TryAcquireSRWLockExclusive(raw(self)) != 0 }
     }
 
     #[inline]
index fa5ffe5749f259e9e6441c1926e53e888c2fbde9..e69415baac42be22578975b723854757fd173e29 100644 (file)
@@ -5,8 +5,6 @@ pub struct RwLock {
     inner: UnsafeCell<c::SRWLOCK>,
 }
 
-pub type MovableRwLock = RwLock;
-
 unsafe impl Send for RwLock {}
 unsafe impl Sync for RwLock {}
 
@@ -16,20 +14,20 @@ pub const fn new() -> RwLock {
         RwLock { inner: UnsafeCell::new(c::SRWLOCK_INIT) }
     }
     #[inline]
-    pub unsafe fn read(&self) {
-        c::AcquireSRWLockShared(self.inner.get())
+    pub fn read(&self) {
+        unsafe { c::AcquireSRWLockShared(self.inner.get()) }
     }
     #[inline]
-    pub unsafe fn try_read(&self) -> bool {
-        c::TryAcquireSRWLockShared(self.inner.get()) != 0
+    pub fn try_read(&self) -> bool {
+        unsafe { c::TryAcquireSRWLockShared(self.inner.get()) != 0 }
     }
     #[inline]
-    pub unsafe fn write(&self) {
-        c::AcquireSRWLockExclusive(self.inner.get())
+    pub fn write(&self) {
+        unsafe { c::AcquireSRWLockExclusive(self.inner.get()) }
     }
     #[inline]
-    pub unsafe fn try_write(&self) -> bool {
-        c::TryAcquireSRWLockExclusive(self.inner.get()) != 0
+    pub fn try_write(&self) -> bool {
+        unsafe { c::TryAcquireSRWLockExclusive(self.inner.get()) != 0 }
     }
     #[inline]
     pub unsafe fn read_unlock(&self) {
diff --git a/library/std/src/sys_common/condvar.rs b/library/std/src/sys_common/condvar.rs
deleted file mode 100644 (file)
index 8bc5b24..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-use crate::sys::locks as imp;
-use crate::sys_common::mutex::MovableMutex;
-use crate::time::Duration;
-
-mod check;
-
-type CondvarCheck = <imp::MovableMutex as check::CondvarCheck>::Check;
-
-/// An OS-based condition variable.
-pub struct Condvar {
-    inner: imp::MovableCondvar,
-    check: CondvarCheck,
-}
-
-impl Condvar {
-    /// Creates a new condition variable for use.
-    #[inline]
-    #[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
-    pub const fn new() -> Self {
-        Self { inner: imp::MovableCondvar::new(), check: CondvarCheck::new() }
-    }
-
-    /// Signals one waiter on this condition variable to wake up.
-    #[inline]
-    pub fn notify_one(&self) {
-        unsafe { self.inner.notify_one() };
-    }
-
-    /// Awakens all current waiters on this condition variable.
-    #[inline]
-    pub fn notify_all(&self) {
-        unsafe { self.inner.notify_all() };
-    }
-
-    /// Waits for a signal on the specified mutex.
-    ///
-    /// Behavior is undefined if the mutex is not locked by the current thread.
-    ///
-    /// May panic if used with more than one mutex.
-    #[inline]
-    pub unsafe fn wait(&self, mutex: &MovableMutex) {
-        self.check.verify(mutex);
-        self.inner.wait(mutex.raw())
-    }
-
-    /// Waits for a signal on the specified mutex with a timeout duration
-    /// specified by `dur` (a relative time into the future).
-    ///
-    /// Behavior is undefined if the mutex is not locked by the current thread.
-    ///
-    /// May panic if used with more than one mutex.
-    #[inline]
-    pub unsafe fn wait_timeout(&self, mutex: &MovableMutex, dur: Duration) -> bool {
-        self.check.verify(mutex);
-        self.inner.wait_timeout(mutex.raw(), dur)
-    }
-}
diff --git a/library/std/src/sys_common/condvar/check.rs b/library/std/src/sys_common/condvar/check.rs
deleted file mode 100644 (file)
index 4ac9e62..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-use crate::ptr;
-use crate::sync::atomic::{AtomicPtr, Ordering};
-use crate::sys::locks as imp;
-use crate::sys_common::lazy_box::{LazyBox, LazyInit};
-use crate::sys_common::mutex::MovableMutex;
-
-pub trait CondvarCheck {
-    type Check;
-}
-
-/// For boxed mutexes, a `Condvar` will check it's only ever used with the same
-/// mutex, based on its (stable) address.
-impl<T: LazyInit> CondvarCheck for LazyBox<T> {
-    type Check = SameMutexCheck;
-}
-
-pub struct SameMutexCheck {
-    addr: AtomicPtr<()>,
-}
-
-#[allow(dead_code)]
-impl SameMutexCheck {
-    pub const fn new() -> Self {
-        Self { addr: AtomicPtr::new(ptr::null_mut()) }
-    }
-    pub fn verify(&self, mutex: &MovableMutex) {
-        let addr = mutex.raw() as *const imp::Mutex as *const () as *mut _;
-        // Relaxed is okay here because we never read through `self.addr`, and only use it to
-        // compare addresses.
-        match self.addr.compare_exchange(
-            ptr::null_mut(),
-            addr,
-            Ordering::Relaxed,
-            Ordering::Relaxed,
-        ) {
-            Ok(_) => {}               // Stored the address
-            Err(n) if n == addr => {} // Lost a race to store the same address
-            _ => panic!("attempted to use a condition variable with two mutexes"),
-        }
-    }
-}
-
-/// Unboxed mutexes may move, so `Condvar` can not require its address to stay
-/// constant.
-impl CondvarCheck for imp::Mutex {
-    type Check = NoCheck;
-}
-
-pub struct NoCheck;
-
-#[allow(dead_code)]
-impl NoCheck {
-    #[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
-    pub const fn new() -> Self {
-        Self
-    }
-    pub fn verify(&self, _: &MovableMutex) {}
-}
index 8c19f9332dc563c4e59535d0788326a243b3e48a..069b13e9d85ea4b6fd5b6bdc7631d608e7f46f0f 100644 (file)
 mod tests;
 
 pub mod backtrace;
-pub mod condvar;
 pub mod fs;
 pub mod io;
 pub mod lazy_box;
 pub mod memchr;
-pub mod mutex;
 pub mod once;
 pub mod process;
 pub mod remutex;
-pub mod rwlock;
 pub mod thread;
 pub mod thread_info;
 pub mod thread_local_dtor;
diff --git a/library/std/src/sys_common/mutex.rs b/library/std/src/sys_common/mutex.rs
deleted file mode 100644 (file)
index 98046f2..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-use crate::sys::locks as imp;
-
-/// An OS-based mutual exclusion lock.
-///
-/// This mutex cleans up its resources in its `Drop` implementation, may safely
-/// be moved (when not borrowed), and does not cause UB when used reentrantly.
-///
-/// This mutex does not implement poisoning.
-///
-/// This is either a wrapper around `LazyBox<imp::Mutex>` or `imp::Mutex`,
-/// depending on the platform. It is boxed on platforms where `imp::Mutex` may
-/// not be moved.
-pub struct MovableMutex(imp::MovableMutex);
-
-unsafe impl Sync for MovableMutex {}
-
-impl MovableMutex {
-    /// Creates a new mutex.
-    #[inline]
-    #[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
-    pub const fn new() -> Self {
-        Self(imp::MovableMutex::new())
-    }
-
-    pub(super) fn raw(&self) -> &imp::Mutex {
-        &self.0
-    }
-
-    /// Locks the mutex blocking the current thread until it is available.
-    #[inline]
-    pub fn raw_lock(&self) {
-        unsafe { self.0.lock() }
-    }
-
-    /// Attempts to lock the mutex without blocking, returning whether it was
-    /// successfully acquired or not.
-    #[inline]
-    pub fn try_lock(&self) -> bool {
-        unsafe { self.0.try_lock() }
-    }
-
-    /// Unlocks the mutex.
-    ///
-    /// Behavior is undefined if the current thread does not actually hold the
-    /// mutex.
-    #[inline]
-    pub unsafe fn raw_unlock(&self) {
-        self.0.unlock()
-    }
-}
index b448ae3a99777162c35f930b64833baf34733427..4c054da64714cf1ecd1fe9e136854dde7eb08c0d 100644 (file)
@@ -1,11 +1,11 @@
 #[cfg(all(test, not(target_os = "emscripten")))]
 mod tests;
 
-use super::mutex as sys;
 use crate::cell::UnsafeCell;
 use crate::ops::Deref;
 use crate::panic::{RefUnwindSafe, UnwindSafe};
 use crate::sync::atomic::{AtomicUsize, Ordering::Relaxed};
+use crate::sys::locks as sys;
 
 /// A re-entrant mutual exclusion
 ///
@@ -39,7 +39,7 @@
 /// synchronization is left to the mutex, making relaxed memory ordering for
 /// the `owner` field fine in all cases.
 pub struct ReentrantMutex<T> {
-    mutex: sys::MovableMutex,
+    mutex: sys::Mutex,
     owner: AtomicUsize,
     lock_count: UnsafeCell<u32>,
     data: T,
@@ -74,7 +74,7 @@ impl<T> ReentrantMutex<T> {
     /// Creates a new reentrant mutex in an unlocked state.
     pub const fn new(t: T) -> ReentrantMutex<T> {
         ReentrantMutex {
-            mutex: sys::MovableMutex::new(),
+            mutex: sys::Mutex::new(),
             owner: AtomicUsize::new(0),
             lock_count: UnsafeCell::new(0),
             data: t,
@@ -100,7 +100,7 @@ pub fn lock(&self) -> ReentrantMutexGuard<'_, T> {
             if self.owner.load(Relaxed) == this_thread {
                 self.increment_lock_count();
             } else {
-                self.mutex.raw_lock();
+                self.mutex.lock();
                 self.owner.store(this_thread, Relaxed);
                 debug_assert_eq!(*self.lock_count.get(), 0);
                 *self.lock_count.get() = 1;
@@ -162,7 +162,7 @@ fn drop(&mut self) {
             *self.lock.lock_count.get() -= 1;
             if *self.lock.lock_count.get() == 0 {
                 self.lock.owner.store(0, Relaxed);
-                self.lock.mutex.raw_unlock();
+                self.lock.mutex.unlock();
             }
         }
     }
diff --git a/library/std/src/sys_common/rwlock.rs b/library/std/src/sys_common/rwlock.rs
deleted file mode 100644 (file)
index 042981d..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-use crate::sys::locks as imp;
-
-/// An OS-based reader-writer lock.
-///
-/// This rwlock cleans up its resources in its `Drop` implementation and may
-/// safely be moved (when not borrowed).
-///
-/// This rwlock does not implement poisoning.
-///
-/// This is either a wrapper around `LazyBox<imp::RwLock>` or `imp::RwLock`,
-/// depending on the platform. It is boxed on platforms where `imp::RwLock` may
-/// not be moved.
-pub struct MovableRwLock(imp::MovableRwLock);
-
-impl MovableRwLock {
-    /// Creates a new reader-writer lock for use.
-    #[inline]
-    #[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
-    pub const fn new() -> Self {
-        Self(imp::MovableRwLock::new())
-    }
-
-    /// Acquires shared access to the underlying lock, blocking the current
-    /// thread to do so.
-    #[inline]
-    pub fn read(&self) {
-        unsafe { self.0.read() }
-    }
-
-    /// Attempts to acquire shared access to this lock, returning whether it
-    /// succeeded or not.
-    ///
-    /// This function does not block the current thread.
-    #[inline]
-    pub fn try_read(&self) -> bool {
-        unsafe { self.0.try_read() }
-    }
-
-    /// Acquires write access to the underlying lock, blocking the current thread
-    /// to do so.
-    #[inline]
-    pub fn write(&self) {
-        unsafe { self.0.write() }
-    }
-
-    /// Attempts to acquire exclusive access to this lock, returning whether it
-    /// succeeded or not.
-    ///
-    /// This function does not block the current thread.
-    #[inline]
-    pub fn try_write(&self) -> bool {
-        unsafe { self.0.try_write() }
-    }
-
-    /// Unlocks previously acquired shared access to this lock.
-    ///
-    /// Behavior is undefined if the current thread does not have shared access.
-    #[inline]
-    pub unsafe fn read_unlock(&self) {
-        self.0.read_unlock()
-    }
-
-    /// Unlocks previously acquired exclusive access to this lock.
-    ///
-    /// Behavior is undefined if the current thread does not currently have
-    /// exclusive access.
-    #[inline]
-    pub unsafe fn write_unlock(&self) {
-        self.0.write_unlock()
-    }
-}
index 1df1ca758c054d10516cce9c215dd08977036be3..80dc4c038d615388bab3e00b9217af129ca58c5b 100644 (file)
@@ -1,15 +1,34 @@
 use crate::cell::{Cell, UnsafeCell};
 use crate::sync::atomic::{AtomicU8, Ordering};
-use crate::sync::mpsc::{channel, Sender};
+use crate::sync::{Arc, Condvar, Mutex};
 use crate::thread::{self, LocalKey};
 use crate::thread_local;
 
-struct Foo(Sender<()>);
+#[derive(Clone, Default)]
+struct Signal(Arc<(Mutex<bool>, Condvar)>);
+
+impl Signal {
+    fn notify(&self) {
+        let (set, cvar) = &*self.0;
+        *set.lock().unwrap() = true;
+        cvar.notify_one();
+    }
+
+    fn wait(&self) {
+        let (set, cvar) = &*self.0;
+        let mut set = set.lock().unwrap();
+        while !*set {
+            set = cvar.wait(set).unwrap();
+        }
+    }
+}
+
+struct Foo(Signal);
 
 impl Drop for Foo {
     fn drop(&mut self) {
-        let Foo(ref s) = *self;
-        s.send(()).unwrap();
+        let Foo(ref f) = *self;
+        f.notify();
     }
 }
 
@@ -69,14 +88,15 @@ fn smoke_dtor() {
     run(&FOO2);
 
     fn run(key: &'static LocalKey<UnsafeCell<Option<Foo>>>) {
-        let (tx, rx) = channel();
+        let signal = Signal::default();
+        let signal2 = signal.clone();
         let t = thread::spawn(move || unsafe {
-            let mut tx = Some(tx);
+            let mut signal = Some(signal2);
             key.with(|f| {
-                *f.get() = Some(Foo(tx.take().unwrap()));
+                *f.get() = Some(Foo(signal.take().unwrap()));
             });
         });
-        rx.recv().unwrap();
+        signal.wait();
         t.join().unwrap();
     }
 }
@@ -165,48 +185,50 @@ fn drop(&mut self) {
 // requires the destructor to be run to pass the test).
 #[test]
 fn dtors_in_dtors_in_dtors() {
-    struct S1(Sender<()>);
+    struct S1(Signal);
     thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell::new(None));
     thread_local!(static K2: UnsafeCell<Option<Foo>> = UnsafeCell::new(None));
 
     impl Drop for S1 {
         fn drop(&mut self) {
-            let S1(ref tx) = *self;
+            let S1(ref signal) = *self;
             unsafe {
-                let _ = K2.try_with(|s| *s.get() = Some(Foo(tx.clone())));
+                let _ = K2.try_with(|s| *s.get() = Some(Foo(signal.clone())));
             }
         }
     }
 
-    let (tx, rx) = channel();
+    let signal = Signal::default();
+    let signal2 = signal.clone();
     let _t = thread::spawn(move || unsafe {
-        let mut tx = Some(tx);
-        K1.with(|s| *s.get() = Some(S1(tx.take().unwrap())));
+        let mut signal = Some(signal2);
+        K1.with(|s| *s.get() = Some(S1(signal.take().unwrap())));
     });
-    rx.recv().unwrap();
+    signal.wait();
 }
 
 #[test]
 fn dtors_in_dtors_in_dtors_const_init() {
-    struct S1(Sender<()>);
+    struct S1(Signal);
     thread_local!(static K1: UnsafeCell<Option<S1>> = const { UnsafeCell::new(None) });
     thread_local!(static K2: UnsafeCell<Option<Foo>> = const { UnsafeCell::new(None) });
 
     impl Drop for S1 {
         fn drop(&mut self) {
-            let S1(ref tx) = *self;
+            let S1(ref signal) = *self;
             unsafe {
-                let _ = K2.try_with(|s| *s.get() = Some(Foo(tx.clone())));
+                let _ = K2.try_with(|s| *s.get() = Some(Foo(signal.clone())));
             }
         }
     }
 
-    let (tx, rx) = channel();
+    let signal = Signal::default();
+    let signal2 = signal.clone();
     let _t = thread::spawn(move || unsafe {
-        let mut tx = Some(tx);
-        K1.with(|s| *s.get() = Some(S1(tx.take().unwrap())));
+        let mut signal = Some(signal2);
+        K1.with(|s| *s.get() = Some(S1(signal.take().unwrap())));
     });
-    rx.recv().unwrap();
+    signal.wait();
 }
 
 // This test tests that TLS destructors have run before the thread joins. The
index 34e18b5fa8778ebb4750284d661f0ca226a40622..ecd06ebf743ab49969617210f0b326e6b45aaf5a 100644 (file)
@@ -43,7 +43,7 @@
 #[stable(feature = "time", since = "1.3.0")]
 pub use core::time::Duration;
 
-#[stable(feature = "duration_checked_float", since = "CURRENT_RUSTC_VERSION")]
+#[stable(feature = "duration_checked_float", since = "1.66.0")]
 pub use core::time::TryFromFloatSecsError;
 
 /// A measurement of a monotonically nondecreasing clock.
index 32c4a7eb5c18cb0f0b2ff1c8debee4a2690265f8..eab2717c45233e2754c6a2254d588750935f6221 100644 (file)
@@ -20,7 +20,7 @@ compiler_builtins = "0.1.0"
 cfg-if = "1.0"
 
 [build-dependencies]
-cc = "1.0.69"
+cc = "1.0.76"
 
 [features]
 
index 46fe50cb9453d9b045d95688e178146ff7b608ed..2efd2d5dd4aa47189b5908f2ecbb5b08f116395a 100644 (file)
@@ -15,7 +15,6 @@
         target_os = "espidf",
     ))] {
         // These "unix" family members do not have unwinder.
-        // Note this also matches x86_64-unknown-none-linuxkernel.
     } else if #[cfg(any(
         unix,
         windows,
 #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))]
 #[link(name = "unwind", kind = "static", modifiers = "-bundle")]
 extern "C" {}
-
-#[cfg(all(target_os = "windows", target_env = "gnu", target_abi = "llvm"))]
-#[link(name = "unwind", kind = "static", modifiers = "-bundle")]
-extern "C" {}
index a5b6193b086fbf44aef522205179d07a7abefdcc..15500f7fd3543e099338831d43a260af1cdd5e11 100644 (file)
@@ -36,9 +36,12 @@ pub enum _Unwind_Reason_Code {
 #[cfg(all(target_arch = "arm", any(target_os = "ios", target_os = "watchos")))]
 pub const unwinder_private_data_size: usize = 5;
 
-#[cfg(all(target_arch = "aarch64", target_pointer_width = "64"))]
+#[cfg(all(target_arch = "aarch64", target_pointer_width = "64", not(target_os = "windows")))]
 pub const unwinder_private_data_size: usize = 2;
 
+#[cfg(all(target_arch = "aarch64", target_pointer_width = "64", target_os = "windows"))]
+pub const unwinder_private_data_size: usize = 6;
+
 #[cfg(all(target_arch = "aarch64", target_pointer_width = "32"))]
 pub const unwinder_private_data_size: usize = 5;
 
@@ -90,7 +93,10 @@ pub enum _Unwind_Context {}
 // rustc_codegen_ssa::src::back::symbol_export, rustc_middle::middle::exported_symbols
 // and RFC 2841
 #[cfg_attr(
-    all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")),
+    any(
+        all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")),
+        all(target_os = "windows", target_env = "gnu", target_abi = "llvm")
+    ),
     link(name = "unwind", kind = "static", modifiers = "-bundle")
 )]
 extern "C-unwind" {
index baecca44cd987adda8d1b3bf2ba2c4a068bbd0a9..e1a108cea9574a6a772ce946215cef328a8facf1 100644 (file)
@@ -224,13 +224,13 @@ dependencies = [
 
 [[package]]
 name = "fd-lock"
-version = "3.0.6"
+version = "3.0.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e11dcc7e4d79a8c89b9ab4c6f5c30b1fc4a83c420792da3542fd31179ed5f517"
+checksum = "0c93a581058d957dc4176875aad04f82f81613e6611d64aa1a9c755bdfb16711"
 dependencies = [
  "cfg-if",
  "rustix",
- "windows-sys",
+ "windows-sys 0.42.0",
 ]
 
 [[package]]
@@ -528,7 +528,7 @@ dependencies = [
  "io-lifetimes",
  "libc",
  "linux-raw-sys",
- "windows-sys",
+ "windows-sys 0.36.1",
 ]
 
 [[package]]
@@ -721,43 +721,100 @@ version = "0.36.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
 dependencies = [
- "windows_aarch64_msvc",
- "windows_i686_gnu",
- "windows_i686_msvc",
- "windows_x86_64_gnu",
- "windows_x86_64_msvc",
+ "windows_aarch64_msvc 0.36.1",
+ "windows_i686_gnu 0.36.1",
+ "windows_i686_msvc 0.36.1",
+ "windows_x86_64_gnu 0.36.1",
+ "windows_x86_64_msvc 0.36.1",
 ]
 
+[[package]]
+name = "windows-sys"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc 0.42.0",
+ "windows_i686_gnu 0.42.0",
+ "windows_i686_msvc 0.42.0",
+ "windows_x86_64_gnu 0.42.0",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc 0.42.0",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
+
 [[package]]
 name = "windows_aarch64_msvc"
 version = "0.36.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
 
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
+
 [[package]]
 name = "windows_i686_gnu"
 version = "0.36.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
 
+[[package]]
+name = "windows_i686_gnu"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
+
 [[package]]
 name = "windows_i686_msvc"
 version = "0.36.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
 
+[[package]]
+name = "windows_i686_msvc"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
+
 [[package]]
 name = "windows_x86_64_gnu"
 version = "0.36.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
 
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
+
 [[package]]
 name = "windows_x86_64_msvc"
 version = "0.36.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
 
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
+
 [[package]]
 name = "xattr"
 version = "0.2.3"
index 95e711737738a4e661fe1f86c0b7edfb09e3241c..f74738437ea3a2e7ac0bd91b536b9ed8236e6c42 100644 (file)
@@ -36,7 +36,7 @@ test = false
 
 [dependencies]
 cmake = "0.1.38"
-fd-lock = "3.0.6"
+fd-lock = "3.0.7"
 filetime = "0.2"
 getopts = "0.2.19"
 cc = "1.0.69"
index 9b4861ccd95f4965525ac5192d04acc5065927df..be69f819c6428f8e88332ab7889656ec7482a88a 100644 (file)
@@ -35,7 +35,7 @@ fn main() {
 
     // NOTE: Since `./configure` generates a `config.toml`, distro maintainers will see the
     // changelog warning, not the `x.py setup` message.
-    let suggest_setup = !config.config.exists() && !matches!(config.cmd, Subcommand::Setup { .. });
+    let suggest_setup = config.config.is_none() && !matches!(config.cmd, Subcommand::Setup { .. });
     if suggest_setup {
         println!("warning: you have not made a `config.toml`");
         println!(
index 406bae02d84da581c9b3c37c9d8f7693c22d7a59..8d999302a6d7b2240a8ef56eb10c52fc7714b67c 100644 (file)
@@ -2,14 +2,13 @@
 use std::cell::{Cell, RefCell};
 use std::collections::BTreeSet;
 use std::env;
-use std::ffi::{OsStr, OsString};
+use std::ffi::OsStr;
 use std::fmt::{Debug, Write};
-use std::fs::{self, File};
+use std::fs::{self};
 use std::hash::Hash;
-use std::io::{BufRead, BufReader, ErrorKind};
 use std::ops::Deref;
 use std::path::{Component, Path, PathBuf};
-use std::process::{Command, Stdio};
+use std::process::Command;
 use std::time::{Duration, Instant};
 
 use crate::cache::{Cache, Interned, INTERNER};
 use crate::tool::{self, SourceType};
 use crate::util::{self, add_dylib_path, add_link_lib_path, exe, libdir, output, t};
 use crate::EXTRA_CHECK_CFGS;
-use crate::{check, Config};
-use crate::{compile, Crate};
+use crate::{check, compile, Crate};
 use crate::{Build, CLang, DocTests, GitRepo, Mode};
 
 pub use crate::Compiler;
 // FIXME: replace with std::lazy after it gets stabilized and reaches beta
-use once_cell::sync::{Lazy, OnceCell};
-use xz2::bufread::XzDecoder;
+use once_cell::sync::Lazy;
 
 pub struct Builder<'a> {
     pub build: &'a Build,
@@ -755,6 +752,7 @@ macro_rules! describe {
                 run::BuildManifest,
                 run::BumpStage0,
                 run::ReplaceVersionPlaceholder,
+                run::Miri,
             ),
             // These commands either don't use paths, or they're special-cased in Build::build()
             Kind::Clean | Kind::Format | Kind::Setup => vec![],
@@ -818,7 +816,7 @@ pub fn new(build: &Build) -> Builder<'_> {
             Subcommand::Bench { ref paths, .. } => (Kind::Bench, &paths[..]),
             Subcommand::Dist { ref paths } => (Kind::Dist, &paths[..]),
             Subcommand::Install { ref paths } => (Kind::Install, &paths[..]),
-            Subcommand::Run { ref paths } => (Kind::Run, &paths[..]),
+            Subcommand::Run { ref paths, .. } => (Kind::Run, &paths[..]),
             Subcommand::Format { .. } => (Kind::Format, &[][..]),
             Subcommand::Clean { .. } | Subcommand::Setup { .. } => {
                 panic!()
@@ -852,241 +850,6 @@ fn run_step_descriptions(&self, v: &[StepDescription], paths: &[PathBuf]) {
         StepDescription::run(v, self, paths);
     }
 
-    /// Modifies the interpreter section of 'fname' to fix the dynamic linker,
-    /// or the RPATH section, to fix the dynamic library search path
-    ///
-    /// This is only required on NixOS and uses the PatchELF utility to
-    /// change the interpreter/RPATH of ELF executables.
-    ///
-    /// Please see https://nixos.org/patchelf.html for more information
-    pub(crate) fn fix_bin_or_dylib(&self, fname: &Path) {
-        // FIXME: cache NixOS detection?
-        match Command::new("uname").arg("-s").stderr(Stdio::inherit()).output() {
-            Err(_) => return,
-            Ok(output) if !output.status.success() => return,
-            Ok(output) => {
-                let mut s = output.stdout;
-                if s.last() == Some(&b'\n') {
-                    s.pop();
-                }
-                if s != b"Linux" {
-                    return;
-                }
-            }
-        }
-
-        // If the user has asked binaries to be patched for Nix, then
-        // don't check for NixOS or `/lib`, just continue to the patching.
-        // NOTE: this intentionally comes after the Linux check:
-        // - patchelf only works with ELF files, so no need to run it on Mac or Windows
-        // - On other Unix systems, there is no stable syscall interface, so Nix doesn't manage the global libc.
-        if !self.config.patch_binaries_for_nix {
-            // Use `/etc/os-release` instead of `/etc/NIXOS`.
-            // The latter one does not exist on NixOS when using tmpfs as root.
-            const NIX_IDS: &[&str] = &["ID=nixos", "ID='nixos'", "ID=\"nixos\""];
-            let os_release = match File::open("/etc/os-release") {
-                Err(e) if e.kind() == ErrorKind::NotFound => return,
-                Err(e) => panic!("failed to access /etc/os-release: {}", e),
-                Ok(f) => f,
-            };
-            if !BufReader::new(os_release).lines().any(|l| NIX_IDS.contains(&t!(l).trim())) {
-                return;
-            }
-            if Path::new("/lib").exists() {
-                return;
-            }
-        }
-
-        // At this point we're pretty sure the user is running NixOS or using Nix
-        println!("info: you seem to be using Nix. Attempting to patch {}", fname.display());
-
-        // Only build `.nix-deps` once.
-        static NIX_DEPS_DIR: OnceCell<PathBuf> = OnceCell::new();
-        let mut nix_build_succeeded = true;
-        let nix_deps_dir = NIX_DEPS_DIR.get_or_init(|| {
-            // Run `nix-build` to "build" each dependency (which will likely reuse
-            // the existing `/nix/store` copy, or at most download a pre-built copy).
-            //
-            // Importantly, we create a gc-root called `.nix-deps` in the `build/`
-            // directory, but still reference the actual `/nix/store` path in the rpath
-            // as it makes it significantly more robust against changes to the location of
-            // the `.nix-deps` location.
-            //
-            // bintools: Needed for the path of `ld-linux.so` (via `nix-support/dynamic-linker`).
-            // zlib: Needed as a system dependency of `libLLVM-*.so`.
-            // patchelf: Needed for patching ELF binaries (see doc comment above).
-            let nix_deps_dir = self.out.join(".nix-deps");
-            const NIX_EXPR: &str = "
-            with (import <nixpkgs> {});
-            symlinkJoin {
-                name = \"rust-stage0-dependencies\";
-                paths = [
-                    zlib
-                    patchelf
-                    stdenv.cc.bintools
-                ];
-            }
-            ";
-            nix_build_succeeded = self.try_run(Command::new("nix-build").args(&[
-                Path::new("-E"),
-                Path::new(NIX_EXPR),
-                Path::new("-o"),
-                &nix_deps_dir,
-            ]));
-            nix_deps_dir
-        });
-        if !nix_build_succeeded {
-            return;
-        }
-
-        let mut patchelf = Command::new(nix_deps_dir.join("bin/patchelf"));
-        let rpath_entries = {
-            // ORIGIN is a relative default, all binary and dynamic libraries we ship
-            // appear to have this (even when `../lib` is redundant).
-            // NOTE: there are only two paths here, delimited by a `:`
-            let mut entries = OsString::from("$ORIGIN/../lib:");
-            entries.push(t!(fs::canonicalize(nix_deps_dir)));
-            entries.push("/lib");
-            entries
-        };
-        patchelf.args(&[OsString::from("--set-rpath"), rpath_entries]);
-        if !fname.extension().map_or(false, |ext| ext == "so") {
-            // Finally, set the correct .interp for binaries
-            let dynamic_linker_path = nix_deps_dir.join("nix-support/dynamic-linker");
-            // FIXME: can we support utf8 here? `args` doesn't accept Vec<u8>, only OsString ...
-            let dynamic_linker = t!(String::from_utf8(t!(fs::read(dynamic_linker_path))));
-            patchelf.args(&["--set-interpreter", dynamic_linker.trim_end()]);
-        }
-
-        self.try_run(patchelf.arg(fname));
-    }
-
-    pub(crate) fn download_component(&self, url: &str, dest_path: &Path, help_on_error: &str) {
-        self.verbose(&format!("download {url}"));
-        // Use a temporary file in case we crash while downloading, to avoid a corrupt download in cache/.
-        let tempfile = self.tempdir().join(dest_path.file_name().unwrap());
-        // While bootstrap itself only supports http and https downloads, downstream forks might
-        // need to download components from other protocols. The match allows them adding more
-        // protocols without worrying about merge conflicts if we change the HTTP implementation.
-        match url.split_once("://").map(|(proto, _)| proto) {
-            Some("http") | Some("https") => {
-                self.download_http_with_retries(&tempfile, url, help_on_error)
-            }
-            Some(other) => panic!("unsupported protocol {other} in {url}"),
-            None => panic!("no protocol in {url}"),
-        }
-        t!(std::fs::rename(&tempfile, dest_path));
-    }
-
-    fn download_http_with_retries(&self, tempfile: &Path, url: &str, help_on_error: &str) {
-        println!("downloading {}", url);
-        // Try curl. If that fails and we are on windows, fallback to PowerShell.
-        let mut curl = Command::new("curl");
-        curl.args(&[
-            "-#",
-            "-y",
-            "30",
-            "-Y",
-            "10", // timeout if speed is < 10 bytes/sec for > 30 seconds
-            "--connect-timeout",
-            "30", // timeout if cannot connect within 30 seconds
-            "--retry",
-            "3",
-            "-Sf",
-            "-o",
-        ]);
-        curl.arg(tempfile);
-        curl.arg(url);
-        if !self.check_run(&mut curl) {
-            if self.build.build.contains("windows-msvc") {
-                println!("Fallback to PowerShell");
-                for _ in 0..3 {
-                    if self.try_run(Command::new("PowerShell.exe").args(&[
-                        "/nologo",
-                        "-Command",
-                        "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;",
-                        &format!(
-                            "(New-Object System.Net.WebClient).DownloadFile('{}', '{}')",
-                            url, tempfile.to_str().expect("invalid UTF-8 not supported with powershell downloads"),
-                        ),
-                    ])) {
-                        return;
-                    }
-                    println!("\nspurious failure, trying again");
-                }
-            }
-            if !help_on_error.is_empty() {
-                eprintln!("{}", help_on_error);
-            }
-            crate::detail_exit(1);
-        }
-    }
-
-    pub(crate) fn unpack(&self, tarball: &Path, dst: &Path, pattern: &str) {
-        println!("extracting {} to {}", tarball.display(), dst.display());
-        if !dst.exists() {
-            t!(fs::create_dir_all(dst));
-        }
-
-        // `tarball` ends with `.tar.xz`; strip that suffix
-        // example: `rust-dev-nightly-x86_64-unknown-linux-gnu`
-        let uncompressed_filename =
-            Path::new(tarball.file_name().expect("missing tarball filename")).file_stem().unwrap();
-        let directory_prefix = Path::new(Path::new(uncompressed_filename).file_stem().unwrap());
-
-        // decompress the file
-        let data = t!(File::open(tarball));
-        let decompressor = XzDecoder::new(BufReader::new(data));
-
-        let mut tar = tar::Archive::new(decompressor);
-        for member in t!(tar.entries()) {
-            let mut member = t!(member);
-            let original_path = t!(member.path()).into_owned();
-            // skip the top-level directory
-            if original_path == directory_prefix {
-                continue;
-            }
-            let mut short_path = t!(original_path.strip_prefix(directory_prefix));
-            if !short_path.starts_with(pattern) {
-                continue;
-            }
-            short_path = t!(short_path.strip_prefix(pattern));
-            let dst_path = dst.join(short_path);
-            self.verbose(&format!("extracting {} to {}", original_path.display(), dst.display()));
-            if !t!(member.unpack_in(dst)) {
-                panic!("path traversal attack ??");
-            }
-            let src_path = dst.join(original_path);
-            if src_path.is_dir() && dst_path.exists() {
-                continue;
-            }
-            t!(fs::rename(src_path, dst_path));
-        }
-        t!(fs::remove_dir_all(dst.join(directory_prefix)));
-    }
-
-    /// Returns whether the SHA256 checksum of `path` matches `expected`.
-    pub(crate) fn verify(&self, path: &Path, expected: &str) -> bool {
-        use sha2::Digest;
-
-        self.verbose(&format!("verifying {}", path.display()));
-        let mut hasher = sha2::Sha256::new();
-        // FIXME: this is ok for rustfmt (4.1 MB large at time of writing), but it seems memory-intensive for rustc and larger components.
-        // Consider using streaming IO instead?
-        let contents = if self.config.dry_run { vec![] } else { t!(fs::read(path)) };
-        hasher.update(&contents);
-        let found = hex::encode(hasher.finalize().as_slice());
-        let verified = found == expected;
-        if !verified && !self.config.dry_run {
-            println!(
-                "invalid checksum: \n\
-                found:    {found}\n\
-                expected: {expected}",
-            );
-        }
-        return verified;
-    }
-
     /// Obtain a compiler at a given stage and for a given host. Explicitly does
     /// not take `Compiler` since all `Compiler` instances are meant to be
     /// obtained through this function, since it ensures that they are valid
@@ -1291,7 +1054,7 @@ pub fn rustdoc_cmd(&self, compiler: Compiler) -> Command {
     /// Note that this returns `None` if LLVM is disabled, or if we're in a
     /// check build or dry-run, where there's no need to build all of LLVM.
     fn llvm_config(&self, target: TargetSelection) -> Option<PathBuf> {
-        if self.config.llvm_enabled() && self.kind != Kind::Check && !self.config.dry_run {
+        if self.config.llvm_enabled() && self.kind != Kind::Check && !self.config.dry_run() {
             let llvm_config = self.ensure(native::Llvm { target });
             if llvm_config.is_file() {
                 return Some(llvm_config);
@@ -1300,19 +1063,6 @@ fn llvm_config(&self, target: TargetSelection) -> Option<PathBuf> {
         None
     }
 
-    /// Convenience wrapper to allow `builder.llvm_link_shared()` instead of `builder.config.llvm_link_shared(&builder)`.
-    pub(crate) fn llvm_link_shared(&self) -> bool {
-        Config::llvm_link_shared(self)
-    }
-
-    pub(crate) fn download_rustc(&self) -> bool {
-        Config::download_rustc(self)
-    }
-
-    pub(crate) fn initial_rustfmt(&self) -> Option<PathBuf> {
-        Config::initial_rustfmt(self)
-    }
-
     /// Prepares an invocation of `cargo` to be run.
     ///
     /// This will create a `Command` that represents a pending execution of
@@ -1643,7 +1393,7 @@ pub fn cargo(
         //
         // Only clear out the directory if we're compiling std; otherwise, we
         // should let Cargo take care of things for us (via depdep info)
-        if !self.config.dry_run && mode == Mode::Std && cmd == "build" {
+        if !self.config.dry_run() && mode == Mode::Std && cmd == "build" {
             self.clear_if_dirty(&out_dir, &self.rustc(compiler));
         }
 
@@ -2141,7 +1891,7 @@ pub fn ensure<S: Step>(&'a self, step: S) -> S::Output {
             (out, dur - deps)
         };
 
-        if self.config.print_step_timings && !self.config.dry_run {
+        if self.config.print_step_timings && !self.config.dry_run() {
             let step_string = format!("{:?}", step);
             let brace_index = step_string.find("{").unwrap_or(0);
             let type_string = type_name::<S>();
@@ -2215,7 +1965,7 @@ pub(crate) fn maybe_open_in_browser<S: Step>(&self, path: impl AsRef<Path>) {
     }
 
     pub(crate) fn open_in_browser(&self, path: impl AsRef<Path>) {
-        if self.config.dry_run || !self.config.cmd.open() {
+        if self.config.dry_run() || !self.config.cmd.open() {
             return;
         }
 
index 88bbcc93d072cc47ba11b30b14a2bdbf3334b368..5f21d2b0067dc57f6fd910453b528608cf7b9975 100644 (file)
@@ -1,5 +1,5 @@
 use super::*;
-use crate::config::{Config, TargetSelection};
+use crate::config::{Config, DryRun, TargetSelection};
 use std::thread;
 
 fn configure(cmd: &str, host: &[&str], target: &[&str]) -> Config {
@@ -10,7 +10,7 @@ fn configure_with_args(cmd: &[String], host: &[&str], target: &[&str]) -> Config
     let mut config = Config::parse(cmd);
     // don't save toolstates
     config.save_toolstates = None;
-    config.dry_run = true;
+    config.dry_run = DryRun::SelfCheck;
 
     // Ignore most submodules, since we don't need them for a dry run.
     // But make sure to check out the `doc` and `rust-analyzer` submodules, since some steps need them
index 258352a21a4ad76a2bc4582b4ed5dba919b64700..eae81b9fc69c83c91919804bf18858b1ca66baed 100644 (file)
 use crate::util::t;
 use crate::Build;
 
+#[derive(Clone, Default)]
 pub enum GitInfo {
     /// This is not a git repository.
+    #[default]
     Absent,
     /// This is a git repository.
     /// If the info should be used (`ignore_git` is false), this will be
@@ -25,6 +27,7 @@ pub enum GitInfo {
     RecordedForTarball(Info),
 }
 
+#[derive(Clone)]
 pub struct Info {
     pub commit_date: String,
     pub sha: String,
index 18e780a108d5a5420f677c2706786111766967d9..54906a4918bc12b3d67d90853b38f97a511abe9d 100644 (file)
@@ -206,7 +206,6 @@ fn copy_third_party_objects(
     }
 
     if target == "x86_64-fortanix-unknown-sgx"
-        || target.contains("pc-windows-gnullvm")
         || builder.config.llvm_libunwind(target) == LlvmLibunwind::InTree
             && (target.contains("linux") || target.contains("fuchsia"))
     {
@@ -447,7 +446,7 @@ fn copy_sanitizers(
 ) -> Vec<PathBuf> {
     let runtimes: Vec<native::SanitizerRuntime> = builder.ensure(native::Sanitizers { target });
 
-    if builder.config.dry_run {
+    if builder.config.dry_run() {
         return Vec::new();
     }
 
@@ -764,10 +763,10 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS
 
     cargo.env("CFG_LIBDIR_RELATIVE", libdir_relative);
 
-    if let Some(ref ver_date) = builder.rust_info.commit_date() {
+    if let Some(ref ver_date) = builder.rust_info().commit_date() {
         cargo.env("CFG_VER_DATE", ver_date);
     }
-    if let Some(ref ver_hash) = builder.rust_info.sha() {
+    if let Some(ref ver_hash) = builder.rust_info().sha() {
         cargo.env("CFG_VER_HASH", ver_hash);
     }
     if !builder.unstable_features() {
@@ -986,7 +985,7 @@ fn run(self, builder: &Builder<'_>) {
             compiler.stage, backend, &compiler.host, target
         ));
         let files = run_cargo(builder, cargo, vec![], &tmp_stamp, vec![], false);
-        if builder.config.dry_run {
+        if builder.config.dry_run() {
             return;
         }
         let mut files = files.into_iter().filter(|f| {
@@ -1034,7 +1033,7 @@ fn copy_codegen_backends_to_sysroot(
     let dst = builder.sysroot_codegen_backends(target_compiler);
     t!(fs::create_dir_all(&dst), dst);
 
-    if builder.config.dry_run {
+    if builder.config.dry_run() {
         return;
     }
 
@@ -1332,7 +1331,7 @@ fn run(self, builder: &Builder<'_>) -> Compiler {
 
         if builder.config.rust_codegen_backends.contains(&INTERNER.intern_str("llvm")) {
             let llvm_config_bin = builder.ensure(native::Llvm { target: target_compiler.host });
-            if !builder.config.dry_run {
+            if !builder.config.dry_run() {
                 let llvm_bin_dir = output(Command::new(llvm_config_bin).arg("--bindir"));
                 let llvm_bin_dir = Path::new(llvm_bin_dir.trim());
 
@@ -1402,7 +1401,7 @@ pub fn run_cargo(
     additional_target_deps: Vec<(PathBuf, DependencyType)>,
     is_check: bool,
 ) -> Vec<PathBuf> {
-    if builder.config.dry_run {
+    if builder.config.dry_run() {
         return Vec::new();
     }
 
@@ -1542,7 +1541,7 @@ pub fn stream_cargo(
     cb: &mut dyn FnMut(CargoMessage<'_>),
 ) -> bool {
     let mut cargo = Command::from(cargo);
-    if builder.config.dry_run {
+    if builder.config.dry_run() {
         return true;
     }
     // Instruct Cargo to give us json messages on stdout, critically leaving
index 21dc11c48081e8f18ac2da327378772b85a5cd8c..af004aa5098542a5d3bbc44af8ddd4382c72501f 100644 (file)
@@ -7,19 +7,18 @@
 use std::cmp;
 use std::collections::{HashMap, HashSet};
 use std::env;
-use std::ffi::OsStr;
 use std::fmt;
 use std::fs;
 use std::path::{Path, PathBuf};
 use std::process::Command;
 use std::str::FromStr;
 
-use crate::builder::{Builder, TaskPath};
+use crate::builder::TaskPath;
 use crate::cache::{Interned, INTERNER};
-use crate::channel::GitInfo;
+use crate::channel::{self, GitInfo};
 pub use crate::flags::Subcommand;
 use crate::flags::{Color, Flags};
-use crate::util::{exe, output, program_out_of_date, t};
+use crate::util::{exe, output, t};
 use once_cell::sync::OnceCell;
 use serde::{Deserialize, Deserializer};
 
@@ -33,6 +32,17 @@ macro_rules! check_ci_llvm {
     };
 }
 
+#[derive(Clone, Default)]
+pub enum DryRun {
+    /// This isn't a dry run.
+    #[default]
+    Disabled,
+    /// This is a dry run enabled by bootstrap itself, so it can verify that no work is done.
+    SelfCheck,
+    /// This is a dry run enabled by the `--dry-run` flag.
+    UserSelected,
+}
+
 /// Global configuration for the entire build and/or bootstrap.
 ///
 /// This structure is derived from a combination of both `config.toml` and
@@ -80,11 +90,11 @@ pub struct Config {
     pub keep_stage_std: Vec<u32>,
     pub src: PathBuf,
     /// defaults to `config.toml`
-    pub config: PathBuf,
+    pub config: Option<PathBuf>,
     pub jobs: Option<u32>,
     pub cmd: Subcommand,
     pub incremental: bool,
-    pub dry_run: bool,
+    pub dry_run: DryRun,
     /// `None` if we shouldn't download CI compiler artifacts, or the commit to download if we should.
     #[cfg(not(test))]
     download_rustc_commit: Option<String>,
@@ -213,6 +223,7 @@ pub struct Config {
     #[cfg(test)]
     pub initial_rustfmt: RefCell<RustfmtState>,
     pub out: PathBuf,
+    pub rust_info: channel::GitInfo,
 }
 
 #[derive(Default, Deserialize)]
@@ -781,7 +792,7 @@ pub fn default_opts() -> Config {
         config.llvm_optimize = true;
         config.ninja_in_file = true;
         config.llvm_version_check = true;
-        config.llvm_static_stdcpp = true;
+        config.llvm_static_stdcpp = false;
         config.backtrace = true;
         config.rust_optimize = true;
         config.rust_optimize_tests = true;
@@ -820,7 +831,7 @@ pub fn parse(args: &[String]) -> Config {
         config.jobs = flags.jobs.map(threads_from_config);
         config.cmd = flags.cmd;
         config.incremental = flags.incremental;
-        config.dry_run = flags.dry_run;
+        config.dry_run = if flags.dry_run { DryRun::UserSelected } else { DryRun::Disabled };
         config.keep_stage = flags.keep_stage;
         config.keep_stage_std = flags.keep_stage_std;
         config.color = flags.color;
@@ -926,8 +937,10 @@ pub fn parse(args: &[String]) -> Config {
         // Give a hard error if `--config` or `RUST_BOOTSTRAP_CONFIG` are set to a missing path,
         // but not if `config.toml` hasn't been created.
         let mut toml = if !using_default_path || toml_path.exists() {
+            config.config = Some(toml_path.clone());
             get_toml(&toml_path)
         } else {
+            config.config = None;
             TomlConfig::default()
         };
 
@@ -942,7 +955,6 @@ pub fn parse(args: &[String]) -> Config {
         }
 
         config.changelog_seen = toml.changelog_seen;
-        config.config = toml_path;
 
         let build = toml.build.unwrap_or_default();
 
@@ -964,7 +976,7 @@ pub fn parse(args: &[String]) -> Config {
             .unwrap_or_else(|| config.out.join(config.build.triple).join("stage0/bin/cargo"));
 
         // NOTE: it's important this comes *after* we set `initial_rustc` just above.
-        if config.dry_run {
+        if config.dry_run() {
             let dir = config.out.join("tmp-dry-run");
             t!(fs::create_dir_all(&dir));
             config.out = dir;
@@ -1192,7 +1204,7 @@ pub fn parse(args: &[String]) -> Config {
             config.rust_codegen_units_std = rust.codegen_units_std.map(threads_from_config);
             config.rust_profile_use = flags.rust_profile_use.or(rust.profile_use);
             config.rust_profile_generate = flags.rust_profile_generate.or(rust.profile_generate);
-            config.download_rustc_commit = download_ci_rustc_commit(&config, rust.download_rustc);
+            config.download_rustc_commit = config.download_ci_rustc_commit(rust.download_rustc);
 
             config.rust_lto = rust
                 .lto
@@ -1314,6 +1326,7 @@ pub fn parse(args: &[String]) -> Config {
 
         let default = config.channel == "dev";
         config.ignore_git = ignore_git.unwrap_or(default);
+        config.rust_info = GitInfo::new(config.ignore_git, &config.src);
 
         let download_rustc = config.download_rustc_commit.is_some();
         // See https://github.com/rust-lang/compiler-team/issues/326
@@ -1371,6 +1384,13 @@ pub fn parse(args: &[String]) -> Config {
         config
     }
 
+    pub(crate) fn dry_run(&self) -> bool {
+        match self.dry_run {
+            DryRun::Disabled => false,
+            DryRun::SelfCheck | DryRun::UserSelected => true,
+        }
+    }
+
     /// A git invocation which runs inside the source directory.
     ///
     /// Use this rather than `Command::new("git")` in order to support out-of-tree builds.
@@ -1382,8 +1402,8 @@ pub(crate) fn git(&self) -> Command {
 
     /// Bootstrap embeds a version number into the name of shared libraries it uploads in CI.
     /// Return the version it would have used for the given commit.
-    pub(crate) fn artifact_version_part(&self, builder: &Builder<'_>, commit: &str) -> String {
-        let (channel, version) = if builder.rust_info.is_managed_git_subrepository() {
+    pub(crate) fn artifact_version_part(&self, commit: &str) -> String {
+        let (channel, version) = if self.rust_info.is_managed_git_subrepository() {
             let mut channel = self.git();
             channel.arg("show").arg(format!("{}:src/ci/channel", commit));
             let channel = output(&mut channel);
@@ -1392,14 +1412,14 @@ pub(crate) fn artifact_version_part(&self, builder: &Builder<'_>, commit: &str)
             let version = output(&mut version);
             (channel.trim().to_owned(), version.trim().to_owned())
         } else {
-            let channel = fs::read_to_string(builder.src.join("src/ci/channel"));
-            let version = fs::read_to_string(builder.src.join("src/version"));
+            let channel = fs::read_to_string(self.src.join("src/ci/channel"));
+            let version = fs::read_to_string(self.src.join("src/version"));
             match (channel, version) {
                 (Ok(channel), Ok(version)) => {
                     (channel.trim().to_owned(), version.trim().to_owned())
                 }
                 (channel, version) => {
-                    let src = builder.src.display();
+                    let src = self.src.display();
                     eprintln!("error: failed to determine artifact channel and/or version");
                     eprintln!(
                         "help: consider using a git checkout or ensure these files are readable"
@@ -1458,17 +1478,17 @@ pub(crate) fn ci_llvm_root(&self) -> PathBuf {
     ///
     /// If `false`, llvm should be linked statically.
     /// This is computed on demand since LLVM might have to first be downloaded from CI.
-    pub(crate) fn llvm_link_shared(builder: &Builder<'_>) -> bool {
-        let mut opt = builder.config.llvm_link_shared.get();
-        if opt.is_none() && builder.config.dry_run {
+    pub(crate) fn llvm_link_shared(&self) -> bool {
+        let mut opt = self.llvm_link_shared.get();
+        if opt.is_none() && self.dry_run() {
             // just assume static for now - dynamic linking isn't supported on all platforms
             return false;
         }
 
         let llvm_link_shared = *opt.get_or_insert_with(|| {
-            if builder.config.llvm_from_ci {
-                crate::native::maybe_download_ci_llvm(builder);
-                let ci_llvm = builder.config.ci_llvm_root();
+            if self.llvm_from_ci {
+                self.maybe_download_ci_llvm();
+                let ci_llvm = self.ci_llvm_root();
                 let link_type = t!(
                     std::fs::read_to_string(ci_llvm.join("link-type.txt")),
                     format!("CI llvm missing: {}", ci_llvm.display())
@@ -1480,36 +1500,36 @@ pub(crate) fn llvm_link_shared(builder: &Builder<'_>) -> bool {
                 false
             }
         });
-        builder.config.llvm_link_shared.set(opt);
+        self.llvm_link_shared.set(opt);
         llvm_link_shared
     }
 
     /// Return whether we will use a downloaded, pre-compiled version of rustc, or just build from source.
-    pub(crate) fn download_rustc(builder: &Builder<'_>) -> bool {
+    pub(crate) fn download_rustc(&self) -> bool {
         static DOWNLOAD_RUSTC: OnceCell<bool> = OnceCell::new();
-        if builder.config.dry_run && DOWNLOAD_RUSTC.get().is_none() {
+        if self.dry_run() && DOWNLOAD_RUSTC.get().is_none() {
             // avoid trying to actually download the commit
             return false;
         }
 
-        *DOWNLOAD_RUSTC.get_or_init(|| match &builder.config.download_rustc_commit {
+        *DOWNLOAD_RUSTC.get_or_init(|| match &self.download_rustc_commit {
             None => false,
             Some(commit) => {
-                download_ci_rustc(builder, commit);
+                self.download_ci_rustc(commit);
                 true
             }
         })
     }
 
-    pub(crate) fn initial_rustfmt(builder: &Builder<'_>) -> Option<PathBuf> {
-        match &mut *builder.config.initial_rustfmt.borrow_mut() {
+    pub(crate) fn initial_rustfmt(&self) -> Option<PathBuf> {
+        match &mut *self.initial_rustfmt.borrow_mut() {
             RustfmtState::SystemToolchain(p) | RustfmtState::Downloaded(p) => Some(p.clone()),
             RustfmtState::Unavailable => None,
             r @ RustfmtState::LazyEvaluated => {
-                if builder.config.dry_run {
+                if self.dry_run() {
                     return Some(PathBuf::new());
                 }
-                let path = maybe_download_rustfmt(builder);
+                let path = self.maybe_download_rustfmt();
                 *r = if let Some(p) = &path {
                     RustfmtState::Downloaded(p.clone())
                 } else {
@@ -1520,8 +1540,10 @@ pub(crate) fn initial_rustfmt(builder: &Builder<'_>) -> Option<PathBuf> {
         }
     }
 
-    pub fn verbose(&self) -> bool {
-        self.verbose > 0
+    pub fn verbose(&self, msg: &str) {
+        if self.verbose > 0 {
+            println!("{}", msg);
+        }
     }
 
     pub fn sanitizers_enabled(&self, target: TargetSelection) -> bool {
@@ -1559,218 +1581,77 @@ pub fn llvm_libunwind(&self, target: TargetSelection) -> LlvmLibunwind {
     pub fn submodules(&self, rust_info: &GitInfo) -> bool {
         self.submodules.unwrap_or(rust_info.is_managed_git_subrepository())
     }
-}
-
-fn set<T>(field: &mut T, val: Option<T>) {
-    if let Some(v) = val {
-        *field = v;
-    }
-}
 
-fn threads_from_config(v: u32) -> u32 {
-    match v {
-        0 => std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get) as u32,
-        n => n,
-    }
-}
+    /// Returns the commit to download, or `None` if we shouldn't download CI artifacts.
+    fn download_ci_rustc_commit(&self, download_rustc: Option<StringOrBool>) -> Option<String> {
+        // If `download-rustc` is not set, default to rebuilding.
+        let if_unchanged = match download_rustc {
+            None | Some(StringOrBool::Bool(false)) => return None,
+            Some(StringOrBool::Bool(true)) => false,
+            Some(StringOrBool::String(s)) if s == "if-unchanged" => true,
+            Some(StringOrBool::String(other)) => {
+                panic!("unrecognized option for download-rustc: {}", other)
+            }
+        };
 
-/// Returns the commit to download, or `None` if we shouldn't download CI artifacts.
-fn download_ci_rustc_commit(
-    config: &Config,
-    download_rustc: Option<StringOrBool>,
-) -> Option<String> {
-    // If `download-rustc` is not set, default to rebuilding.
-    let if_unchanged = match download_rustc {
-        None | Some(StringOrBool::Bool(false)) => return None,
-        Some(StringOrBool::Bool(true)) => false,
-        Some(StringOrBool::String(s)) if s == "if-unchanged" => true,
-        Some(StringOrBool::String(other)) => {
-            panic!("unrecognized option for download-rustc: {}", other)
+        // Handle running from a directory other than the top level
+        let top_level = output(self.git().args(&["rev-parse", "--show-toplevel"]));
+        let top_level = top_level.trim_end();
+        let compiler = format!("{top_level}/compiler/");
+        let library = format!("{top_level}/library/");
+
+        // Look for a version to compare to based on the current commit.
+        // Only commits merged by bors will have CI artifacts.
+        let merge_base = output(
+            self.git()
+                .arg("rev-list")
+                .arg(format!("--author={}", self.stage0_metadata.config.git_merge_commit_email))
+                .args(&["-n1", "--first-parent", "HEAD"]),
+        );
+        let commit = merge_base.trim_end();
+        if commit.is_empty() {
+            println!("error: could not find commit hash for downloading rustc");
+            println!("help: maybe your repository history is too shallow?");
+            println!("help: consider disabling `download-rustc`");
+            println!("help: or fetch enough history to include one upstream commit");
+            crate::detail_exit(1);
         }
-    };
 
-    // Handle running from a directory other than the top level
-    let top_level = output(config.git().args(&["rev-parse", "--show-toplevel"]));
-    let top_level = top_level.trim_end();
-    let compiler = format!("{top_level}/compiler/");
-    let library = format!("{top_level}/library/");
-
-    // Look for a version to compare to based on the current commit.
-    // Only commits merged by bors will have CI artifacts.
-    let merge_base = output(
-        config
+        // Warn if there were changes to the compiler or standard library since the ancestor commit.
+        let has_changes = !t!(self
             .git()
-            .arg("rev-list")
-            .arg(format!("--author={}", config.stage0_metadata.config.git_merge_commit_email))
-            .args(&["-n1", "--first-parent", "HEAD"]),
-    );
-    let commit = merge_base.trim_end();
-    if commit.is_empty() {
-        println!("error: could not find commit hash for downloading rustc");
-        println!("help: maybe your repository history is too shallow?");
-        println!("help: consider disabling `download-rustc`");
-        println!("help: or fetch enough history to include one upstream commit");
-        crate::detail_exit(1);
-    }
-
-    // Warn if there were changes to the compiler or standard library since the ancestor commit.
-    let has_changes = !t!(config
-        .git()
-        .args(&["diff-index", "--quiet", &commit, "--", &compiler, &library])
-        .status())
-    .success();
-    if has_changes {
-        if if_unchanged {
-            if config.verbose > 0 {
-                println!(
-                    "warning: saw changes to compiler/ or library/ since {commit}; \
-                          ignoring `download-rustc`"
-                );
+            .args(&["diff-index", "--quiet", &commit, "--", &compiler, &library])
+            .status())
+        .success();
+        if has_changes {
+            if if_unchanged {
+                if self.verbose > 0 {
+                    println!(
+                        "warning: saw changes to compiler/ or library/ since {commit}; \
+                            ignoring `download-rustc`"
+                    );
+                }
+                return None;
             }
-            return None;
+            println!(
+                "warning: `download-rustc` is enabled, but there are changes to \
+                    compiler/ or library/"
+            );
         }
-        println!(
-            "warning: `download-rustc` is enabled, but there are changes to \
-                  compiler/ or library/"
-        );
-    }
 
-    Some(commit.to_string())
-}
-
-fn maybe_download_rustfmt(builder: &Builder<'_>) -> Option<PathBuf> {
-    let RustfmtMetadata { date, version } = builder.config.stage0_metadata.rustfmt.as_ref()?;
-    let channel = format!("{version}-{date}");
-
-    let host = builder.config.build;
-    let rustfmt_path = builder.config.initial_rustc.with_file_name(exe("rustfmt", host));
-    let bin_root = builder.config.out.join(host.triple).join("stage0");
-    let rustfmt_stamp = bin_root.join(".rustfmt-stamp");
-    if rustfmt_path.exists() && !program_out_of_date(&rustfmt_stamp, &channel) {
-        return Some(rustfmt_path);
+        Some(commit.to_string())
     }
-
-    let filename = format!("rustfmt-{version}-{build}.tar.xz", build = host.triple);
-    download_component(builder, DownloadSource::Dist, filename, "rustfmt-preview", &date, "stage0");
-
-    builder.fix_bin_or_dylib(&bin_root.join("bin").join("rustfmt"));
-    builder.fix_bin_or_dylib(&bin_root.join("bin").join("cargo-fmt"));
-
-    builder.create(&rustfmt_stamp, &channel);
-    Some(rustfmt_path)
 }
 
-fn download_ci_rustc(builder: &Builder<'_>, commit: &str) {
-    builder.verbose(&format!("using downloaded stage2 artifacts from CI (commit {commit})"));
-    let version = builder.config.artifact_version_part(builder, commit);
-    let host = builder.config.build.triple;
-    let bin_root = builder.out.join(host).join("ci-rustc");
-    let rustc_stamp = bin_root.join(".rustc-stamp");
-
-    if !bin_root.join("bin").join("rustc").exists() || program_out_of_date(&rustc_stamp, commit) {
-        if bin_root.exists() {
-            t!(fs::remove_dir_all(&bin_root));
-        }
-        let filename = format!("rust-std-{version}-{host}.tar.xz");
-        let pattern = format!("rust-std-{host}");
-        download_ci_component(builder, filename, &pattern, commit);
-        let filename = format!("rustc-{version}-{host}.tar.xz");
-        download_ci_component(builder, filename, "rustc", commit);
-        // download-rustc doesn't need its own cargo, it can just use beta's.
-        let filename = format!("rustc-dev-{version}-{host}.tar.xz");
-        download_ci_component(builder, filename, "rustc-dev", commit);
-
-        builder.fix_bin_or_dylib(&bin_root.join("bin").join("rustc"));
-        builder.fix_bin_or_dylib(&bin_root.join("bin").join("rustdoc"));
-        let lib_dir = bin_root.join("lib");
-        for lib in t!(fs::read_dir(&lib_dir), lib_dir.display().to_string()) {
-            let lib = t!(lib);
-            if lib.path().extension() == Some(OsStr::new("so")) {
-                builder.fix_bin_or_dylib(&lib.path());
-            }
-        }
-        t!(fs::write(rustc_stamp, commit));
+fn set<T>(field: &mut T, val: Option<T>) {
+    if let Some(v) = val {
+        *field = v;
     }
 }
 
-pub(crate) enum DownloadSource {
-    CI,
-    Dist,
-}
-
-/// Download a single component of a CI-built toolchain (not necessarily a published nightly).
-// NOTE: intentionally takes an owned string to avoid downloading multiple times by accident
-fn download_ci_component(builder: &Builder<'_>, filename: String, prefix: &str, commit: &str) {
-    download_component(builder, DownloadSource::CI, filename, prefix, commit, "ci-rustc")
-}
-
-fn download_component(
-    builder: &Builder<'_>,
-    mode: DownloadSource,
-    filename: String,
-    prefix: &str,
-    key: &str,
-    destination: &str,
-) {
-    let cache_dst = builder.out.join("cache");
-    let cache_dir = cache_dst.join(key);
-    if !cache_dir.exists() {
-        t!(fs::create_dir_all(&cache_dir));
-    }
-
-    let bin_root = builder.out.join(builder.config.build.triple).join(destination);
-    let tarball = cache_dir.join(&filename);
-    let (base_url, url, should_verify) = match mode {
-        DownloadSource::CI => (
-            builder.config.stage0_metadata.config.artifacts_server.clone(),
-            format!("{key}/{filename}"),
-            false,
-        ),
-        DownloadSource::Dist => {
-            let dist_server = env::var("RUSTUP_DIST_SERVER")
-                .unwrap_or(builder.config.stage0_metadata.config.dist_server.to_string());
-            // NOTE: make `dist` part of the URL because that's how it's stored in src/stage0.json
-            (dist_server, format!("dist/{key}/{filename}"), true)
-        }
-    };
-
-    // For the beta compiler, put special effort into ensuring the checksums are valid.
-    // FIXME: maybe we should do this for download-rustc as well? but it would be a pain to update
-    // this on each and every nightly ...
-    let checksum = if should_verify {
-        let error = format!(
-            "src/stage0.json doesn't contain a checksum for {url}. \
-            Pre-built artifacts might not be available for this \
-            target at this time, see https://doc.rust-lang.org/nightly\
-            /rustc/platform-support.html for more information."
-        );
-        let sha256 = builder.config.stage0_metadata.checksums_sha256.get(&url).expect(&error);
-        if tarball.exists() {
-            if builder.verify(&tarball, sha256) {
-                builder.unpack(&tarball, &bin_root, prefix);
-                return;
-            } else {
-                builder.verbose(&format!(
-                    "ignoring cached file {} due to failed verification",
-                    tarball.display()
-                ));
-                builder.remove(&tarball);
-            }
-        }
-        Some(sha256)
-    } else if tarball.exists() {
-        builder.unpack(&tarball, &bin_root, prefix);
-        return;
-    } else {
-        None
-    };
-
-    builder.download_component(&format!("{base_url}/{url}"), &tarball, "");
-    if let Some(sha256) = checksum {
-        if !builder.verify(&tarball, sha256) {
-            panic!("failed to verify {}", tarball.display());
-        }
+fn threads_from_config(v: u32) -> u32 {
+    match v {
+        0 => std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get) as u32,
+        n => n,
     }
-
-    builder.unpack(&tarball, &bin_root, prefix);
 }
index 110a3ee4918da2d1ee6a1f359533f91ade9b4244..aacd2c7eab9814dc960f19ebaa2704e15a81c748 100644 (file)
@@ -924,13 +924,13 @@ fn run(self, builder: &Builder<'_>) -> GeneratedTarball {
 
         // Create the version file
         builder.create(&plain_dst_src.join("version"), &builder.rust_version());
-        if let Some(info) = builder.rust_info.info() {
+        if let Some(info) = builder.rust_info().info() {
             channel::write_commit_hash_file(&plain_dst_src, &info.sha);
             channel::write_commit_info_file(&plain_dst_src, info);
         }
 
         // If we're building from git sources, we need to vendor a complete distribution.
-        if builder.rust_info.is_managed_git_subrepository() {
+        if builder.rust_info().is_managed_git_subrepository() {
             // Ensure we have the submodules checked out.
             builder.update_submodule(Path::new("src/tools/rust-analyzer"));
 
@@ -945,7 +945,7 @@ fn run(self, builder: &Builder<'_>) -> GeneratedTarball {
                 .arg(builder.src.join("./src/bootstrap/Cargo.toml"))
                 .current_dir(&plain_dst_src);
 
-            let config = if !builder.config.dry_run {
+            let config = if !builder.config.dry_run() {
                 t!(String::from_utf8(t!(cmd.output()).stdout))
             } else {
                 String::new()
@@ -1386,7 +1386,7 @@ macro_rules! add_component {
         let etc = builder.src.join("src/etc/installer");
 
         // Avoid producing tarballs during a dry run.
-        if builder.config.dry_run {
+        if builder.config.dry_run() {
             return;
         }
 
@@ -1818,7 +1818,7 @@ fn filter(contents: &str, marker: &str) -> String {
             let _time = timeit(builder);
             builder.run(&mut cmd);
 
-            if !builder.config.dry_run {
+            if !builder.config.dry_run() {
                 t!(fs::rename(exe.join(&filename), distdir(builder).join(&filename)));
             }
         }
@@ -1882,12 +1882,12 @@ fn maybe_install_llvm(builder: &Builder<'_>, target: TargetSelection, dst_libdir
         if llvm_dylib_path.exists() {
             builder.install(&llvm_dylib_path, dst_libdir, 0o644);
         }
-        !builder.config.dry_run
+        !builder.config.dry_run()
     } else if let Ok(llvm_config) = crate::native::prebuilt_llvm_config(builder, target) {
         let mut cmd = Command::new(llvm_config);
         cmd.arg("--libfiles");
         builder.verbose(&format!("running {:?}", cmd));
-        let files = if builder.config.dry_run { "".into() } else { output(&mut cmd) };
+        let files = if builder.config.dry_run() { "".into() } else { output(&mut cmd) };
         let build_llvm_out = &builder.llvm_out(builder.config.build);
         let target_llvm_out = &builder.llvm_out(target);
         for file in files.trim_end().split(' ') {
@@ -1899,7 +1899,7 @@ fn maybe_install_llvm(builder: &Builder<'_>, target: TargetSelection, dst_libdir
             };
             builder.install(&file, dst_libdir, 0o644);
         }
-        !builder.config.dry_run
+        !builder.config.dry_run()
     } else {
         false
     }
index 280e232ca2dd02e7a67a4c5d84b584af0b7bd38a..3180a12c85be759984d013d5a5907127a4e0e373 100644 (file)
@@ -151,7 +151,7 @@ fn run(self, builder: &Builder<'_>) {
         let index = out.join("index.html");
         let rustbook = builder.tool_exe(Tool::Rustbook);
         let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook);
-        if builder.config.dry_run || up_to_date(&src, &index) && up_to_date(&rustbook, &index) {
+        if builder.config.dry_run() || up_to_date(&src, &index) && up_to_date(&rustbook, &index) {
             return;
         }
         builder.info(&format!("Rustbook ({}) - {}", target, name));
@@ -331,8 +331,8 @@ fn run(self, builder: &Builder<'_>) {
                 && up_to_date(&footer, &html)
                 && up_to_date(&favicon, &html)
                 && up_to_date(&full_toc, &html)
-                && (builder.config.dry_run || up_to_date(&version_info, &html))
-                && (builder.config.dry_run || up_to_date(&rustdoc, &html))
+                && (builder.config.dry_run() || up_to_date(&version_info, &html))
+                && (builder.config.dry_run() || up_to_date(&rustdoc, &html))
             {
                 continue;
             }
@@ -402,11 +402,11 @@ fn run(self, builder: &Builder<'_>) -> Self::Output {
 
         let version_input = builder.src.join("src").join("doc").join("version_info.html.template");
         let version_info = out.join("version_info.html");
-        if !builder.config.dry_run && !up_to_date(&version_input, &version_info) {
+        if !builder.config.dry_run() && !up_to_date(&version_input, &version_info) {
             let info = t!(fs::read_to_string(&version_input))
                 .replace("VERSION", &builder.rust_release())
-                .replace("SHORT_HASH", builder.rust_info.sha_short().unwrap_or(""))
-                .replace("STAMP", builder.rust_info.sha().unwrap_or(""));
+                .replace("SHORT_HASH", builder.rust_info().sha_short().unwrap_or(""))
+                .replace("STAMP", builder.rust_info().sha().unwrap_or(""));
             t!(fs::write(&version_info, &info));
         }
 
@@ -900,7 +900,7 @@ fn run(self, builder: &Builder<'_>) {
 }
 
 fn symlink_dir_force(config: &Config, src: &Path, dst: &Path) -> io::Result<()> {
-    if config.dry_run {
+    if config.dry_run() {
         return Ok(());
     }
     if let Ok(m) = fs::symlink_metadata(dst) {
@@ -965,7 +965,7 @@ fn run(self, builder: &Builder<'_>) {
         cmd.arg("--rustc");
         cmd.arg(&rustc);
         cmd.arg("--rustc-target").arg(&self.target.rustc_target_arg());
-        if builder.config.verbose() {
+        if builder.is_verbose() {
             cmd.arg("--verbose");
         }
         if self.validate {
diff --git a/src/bootstrap/download.rs b/src/bootstrap/download.rs
new file mode 100644 (file)
index 0000000..d0f389d
--- /dev/null
@@ -0,0 +1,519 @@
+use std::{
+    env,
+    ffi::{OsStr, OsString},
+    fs::{self, File},
+    io::{BufRead, BufReader, ErrorKind},
+    path::{Path, PathBuf},
+    process::{Command, Stdio},
+};
+
+use once_cell::sync::OnceCell;
+use xz2::bufread::XzDecoder;
+
+use crate::{
+    config::RustfmtMetadata,
+    native::detect_llvm_sha,
+    t,
+    util::{check_run, exe, program_out_of_date, try_run},
+    Config,
+};
+
+/// Generic helpers that are useful anywhere in bootstrap.
+impl Config {
+    pub fn is_verbose(&self) -> bool {
+        self.verbose > 0
+    }
+
+    pub(crate) fn create(&self, path: &Path, s: &str) {
+        if self.dry_run() {
+            return;
+        }
+        t!(fs::write(path, s));
+    }
+
+    pub(crate) fn remove(&self, f: &Path) {
+        if self.dry_run() {
+            return;
+        }
+        fs::remove_file(f).unwrap_or_else(|_| panic!("failed to remove {:?}", f));
+    }
+
+    /// Create a temporary directory in `out` and return its path.
+    ///
+    /// NOTE: this temporary directory is shared between all steps;
+    /// if you need an empty directory, create a new subdirectory inside it.
+    pub(crate) fn tempdir(&self) -> PathBuf {
+        let tmp = self.out.join("tmp");
+        t!(fs::create_dir_all(&tmp));
+        tmp
+    }
+
+    /// Runs a command, printing out nice contextual information if it fails.
+    /// Exits if the command failed to execute at all, otherwise returns its
+    /// `status.success()`.
+    pub(crate) fn try_run(&self, cmd: &mut Command) -> bool {
+        if self.dry_run() {
+            return true;
+        }
+        self.verbose(&format!("running: {:?}", cmd));
+        try_run(cmd, self.is_verbose())
+    }
+
+    /// Runs a command, printing out nice contextual information if it fails.
+    /// Returns false if do not execute at all, otherwise returns its
+    /// `status.success()`.
+    pub(crate) fn check_run(&self, cmd: &mut Command) -> bool {
+        if self.dry_run() {
+            return true;
+        }
+        self.verbose(&format!("running: {:?}", cmd));
+        check_run(cmd, self.is_verbose())
+    }
+
+    /// Modifies the interpreter section of 'fname' to fix the dynamic linker,
+    /// or the RPATH section, to fix the dynamic library search path
+    ///
+    /// This is only required on NixOS and uses the PatchELF utility to
+    /// change the interpreter/RPATH of ELF executables.
+    ///
+    /// Please see https://nixos.org/patchelf.html for more information
+    fn fix_bin_or_dylib(&self, fname: &Path) {
+        // FIXME: cache NixOS detection?
+        match Command::new("uname").arg("-s").stderr(Stdio::inherit()).output() {
+            Err(_) => return,
+            Ok(output) if !output.status.success() => return,
+            Ok(output) => {
+                let mut s = output.stdout;
+                if s.last() == Some(&b'\n') {
+                    s.pop();
+                }
+                if s != b"Linux" {
+                    return;
+                }
+            }
+        }
+
+        // If the user has asked binaries to be patched for Nix, then
+        // don't check for NixOS or `/lib`, just continue to the patching.
+        // NOTE: this intentionally comes after the Linux check:
+        // - patchelf only works with ELF files, so no need to run it on Mac or Windows
+        // - On other Unix systems, there is no stable syscall interface, so Nix doesn't manage the global libc.
+        if !self.patch_binaries_for_nix {
+            // Use `/etc/os-release` instead of `/etc/NIXOS`.
+            // The latter one does not exist on NixOS when using tmpfs as root.
+            const NIX_IDS: &[&str] = &["ID=nixos", "ID='nixos'", "ID=\"nixos\""];
+            let os_release = match File::open("/etc/os-release") {
+                Err(e) if e.kind() == ErrorKind::NotFound => return,
+                Err(e) => panic!("failed to access /etc/os-release: {}", e),
+                Ok(f) => f,
+            };
+            if !BufReader::new(os_release).lines().any(|l| NIX_IDS.contains(&t!(l).trim())) {
+                return;
+            }
+            if Path::new("/lib").exists() {
+                return;
+            }
+        }
+
+        // At this point we're pretty sure the user is running NixOS or using Nix
+        println!("info: you seem to be using Nix. Attempting to patch {}", fname.display());
+
+        // Only build `.nix-deps` once.
+        static NIX_DEPS_DIR: OnceCell<PathBuf> = OnceCell::new();
+        let mut nix_build_succeeded = true;
+        let nix_deps_dir = NIX_DEPS_DIR.get_or_init(|| {
+            // Run `nix-build` to "build" each dependency (which will likely reuse
+            // the existing `/nix/store` copy, or at most download a pre-built copy).
+            //
+            // Importantly, we create a gc-root called `.nix-deps` in the `build/`
+            // directory, but still reference the actual `/nix/store` path in the rpath
+            // as it makes it significantly more robust against changes to the location of
+            // the `.nix-deps` location.
+            //
+            // bintools: Needed for the path of `ld-linux.so` (via `nix-support/dynamic-linker`).
+            // zlib: Needed as a system dependency of `libLLVM-*.so`.
+            // patchelf: Needed for patching ELF binaries (see doc comment above).
+            let nix_deps_dir = self.out.join(".nix-deps");
+            const NIX_EXPR: &str = "
+            with (import <nixpkgs> {});
+            symlinkJoin {
+                name = \"rust-stage0-dependencies\";
+                paths = [
+                    zlib
+                    patchelf
+                    stdenv.cc.bintools
+                ];
+            }
+            ";
+            nix_build_succeeded = self.try_run(Command::new("nix-build").args(&[
+                Path::new("-E"),
+                Path::new(NIX_EXPR),
+                Path::new("-o"),
+                &nix_deps_dir,
+            ]));
+            nix_deps_dir
+        });
+        if !nix_build_succeeded {
+            return;
+        }
+
+        let mut patchelf = Command::new(nix_deps_dir.join("bin/patchelf"));
+        let rpath_entries = {
+            // ORIGIN is a relative default, all binary and dynamic libraries we ship
+            // appear to have this (even when `../lib` is redundant).
+            // NOTE: there are only two paths here, delimited by a `:`
+            let mut entries = OsString::from("$ORIGIN/../lib:");
+            entries.push(t!(fs::canonicalize(nix_deps_dir)));
+            entries.push("/lib");
+            entries
+        };
+        patchelf.args(&[OsString::from("--set-rpath"), rpath_entries]);
+        if !fname.extension().map_or(false, |ext| ext == "so") {
+            // Finally, set the correct .interp for binaries
+            let dynamic_linker_path = nix_deps_dir.join("nix-support/dynamic-linker");
+            // FIXME: can we support utf8 here? `args` doesn't accept Vec<u8>, only OsString ...
+            let dynamic_linker = t!(String::from_utf8(t!(fs::read(dynamic_linker_path))));
+            patchelf.args(&["--set-interpreter", dynamic_linker.trim_end()]);
+        }
+
+        self.try_run(patchelf.arg(fname));
+    }
+
+    fn download_file(&self, url: &str, dest_path: &Path, help_on_error: &str) {
+        self.verbose(&format!("download {url}"));
+        // Use a temporary file in case we crash while downloading, to avoid a corrupt download in cache/.
+        let tempfile = self.tempdir().join(dest_path.file_name().unwrap());
+        // While bootstrap itself only supports http and https downloads, downstream forks might
+        // need to download components from other protocols. The match allows them adding more
+        // protocols without worrying about merge conflicts if we change the HTTP implementation.
+        match url.split_once("://").map(|(proto, _)| proto) {
+            Some("http") | Some("https") => {
+                self.download_http_with_retries(&tempfile, url, help_on_error)
+            }
+            Some(other) => panic!("unsupported protocol {other} in {url}"),
+            None => panic!("no protocol in {url}"),
+        }
+        t!(std::fs::rename(&tempfile, dest_path));
+    }
+
+    fn download_http_with_retries(&self, tempfile: &Path, url: &str, help_on_error: &str) {
+        println!("downloading {}", url);
+        // Try curl. If that fails and we are on windows, fallback to PowerShell.
+        let mut curl = Command::new("curl");
+        curl.args(&[
+            "-#",
+            "-y",
+            "30",
+            "-Y",
+            "10", // timeout if speed is < 10 bytes/sec for > 30 seconds
+            "--connect-timeout",
+            "30", // timeout if cannot connect within 30 seconds
+            "--retry",
+            "3",
+            "-Sf",
+            "-o",
+        ]);
+        curl.arg(tempfile);
+        curl.arg(url);
+        if !self.check_run(&mut curl) {
+            if self.build.contains("windows-msvc") {
+                println!("Fallback to PowerShell");
+                for _ in 0..3 {
+                    if self.try_run(Command::new("PowerShell.exe").args(&[
+                        "/nologo",
+                        "-Command",
+                        "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;",
+                        &format!(
+                            "(New-Object System.Net.WebClient).DownloadFile('{}', '{}')",
+                            url, tempfile.to_str().expect("invalid UTF-8 not supported with powershell downloads"),
+                        ),
+                    ])) {
+                        return;
+                    }
+                    println!("\nspurious failure, trying again");
+                }
+            }
+            if !help_on_error.is_empty() {
+                eprintln!("{}", help_on_error);
+            }
+            crate::detail_exit(1);
+        }
+    }
+
+    fn unpack(&self, tarball: &Path, dst: &Path, pattern: &str) {
+        println!("extracting {} to {}", tarball.display(), dst.display());
+        if !dst.exists() {
+            t!(fs::create_dir_all(dst));
+        }
+
+        // `tarball` ends with `.tar.xz`; strip that suffix
+        // example: `rust-dev-nightly-x86_64-unknown-linux-gnu`
+        let uncompressed_filename =
+            Path::new(tarball.file_name().expect("missing tarball filename")).file_stem().unwrap();
+        let directory_prefix = Path::new(Path::new(uncompressed_filename).file_stem().unwrap());
+
+        // decompress the file
+        let data = t!(File::open(tarball));
+        let decompressor = XzDecoder::new(BufReader::new(data));
+
+        let mut tar = tar::Archive::new(decompressor);
+        for member in t!(tar.entries()) {
+            let mut member = t!(member);
+            let original_path = t!(member.path()).into_owned();
+            // skip the top-level directory
+            if original_path == directory_prefix {
+                continue;
+            }
+            let mut short_path = t!(original_path.strip_prefix(directory_prefix));
+            if !short_path.starts_with(pattern) {
+                continue;
+            }
+            short_path = t!(short_path.strip_prefix(pattern));
+            let dst_path = dst.join(short_path);
+            self.verbose(&format!("extracting {} to {}", original_path.display(), dst.display()));
+            if !t!(member.unpack_in(dst)) {
+                panic!("path traversal attack ??");
+            }
+            let src_path = dst.join(original_path);
+            if src_path.is_dir() && dst_path.exists() {
+                continue;
+            }
+            t!(fs::rename(src_path, dst_path));
+        }
+        t!(fs::remove_dir_all(dst.join(directory_prefix)));
+    }
+
+    /// Returns whether the SHA256 checksum of `path` matches `expected`.
+    fn verify(&self, path: &Path, expected: &str) -> bool {
+        use sha2::Digest;
+
+        self.verbose(&format!("verifying {}", path.display()));
+        let mut hasher = sha2::Sha256::new();
+        // FIXME: this is ok for rustfmt (4.1 MB large at time of writing), but it seems memory-intensive for rustc and larger components.
+        // Consider using streaming IO instead?
+        let contents = if self.dry_run() { vec![] } else { t!(fs::read(path)) };
+        hasher.update(&contents);
+        let found = hex::encode(hasher.finalize().as_slice());
+        let verified = found == expected;
+        if !verified && !self.dry_run() {
+            println!(
+                "invalid checksum: \n\
+                found:    {found}\n\
+                expected: {expected}",
+            );
+        }
+        return verified;
+    }
+}
+
+enum DownloadSource {
+    CI,
+    Dist,
+}
+
+/// Functions that are only ever called once, but named for clarify and to avoid thousand-line functions.
+impl Config {
+    pub(crate) fn maybe_download_rustfmt(&self) -> Option<PathBuf> {
+        let RustfmtMetadata { date, version } = self.stage0_metadata.rustfmt.as_ref()?;
+        let channel = format!("{version}-{date}");
+
+        let host = self.build;
+        let rustfmt_path = self.initial_rustc.with_file_name(exe("rustfmt", host));
+        let bin_root = self.out.join(host.triple).join("stage0");
+        let rustfmt_stamp = bin_root.join(".rustfmt-stamp");
+        if rustfmt_path.exists() && !program_out_of_date(&rustfmt_stamp, &channel) {
+            return Some(rustfmt_path);
+        }
+
+        let filename = format!("rustfmt-{version}-{build}.tar.xz", build = host.triple);
+        self.download_component(DownloadSource::Dist, filename, "rustfmt-preview", &date, "stage0");
+
+        self.fix_bin_or_dylib(&bin_root.join("bin").join("rustfmt"));
+        self.fix_bin_or_dylib(&bin_root.join("bin").join("cargo-fmt"));
+
+        self.create(&rustfmt_stamp, &channel);
+        Some(rustfmt_path)
+    }
+
+    pub(crate) fn download_ci_rustc(&self, commit: &str) {
+        self.verbose(&format!("using downloaded stage2 artifacts from CI (commit {commit})"));
+        let version = self.artifact_version_part(commit);
+        let host = self.build.triple;
+        let bin_root = self.out.join(host).join("ci-rustc");
+        let rustc_stamp = bin_root.join(".rustc-stamp");
+
+        if !bin_root.join("bin").join("rustc").exists() || program_out_of_date(&rustc_stamp, commit)
+        {
+            if bin_root.exists() {
+                t!(fs::remove_dir_all(&bin_root));
+            }
+            let filename = format!("rust-std-{version}-{host}.tar.xz");
+            let pattern = format!("rust-std-{host}");
+            self.download_ci_component(filename, &pattern, commit);
+            let filename = format!("rustc-{version}-{host}.tar.xz");
+            self.download_ci_component(filename, "rustc", commit);
+            // download-rustc doesn't need its own cargo, it can just use beta's.
+            let filename = format!("rustc-dev-{version}-{host}.tar.xz");
+            self.download_ci_component(filename, "rustc-dev", commit);
+            let filename = format!("rust-src-{version}.tar.xz");
+            self.download_ci_component(filename, "rust-src", commit);
+
+            self.fix_bin_or_dylib(&bin_root.join("bin").join("rustc"));
+            self.fix_bin_or_dylib(&bin_root.join("bin").join("rustdoc"));
+            let lib_dir = bin_root.join("lib");
+            for lib in t!(fs::read_dir(&lib_dir), lib_dir.display().to_string()) {
+                let lib = t!(lib);
+                if lib.path().extension() == Some(OsStr::new("so")) {
+                    self.fix_bin_or_dylib(&lib.path());
+                }
+            }
+            t!(fs::write(rustc_stamp, commit));
+        }
+    }
+
+    /// Download a single component of a CI-built toolchain (not necessarily a published nightly).
+    // NOTE: intentionally takes an owned string to avoid downloading multiple times by accident
+    fn download_ci_component(&self, filename: String, prefix: &str, commit: &str) {
+        Self::download_component(self, DownloadSource::CI, filename, prefix, commit, "ci-rustc")
+    }
+
+    fn download_component(
+        &self,
+        mode: DownloadSource,
+        filename: String,
+        prefix: &str,
+        key: &str,
+        destination: &str,
+    ) {
+        let cache_dst = self.out.join("cache");
+        let cache_dir = cache_dst.join(key);
+        if !cache_dir.exists() {
+            t!(fs::create_dir_all(&cache_dir));
+        }
+
+        let bin_root = self.out.join(self.build.triple).join(destination);
+        let tarball = cache_dir.join(&filename);
+        let (base_url, url, should_verify) = match mode {
+            DownloadSource::CI => (
+                self.stage0_metadata.config.artifacts_server.clone(),
+                format!("{key}/{filename}"),
+                false,
+            ),
+            DownloadSource::Dist => {
+                let dist_server = env::var("RUSTUP_DIST_SERVER")
+                    .unwrap_or(self.stage0_metadata.config.dist_server.to_string());
+                // NOTE: make `dist` part of the URL because that's how it's stored in src/stage0.json
+                (dist_server, format!("dist/{key}/{filename}"), true)
+            }
+        };
+
+        // For the beta compiler, put special effort into ensuring the checksums are valid.
+        // FIXME: maybe we should do this for download-rustc as well? but it would be a pain to update
+        // this on each and every nightly ...
+        let checksum = if should_verify {
+            let error = format!(
+                "src/stage0.json doesn't contain a checksum for {url}. \
+                Pre-built artifacts might not be available for this \
+                target at this time, see https://doc.rust-lang.org/nightly\
+                /rustc/platform-support.html for more information."
+            );
+            let sha256 = self.stage0_metadata.checksums_sha256.get(&url).expect(&error);
+            if tarball.exists() {
+                if self.verify(&tarball, sha256) {
+                    self.unpack(&tarball, &bin_root, prefix);
+                    return;
+                } else {
+                    self.verbose(&format!(
+                        "ignoring cached file {} due to failed verification",
+                        tarball.display()
+                    ));
+                    self.remove(&tarball);
+                }
+            }
+            Some(sha256)
+        } else if tarball.exists() {
+            self.unpack(&tarball, &bin_root, prefix);
+            return;
+        } else {
+            None
+        };
+
+        self.download_file(&format!("{base_url}/{url}"), &tarball, "");
+        if let Some(sha256) = checksum {
+            if !self.verify(&tarball, sha256) {
+                panic!("failed to verify {}", tarball.display());
+            }
+        }
+
+        self.unpack(&tarball, &bin_root, prefix);
+    }
+
+    pub(crate) fn maybe_download_ci_llvm(&self) {
+        if !self.llvm_from_ci {
+            return;
+        }
+        let llvm_root = self.ci_llvm_root();
+        let llvm_stamp = llvm_root.join(".llvm-stamp");
+        let llvm_sha = detect_llvm_sha(&self, self.rust_info.is_managed_git_subrepository());
+        let key = format!("{}{}", llvm_sha, self.llvm_assertions);
+        if program_out_of_date(&llvm_stamp, &key) && !self.dry_run() {
+            self.download_ci_llvm(&llvm_sha);
+            for entry in t!(fs::read_dir(llvm_root.join("bin"))) {
+                self.fix_bin_or_dylib(&t!(entry).path());
+            }
+
+            // Update the timestamp of llvm-config to force rustc_llvm to be
+            // rebuilt. This is a hacky workaround for a deficiency in Cargo where
+            // the rerun-if-changed directive doesn't handle changes very well.
+            // https://github.com/rust-lang/cargo/issues/10791
+            // Cargo only compares the timestamp of the file relative to the last
+            // time `rustc_llvm` build script ran. However, the timestamps of the
+            // files in the tarball are in the past, so it doesn't trigger a
+            // rebuild.
+            let now = filetime::FileTime::from_system_time(std::time::SystemTime::now());
+            let llvm_config = llvm_root.join("bin").join(exe("llvm-config", self.build));
+            t!(filetime::set_file_times(&llvm_config, now, now));
+
+            let llvm_lib = llvm_root.join("lib");
+            for entry in t!(fs::read_dir(&llvm_lib)) {
+                let lib = t!(entry).path();
+                if lib.extension().map_or(false, |ext| ext == "so") {
+                    self.fix_bin_or_dylib(&lib);
+                }
+            }
+            t!(fs::write(llvm_stamp, key));
+        }
+    }
+
+    fn download_ci_llvm(&self, llvm_sha: &str) {
+        let llvm_assertions = self.llvm_assertions;
+
+        let cache_prefix = format!("llvm-{}-{}", llvm_sha, llvm_assertions);
+        let cache_dst = self.out.join("cache");
+        let rustc_cache = cache_dst.join(cache_prefix);
+        if !rustc_cache.exists() {
+            t!(fs::create_dir_all(&rustc_cache));
+        }
+        let base = if llvm_assertions {
+            &self.stage0_metadata.config.artifacts_with_llvm_assertions_server
+        } else {
+            &self.stage0_metadata.config.artifacts_server
+        };
+        let version = self.artifact_version_part(llvm_sha);
+        let filename = format!("rust-dev-{}-{}.tar.xz", version, self.build.triple);
+        let tarball = rustc_cache.join(&filename);
+        if !tarball.exists() {
+            let help_on_error = "error: failed to download llvm from ci
+
+    help: old builds get deleted after a certain time
+    help: if trying to compile an old commit of rustc, disable `download-ci-llvm` in config.toml:
+
+    [llvm]
+    download-ci-llvm = false
+    ";
+            self.download_file(&format!("{base}/{llvm_sha}/{filename}"), &tarball, help_on_error);
+        }
+        let llvm_root = self.ci_llvm_root();
+        self.unpack(&tarball, &llvm_root, "rust-dev");
+    }
+}
index ee341a353ac470867699aab12fdb29a06066ec64..2001e29bd2eadc56759de805020fb83fc86cdc25 100644 (file)
@@ -140,6 +140,7 @@ pub enum Subcommand {
     },
     Run {
         paths: Vec<PathBuf>,
+        args: Vec<String>,
     },
     Setup {
         profile: Profile,
@@ -342,6 +343,9 @@ pub fn parse(args: &[String]) -> Flags {
             Kind::Format => {
                 opts.optflag("", "check", "check formatting instead of applying.");
             }
+            Kind::Run => {
+                opts.optmulti("", "args", "arguments for the tool", "ARGS");
+            }
             _ => {}
         };
 
@@ -613,7 +617,7 @@ pub fn parse(args: &[String]) -> Flags {
                     println!("\nrun requires at least a path!\n");
                     usage(1, &opts, verbose, &subcommand_help);
                 }
-                Subcommand::Run { paths }
+                Subcommand::Run { paths, args: matches.opt_strs("args") }
             }
             Kind::Setup => {
                 let profile = if paths.len() > 1 {
@@ -721,16 +725,12 @@ pub fn kind(&self) -> Kind {
     }
 
     pub fn test_args(&self) -> Vec<&str> {
-        let mut args = vec![];
-
         match *self {
             Subcommand::Test { ref test_args, .. } | Subcommand::Bench { ref test_args, .. } => {
-                args.extend(test_args.iter().flat_map(|s| s.split_whitespace()))
+                test_args.iter().flat_map(|s| s.split_whitespace()).collect()
             }
-            _ => (),
+            _ => vec![],
         }
-
-        args
     }
 
     pub fn rustc_args(&self) -> Vec<&str> {
@@ -738,7 +738,16 @@ pub fn rustc_args(&self) -> Vec<&str> {
             Subcommand::Test { ref rustc_args, .. } => {
                 rustc_args.iter().flat_map(|s| s.split_whitespace()).collect()
             }
-            _ => Vec::new(),
+            _ => vec![],
+        }
+    }
+
+    pub fn args(&self) -> Vec<&str> {
+        match *self {
+            Subcommand::Run { ref args, .. } => {
+                args.iter().flat_map(|s| s.split_whitespace()).collect()
+            }
+            _ => vec![],
         }
     }
 
index 37322670e656483864a662a7537db4d6fdd1650b..5e7264fe765a950ac9980b7ef55b5e05023312d6 100644 (file)
@@ -43,7 +43,7 @@ struct RustfmtConfig {
 }
 
 pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
-    if build.config.dry_run {
+    if build.config.dry_run() {
         return;
     }
     let mut builder = ignore::types::TypesBuilder::new();
index f5def8ba8341f58b817afaedb9828e75a6ad0ff7..f4fa556b97450e56fa4c979e45e74c4f73b89e3d 100644 (file)
 use std::process::Command;
 use std::str;
 
-use config::Target;
+use channel::GitInfo;
+use config::{DryRun, Target};
 use filetime::FileTime;
 use once_cell::sync::OnceCell;
 
 use crate::builder::Kind;
 use crate::config::{LlvmLibunwind, TargetSelection};
-use crate::util::{
-    check_run, exe, libdir, mtime, output, run, run_suppressed, try_run, try_run_suppressed, CiEnv,
-};
+use crate::util::{exe, libdir, mtime, output, run, run_suppressed, try_run_suppressed, CiEnv};
 
 mod bolt;
 mod builder;
 mod config;
 mod dist;
 mod doc;
+mod download;
 mod flags;
 mod format;
 mod install;
@@ -281,7 +281,6 @@ pub struct Build {
     src: PathBuf,
     out: PathBuf,
     bootstrap_out: PathBuf,
-    rust_info: channel::GitInfo,
     cargo_info: channel::GitInfo,
     rust_analyzer_info: channel::GitInfo,
     clippy_info: channel::GitInfo,
@@ -396,6 +395,28 @@ pub enum CLang {
     Cxx,
 }
 
+macro_rules! forward {
+    ( $( $fn:ident( $($param:ident: $ty:ty),* ) $( -> $ret:ty)? ),+ $(,)? ) => {
+        impl Build {
+            $( fn $fn(&self, $($param: $ty),* ) $( -> $ret)? {
+                self.config.$fn( $($param),* )
+            } )+
+        }
+    }
+}
+
+forward! {
+    verbose(msg: &str),
+    is_verbose() -> bool,
+    create(path: &Path, s: &str),
+    remove(f: &Path),
+    tempdir() -> PathBuf,
+    try_run(cmd: &mut Command) -> bool,
+    llvm_link_shared() -> bool,
+    download_rustc() -> bool,
+    initial_rustfmt() -> Option<PathBuf>,
+}
+
 impl Build {
     /// Creates a new set of build configuration from the `flags` on the command
     /// line and the filesystem `config`.
@@ -430,7 +451,7 @@ pub fn new(mut config: Config) -> Build {
         // we always try to use git for LLVM builds
         let in_tree_llvm_info = channel::GitInfo::new(false, &src.join("src/llvm-project"));
 
-        let initial_target_libdir_str = if config.dry_run {
+        let initial_target_libdir_str = if config.dry_run() {
             "/dummy/lib/path/to/lib/".to_string()
         } else {
             output(
@@ -444,7 +465,7 @@ pub fn new(mut config: Config) -> Build {
         let initial_target_dir = Path::new(&initial_target_libdir_str).parent().unwrap();
         let initial_lld = initial_target_dir.join("bin").join("rust-lld");
 
-        let initial_sysroot = if config.dry_run {
+        let initial_sysroot = if config.dry_run() {
             "/dummy".to_string()
         } else {
             output(Command::new(&config.initial_rustc).arg("--print").arg("sysroot"))
@@ -499,7 +520,6 @@ pub fn new(mut config: Config) -> Build {
             out,
             bootstrap_out,
 
-            rust_info,
             cargo_info,
             rust_analyzer_info,
             clippy_info,
@@ -570,7 +590,7 @@ fn dir_is_empty(dir: &Path) -> bool {
             t!(std::fs::read_dir(dir)).next().is_none()
         }
 
-        if !self.config.submodules(&self.rust_info) {
+        if !self.config.submodules(&self.rust_info()) {
             return;
         }
 
@@ -636,7 +656,7 @@ fn dir_is_empty(dir: &Path) -> bool {
     /// This avoids contributors checking in a submodule change by accident.
     pub fn maybe_update_submodules(&self) {
         // Avoid running git when there isn't a git checkout.
-        if !self.config.submodules(&self.rust_info) {
+        if !self.config.submodules(&self.rust_info()) {
             return;
         }
         let output = output(
@@ -689,13 +709,13 @@ pub fn build(&mut self) {
             }
         }
 
-        if !self.config.dry_run {
+        if !self.config.dry_run() {
             {
-                self.config.dry_run = true;
+                self.config.dry_run = DryRun::SelfCheck;
                 let builder = builder::Builder::new(&self);
                 builder.execute_cli();
             }
-            self.config.dry_run = false;
+            self.config.dry_run = DryRun::Disabled;
             let builder = builder::Builder::new(&self);
             builder.execute_cli();
         } else {
@@ -735,6 +755,10 @@ fn clear_if_dirty(&self, dir: &Path, input: &Path) -> bool {
         cleared
     }
 
+    fn rust_info(&self) -> &GitInfo {
+        &self.config.rust_info
+    }
+
     /// Gets the space-separated set of activated features for the standard
     /// library.
     fn std_features(&self, target: TargetSelection) -> String {
@@ -947,7 +971,7 @@ fn rustc_snapshot_sysroot(&self) -> &Path {
 
     /// Runs a command, printing out nice contextual information if it fails.
     fn run(&self, cmd: &mut Command) {
-        if self.config.dry_run {
+        if self.config.dry_run() {
             return;
         }
         self.verbose(&format!("running: {:?}", cmd));
@@ -956,57 +980,24 @@ fn run(&self, cmd: &mut Command) {
 
     /// Runs a command, printing out nice contextual information if it fails.
     fn run_quiet(&self, cmd: &mut Command) {
-        if self.config.dry_run {
+        if self.config.dry_run() {
             return;
         }
         self.verbose(&format!("running: {:?}", cmd));
         run_suppressed(cmd)
     }
 
-    /// Runs a command, printing out nice contextual information if it fails.
-    /// Exits if the command failed to execute at all, otherwise returns its
-    /// `status.success()`.
-    fn try_run(&self, cmd: &mut Command) -> bool {
-        if self.config.dry_run {
-            return true;
-        }
-        self.verbose(&format!("running: {:?}", cmd));
-        try_run(cmd, self.is_verbose())
-    }
-
     /// Runs a command, printing out nice contextual information if it fails.
     /// Exits if the command failed to execute at all, otherwise returns its
     /// `status.success()`.
     fn try_run_quiet(&self, cmd: &mut Command) -> bool {
-        if self.config.dry_run {
+        if self.config.dry_run() {
             return true;
         }
         self.verbose(&format!("running: {:?}", cmd));
         try_run_suppressed(cmd)
     }
 
-    /// Runs a command, printing out nice contextual information if it fails.
-    /// Returns false if do not execute at all, otherwise returns its
-    /// `status.success()`.
-    fn check_run(&self, cmd: &mut Command) -> bool {
-        if self.config.dry_run {
-            return true;
-        }
-        self.verbose(&format!("running: {:?}", cmd));
-        check_run(cmd, self.is_verbose())
-    }
-
-    pub fn is_verbose(&self) -> bool {
-        self.verbosity > 0
-    }
-
-    /// Prints a message if this build is configured in verbose mode.
-    fn verbose(&self, msg: &str) {
-        if self.is_verbose() {
-            println!("{}", msg);
-        }
-    }
-
     pub fn is_verbose_than(&self, level: usize) -> bool {
         self.verbosity > level
     }
@@ -1019,10 +1010,12 @@ fn verbose_than(&self, level: usize, msg: &str) {
     }
 
     fn info(&self, msg: &str) {
-        if self.config.dry_run {
-            return;
+        match self.config.dry_run {
+            DryRun::SelfCheck => return,
+            DryRun::Disabled | DryRun::UserSelected => {
+                println!("{}", msg);
+            }
         }
-        println!("{}", msg);
     }
 
     /// Returns the number of parallel jobs that have been configured for this
@@ -1267,7 +1260,7 @@ fn release(&self, num: &str) -> String {
         match &self.config.channel[..] {
             "stable" => num.to_string(),
             "beta" => {
-                if self.rust_info.is_managed_git_subrepository() && !self.config.ignore_git {
+                if self.rust_info().is_managed_git_subrepository() && !self.config.ignore_git {
                     format!("{}-beta.{}", num, self.beta_prerelease_version())
                 } else {
                     format!("{}-beta", num)
@@ -1327,7 +1320,7 @@ fn rust_package_vers(&self) -> String {
     /// Note that this is a descriptive string which includes the commit date,
     /// sha, version, etc.
     fn rust_version(&self) -> String {
-        let mut version = self.rust_info.version(self, &self.version);
+        let mut version = self.rust_info().version(self, &self.version);
         if let Some(ref s) = self.config.description {
             version.push_str(" (");
             version.push_str(s);
@@ -1338,7 +1331,7 @@ fn rust_version(&self) -> String {
 
     /// Returns the full commit hash.
     fn rust_sha(&self) -> Option<&str> {
-        self.rust_info.sha()
+        self.rust_info().sha()
     }
 
     /// Returns the `a.b.c` version that the given package is at.
@@ -1400,7 +1393,7 @@ fn in_tree_crates(&self, root: &str, target: Option<TargetSelection>) -> Vec<&Cr
     }
 
     fn read_stamp_file(&self, stamp: &Path) -> Vec<(PathBuf, DependencyType)> {
-        if self.config.dry_run {
+        if self.config.dry_run() {
             return Vec::new();
         }
 
@@ -1424,23 +1417,13 @@ fn read_stamp_file(&self, stamp: &Path) -> Vec<(PathBuf, DependencyType)> {
         paths
     }
 
-    /// Create a temporary directory in `out` and return its path.
-    ///
-    /// NOTE: this temporary directory is shared between all steps;
-    /// if you need an empty directory, create a new subdirectory inside it.
-    fn tempdir(&self) -> PathBuf {
-        let tmp = self.out.join("tmp");
-        t!(fs::create_dir_all(&tmp));
-        tmp
-    }
-
     /// Copies a file from `src` to `dst`
     pub fn copy(&self, src: &Path, dst: &Path) {
         self.copy_internal(src, dst, false);
     }
 
     fn copy_internal(&self, src: &Path, dst: &Path, dereference_symlinks: bool) {
-        if self.config.dry_run {
+        if self.config.dry_run() {
             return;
         }
         self.verbose_than(1, &format!("Copy {:?} to {:?}", src, dst));
@@ -1477,7 +1460,7 @@ fn copy_internal(&self, src: &Path, dst: &Path, dereference_symlinks: bool) {
     /// Copies the `src` directory recursively to `dst`. Both are assumed to exist
     /// when this function is called.
     pub fn cp_r(&self, src: &Path, dst: &Path) {
-        if self.config.dry_run {
+        if self.config.dry_run() {
             return;
         }
         for f in self.read_dir(src) {
@@ -1530,7 +1513,7 @@ fn copy_to_folder(&self, src: &Path, dest_folder: &Path) {
     }
 
     fn install(&self, src: &Path, dstdir: &Path, perms: u32) {
-        if self.config.dry_run {
+        if self.config.dry_run() {
             return;
         }
         let dst = dstdir.join(src.file_name().unwrap());
@@ -1543,29 +1526,22 @@ fn install(&self, src: &Path, dstdir: &Path, perms: u32) {
         chmod(&dst, perms);
     }
 
-    fn create(&self, path: &Path, s: &str) {
-        if self.config.dry_run {
-            return;
-        }
-        t!(fs::write(path, s));
-    }
-
     fn read(&self, path: &Path) -> String {
-        if self.config.dry_run {
+        if self.config.dry_run() {
             return String::new();
         }
         t!(fs::read_to_string(path))
     }
 
     fn create_dir(&self, dir: &Path) {
-        if self.config.dry_run {
+        if self.config.dry_run() {
             return;
         }
         t!(fs::create_dir_all(dir))
     }
 
     fn remove_dir(&self, dir: &Path) {
-        if self.config.dry_run {
+        if self.config.dry_run() {
             return;
         }
         t!(fs::remove_dir_all(dir))
@@ -1574,7 +1550,7 @@ fn remove_dir(&self, dir: &Path) {
     fn read_dir(&self, dir: &Path) -> impl Iterator<Item = fs::DirEntry> {
         let iter = match fs::read_dir(dir) {
             Ok(v) => v,
-            Err(_) if self.config.dry_run => return vec![].into_iter(),
+            Err(_) if self.config.dry_run() => return vec![].into_iter(),
             Err(err) => panic!("could not read dir {:?}: {:?}", dir, err),
         };
         iter.map(|e| t!(e)).collect::<Vec<_>>().into_iter()
@@ -1585,14 +1561,7 @@ fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(&self, src: P, link: Q) -> io::R
         use std::os::unix::fs::symlink as symlink_file;
         #[cfg(windows)]
         use std::os::windows::fs::symlink_file;
-        if !self.config.dry_run { symlink_file(src.as_ref(), link.as_ref()) } else { Ok(()) }
-    }
-
-    fn remove(&self, f: &Path) {
-        if self.config.dry_run {
-            return;
-        }
-        fs::remove_file(f).unwrap_or_else(|_| panic!("failed to remove {:?}", f));
+        if !self.config.dry_run() { symlink_file(src.as_ref(), link.as_ref()) } else { Ok(()) }
     }
 
     /// Returns if config.ninja is enabled, and checks for ninja existence,
index 94a61b727a32bccfb2bd33e1b47b1fc68a4d74f5..f6c453ebe107bd6f6f2309b42065d801528624e6 100644 (file)
@@ -19,9 +19,9 @@
 use crate::bolt::{instrument_with_bolt_inplace, optimize_library_with_bolt_inplace};
 use crate::builder::{Builder, RunConfig, ShouldRun, Step};
 use crate::channel;
-use crate::config::TargetSelection;
+use crate::config::{Config, TargetSelection};
 use crate::util::get_clang_cl_resource_dir;
-use crate::util::{self, exe, output, program_out_of_date, t, up_to_date};
+use crate::util::{self, exe, output, t, up_to_date};
 use crate::{CLang, GitRepo};
 
 pub struct Meta {
@@ -65,7 +65,7 @@ pub fn prebuilt_llvm_config(
     builder: &Builder<'_>,
     target: TargetSelection,
 ) -> Result<PathBuf, Meta> {
-    maybe_download_ci_llvm(builder);
+    builder.config.maybe_download_ci_llvm();
 
     // If we're using a custom LLVM bail out here, but we can only use a
     // custom LLVM for the build triple.
@@ -117,7 +117,7 @@ pub fn prebuilt_llvm_config(
 }
 
 /// This retrieves the LLVM sha we *want* to use, according to git history.
-pub(crate) fn detect_llvm_sha(config: &crate::config::Config, is_git: bool) -> String {
+pub(crate) fn detect_llvm_sha(config: &Config, is_git: bool) -> String {
     let llvm_sha = if is_git {
         let mut rev_list = config.git();
         rev_list.args(&[
@@ -155,7 +155,7 @@ pub(crate) fn detect_llvm_sha(config: &crate::config::Config, is_git: bool) -> S
 /// This checks both the build triple platform to confirm we're usable at all,
 /// and then verifies if the current HEAD matches the detected LLVM SHA head,
 /// in which case LLVM is indicated as not available.
-pub(crate) fn is_ci_llvm_available(config: &crate::config::Config, asserts: bool) -> bool {
+pub(crate) fn is_ci_llvm_available(config: &Config, asserts: bool) -> bool {
     // This is currently all tier 1 targets and tier 2 targets with host tools
     // (since others may not have CI artifacts)
     // https://doc.rust-lang.org/rustc/platform-support.html#tier-1
@@ -217,80 +217,6 @@ pub(crate) fn is_ci_llvm_available(config: &crate::config::Config, asserts: bool
     true
 }
 
-pub(crate) fn maybe_download_ci_llvm(builder: &Builder<'_>) {
-    let config = &builder.config;
-    if !config.llvm_from_ci {
-        return;
-    }
-    let llvm_root = config.ci_llvm_root();
-    let llvm_stamp = llvm_root.join(".llvm-stamp");
-    let llvm_sha = detect_llvm_sha(&config, builder.rust_info.is_managed_git_subrepository());
-    let key = format!("{}{}", llvm_sha, config.llvm_assertions);
-    if program_out_of_date(&llvm_stamp, &key) && !config.dry_run {
-        download_ci_llvm(builder, &llvm_sha);
-        for entry in t!(fs::read_dir(llvm_root.join("bin"))) {
-            builder.fix_bin_or_dylib(&t!(entry).path());
-        }
-
-        // Update the timestamp of llvm-config to force rustc_llvm to be
-        // rebuilt. This is a hacky workaround for a deficiency in Cargo where
-        // the rerun-if-changed directive doesn't handle changes very well.
-        // https://github.com/rust-lang/cargo/issues/10791
-        // Cargo only compares the timestamp of the file relative to the last
-        // time `rustc_llvm` build script ran. However, the timestamps of the
-        // files in the tarball are in the past, so it doesn't trigger a
-        // rebuild.
-        let now = filetime::FileTime::from_system_time(std::time::SystemTime::now());
-        let llvm_config = llvm_root.join("bin").join(exe("llvm-config", builder.config.build));
-        t!(filetime::set_file_times(&llvm_config, now, now));
-
-        let llvm_lib = llvm_root.join("lib");
-        for entry in t!(fs::read_dir(&llvm_lib)) {
-            let lib = t!(entry).path();
-            if lib.extension().map_or(false, |ext| ext == "so") {
-                builder.fix_bin_or_dylib(&lib);
-            }
-        }
-        t!(fs::write(llvm_stamp, key));
-    }
-}
-
-fn download_ci_llvm(builder: &Builder<'_>, llvm_sha: &str) {
-    let llvm_assertions = builder.config.llvm_assertions;
-
-    let cache_prefix = format!("llvm-{}-{}", llvm_sha, llvm_assertions);
-    let cache_dst = builder.out.join("cache");
-    let rustc_cache = cache_dst.join(cache_prefix);
-    if !rustc_cache.exists() {
-        t!(fs::create_dir_all(&rustc_cache));
-    }
-    let base = if llvm_assertions {
-        &builder.config.stage0_metadata.config.artifacts_with_llvm_assertions_server
-    } else {
-        &builder.config.stage0_metadata.config.artifacts_server
-    };
-    let version = builder.config.artifact_version_part(builder, llvm_sha);
-    let filename = format!("rust-dev-{}-{}.tar.xz", version, builder.build.build.triple);
-    let tarball = rustc_cache.join(&filename);
-    if !tarball.exists() {
-        let help_on_error = "error: failed to download llvm from ci
-
-help: old builds get deleted after a certain time
-help: if trying to compile an old commit of rustc, disable `download-ci-llvm` in config.toml:
-
-[llvm]
-download-ci-llvm = false
-";
-        builder.download_component(
-            &format!("{base}/{llvm_sha}/{filename}"),
-            &tarball,
-            help_on_error,
-        );
-    }
-    let llvm_root = builder.config.ci_llvm_root();
-    builder.unpack(&tarball, &llvm_root, "rust-dev");
-}
-
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Llvm {
     pub target: TargetSelection,
@@ -505,7 +431,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
         // https://llvm.org/docs/HowToCrossCompileLLVM.html
         if target != builder.config.build {
             let llvm_config = builder.ensure(Llvm { target: builder.config.build });
-            if !builder.config.dry_run {
+            if !builder.config.dry_run() {
                 let llvm_bindir = output(Command::new(&llvm_config).arg("--bindir"));
                 let host_bin = Path::new(llvm_bindir.trim());
                 cfg.define(
@@ -519,7 +445,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
             if builder.config.llvm_clang {
                 let build_bin = builder.llvm_out(builder.config.build).join("build").join("bin");
                 let clang_tblgen = build_bin.join("clang-tblgen").with_extension(EXE_EXTENSION);
-                if !builder.config.dry_run && !clang_tblgen.exists() {
+                if !builder.config.dry_run() && !clang_tblgen.exists() {
                     panic!("unable to find {}", clang_tblgen.display());
                 }
                 cfg.define("CLANG_TABLEGEN", clang_tblgen);
@@ -553,7 +479,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
         //        tools. Figure out how to filter them down and only build the right
         //        tools and libs on all platforms.
 
-        if builder.config.dry_run {
+        if builder.config.dry_run() {
             return build_llvm_config;
         }
 
@@ -611,7 +537,7 @@ fn check_llvm_version(builder: &Builder<'_>, llvm_config: &Path) {
         return;
     }
 
-    if builder.config.dry_run {
+    if builder.config.dry_run() {
         return;
     }
 
@@ -872,7 +798,7 @@ fn make_run(run: RunConfig<'_>) {
 
     /// Compile LLD for `target`.
     fn run(self, builder: &Builder<'_>) -> PathBuf {
-        if builder.config.dry_run {
+        if builder.config.dry_run() {
             return PathBuf::from("lld-out-dir-test-gen");
         }
         let target = self.target;
@@ -990,7 +916,7 @@ fn make_run(run: RunConfig<'_>) {
     /// Compiles the `rust_test_helpers.c` library which we used in various
     /// `run-pass` tests for ABI testing.
     fn run(self, builder: &Builder<'_>) {
-        if builder.config.dry_run {
+        if builder.config.dry_run() {
             return;
         }
         // The x86_64-fortanix-unknown-sgx target doesn't have a working C
@@ -1066,7 +992,7 @@ fn run(self, builder: &Builder<'_>) -> Self::Output {
         }
 
         let llvm_config = builder.ensure(Llvm { target: builder.config.build });
-        if builder.config.dry_run {
+        if builder.config.dry_run() {
             return runtimes;
         }
 
@@ -1240,7 +1166,7 @@ fn make_run(run: RunConfig<'_>) {
     fn run(self, builder: &Builder<'_>) -> Self::Output {
         let out_dir = builder.native_dir(self.target).join("crt");
 
-        if builder.config.dry_run {
+        if builder.config.dry_run() {
             return out_dir;
         }
 
@@ -1304,7 +1230,7 @@ fn make_run(run: RunConfig<'_>) {
 
     /// Build linunwind.a
     fn run(self, builder: &Builder<'_>) -> Self::Output {
-        if builder.config.dry_run {
+        if builder.config.dry_run() {
             return PathBuf::new();
         }
 
index 511872903d14e29d7e2c28ff6efa7b2584785a3d..d49b41c51327961203f561254a85ef0ffad7346e 100644 (file)
@@ -1,8 +1,12 @@
+use std::process::Command;
+
 use crate::builder::{Builder, RunConfig, ShouldRun, Step};
+use crate::config::TargetSelection;
 use crate::dist::distdir;
-use crate::tool::Tool;
+use crate::test;
+use crate::tool::{self, SourceType, Tool};
 use crate::util::output;
-use std::process::Command;
+use crate::Mode;
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct ExpandYamlAnchors;
@@ -125,3 +129,63 @@ fn run(self, builder: &Builder<'_>) -> Self::Output {
         builder.run(&mut cmd);
     }
 }
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub struct Miri {
+    stage: u32,
+    host: TargetSelection,
+    target: TargetSelection,
+}
+
+impl Step for Miri {
+    type Output = ();
+    const ONLY_HOSTS: bool = false;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.path("src/tools/miri")
+    }
+
+    fn make_run(run: RunConfig<'_>) {
+        run.builder.ensure(Miri {
+            stage: run.builder.top_stage,
+            host: run.build_triple(),
+            target: run.target,
+        });
+    }
+
+    fn run(self, builder: &Builder<'_>) {
+        let stage = self.stage;
+        let host = self.host;
+        let target = self.target;
+        let compiler = builder.compiler(stage, host);
+
+        let miri = builder
+            .ensure(tool::Miri { compiler, target: self.host, extra_features: Vec::new() })
+            .expect("in-tree tool");
+        let miri_sysroot = test::Miri::build_miri_sysroot(builder, compiler, &miri, target);
+
+        // # Run miri.
+        // Running it via `cargo run` as that figures out the right dylib path.
+        // add_rustc_lib_path does not add the path that contains librustc_driver-<...>.so.
+        let mut miri = tool::prepare_tool_cargo(
+            builder,
+            compiler,
+            Mode::ToolRustc,
+            host,
+            "run",
+            "src/tools/miri",
+            SourceType::InTree,
+            &[],
+        );
+        miri.add_rustc_lib_path(builder, compiler);
+        // Forward arguments.
+        miri.arg("--").arg("--target").arg(target.rustc_target_arg());
+        miri.args(builder.config.cmd.args());
+
+        // miri tests need to know about the stage sysroot
+        miri.env("MIRI_SYSROOT", &miri_sysroot);
+
+        let mut miri = Command::from(miri);
+        builder.run(&mut miri);
+    }
+}
index e905517253c0a364fe54b1e03de42d63063f5a44..631d42acb93fc3564093496169d0a9b4012a9166 100644 (file)
@@ -74,7 +74,7 @@ pub fn check(build: &mut Build) {
     let mut cmd_finder = Finder::new();
     // If we've got a git directory we're gonna need git to update
     // submodules and learn about various other aspects.
-    if build.rust_info.is_managed_git_subrepository() {
+    if build.rust_info().is_managed_git_subrepository() {
         cmd_finder.must_have("git");
     }
 
@@ -155,7 +155,15 @@ pub fn check(build: &mut Build) {
             continue;
         }
 
-        if !build.config.dry_run {
+        // Some environments don't want or need these tools, such as when testing Miri.
+        // FIXME: it would be better to refactor this code to split necessary setup from pure sanity
+        // checks, and have a regular flag for skipping the latter. Also see
+        // <https://github.com/rust-lang/rust/pull/103569#discussion_r1008741742>.
+        if env::var_os("BOOTSTRAP_SKIP_TARGET_SANITY").is_some() {
+            continue;
+        }
+
+        if !build.config.dry_run() {
             cmd_finder.must_have(build.cc(*target));
             if let Some(ar) = build.ar(*target) {
                 cmd_finder.must_have(ar);
@@ -164,7 +172,7 @@ pub fn check(build: &mut Build) {
     }
 
     for host in &build.hosts {
-        if !build.config.dry_run {
+        if !build.config.dry_run() {
             cmd_finder.must_have(build.cxx(*host).unwrap());
         }
     }
@@ -212,6 +220,14 @@ pub fn check(build: &mut Build) {
             }
         }
 
+        // Some environments don't want or need these tools, such as when testing Miri.
+        // FIXME: it would be better to refactor this code to split necessary setup from pure sanity
+        // checks, and have a regular flag for skipping the latter. Also see
+        // <https://github.com/rust-lang/rust/pull/103569#discussion_r1008741742>.
+        if env::var_os("BOOTSTRAP_SKIP_TARGET_SANITY").is_some() {
+            continue;
+        }
+
         if need_cmake && target.contains("msvc") {
             // There are three builds of cmake on windows: MSVC, MinGW, and
             // Cygwin. The Cygwin build does not have generators for Visual
index eb7da1bda73cb19d98fde4ca406a28883acb9a29..04480277fe0474cb8b3dd97993d8f4bdaf1162e0 100644 (file)
@@ -82,7 +82,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 }
 
 pub fn setup(config: &Config, profile: Profile) {
-    let path = &config.config;
+    let path = &config.config.clone().unwrap_or(PathBuf::from("config.toml"));
 
     if path.exists() {
         eprintln!(
index d999b6c150333617352b7995fd2c16b1420ed236..fc850a22b2f6fb689904765165bcb344c4cccdb7 100644 (file)
@@ -298,7 +298,7 @@ fn non_bare_args(&self, cmd: &mut Command) {
     fn run(self, build_cli: impl FnOnce(&Tarball<'a>, &mut Command)) -> GeneratedTarball {
         t!(std::fs::create_dir_all(&self.overlay_dir));
         self.builder.create(&self.overlay_dir.join("version"), &self.overlay.version(self.builder));
-        if let Some(info) = self.builder.rust_info.info() {
+        if let Some(info) = self.builder.rust_info().info() {
             channel::write_commit_hash_file(&self.overlay_dir, &info.sha);
             channel::write_commit_info_file(&self.overlay_dir, info);
         }
@@ -323,7 +323,7 @@ fn run(self, build_cli: impl FnOnce(&Tarball<'a>, &mut Command)) -> GeneratedTar
         // Ensure there are no symbolic links in the tarball. In particular,
         // rustup-toolchain-install-master and most versions of Windows can't handle symbolic links.
         let decompressed_output = self.temp_dir.join(&package_name);
-        if !self.builder.config.dry_run && !self.permit_symlinks {
+        if !self.builder.config.dry_run() && !self.permit_symlinks {
             for entry in walkdir::WalkDir::new(&decompressed_output) {
                 let entry = t!(entry);
                 if entry.path_is_symlink() {
index 931d9a67944df704163193c9eb214f0bbdae1f55..fd362b8367cc00c4ebd920079dcb7956655315a6 100644 (file)
@@ -465,49 +465,20 @@ pub struct Miri {
     target: TargetSelection,
 }
 
-impl Step for Miri {
-    type Output = ();
-    const ONLY_HOSTS: bool = false;
-
-    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.path("src/tools/miri")
-    }
-
-    fn make_run(run: RunConfig<'_>) {
-        run.builder.ensure(Miri {
-            stage: run.builder.top_stage,
-            host: run.build_triple(),
-            target: run.target,
-        });
-    }
-
-    /// Runs `cargo test` for miri.
-    fn run(self, builder: &Builder<'_>) {
-        let stage = self.stage;
-        let host = self.host;
-        let target = self.target;
-        let compiler = builder.compiler(stage, host);
-        // We need the stdlib for the *next* stage, as it was built with this compiler that also built Miri.
-        // Except if we are at stage 2, the bootstrap loop is complete and we can stick with our current stage.
-        let compiler_std = builder.compiler(if stage < 2 { stage + 1 } else { stage }, host);
-
-        let miri = builder
-            .ensure(tool::Miri { compiler, target: self.host, extra_features: Vec::new() })
-            .expect("in-tree tool");
-        let _cargo_miri = builder
-            .ensure(tool::CargoMiri { compiler, target: self.host, extra_features: Vec::new() })
-            .expect("in-tree tool");
-        // The stdlib we need might be at a different stage. And just asking for the
-        // sysroot does not seem to populate it, so we do that first.
-        builder.ensure(compile::Std::new(compiler_std, host));
-        let sysroot = builder.sysroot(compiler_std);
-
-        // # Run `cargo miri setup` for the given target.
+impl Miri {
+    /// Run `cargo miri setup` for the given target, return where the Miri sysroot was put.
+    pub fn build_miri_sysroot(
+        builder: &Builder<'_>,
+        compiler: Compiler,
+        miri: &Path,
+        target: TargetSelection,
+    ) -> String {
+        let miri_sysroot = builder.out.join(compiler.host.triple).join("miri-sysrot");
         let mut cargo = tool::prepare_tool_cargo(
             builder,
             compiler,
             Mode::ToolRustc,
-            host,
+            compiler.host,
             "run",
             "src/tools/miri/cargo-miri",
             SourceType::InTree,
@@ -521,6 +492,8 @@ fn run(self, builder: &Builder<'_>) {
         cargo.env("MIRI_LIB_SRC", builder.src.join("library"));
         // Tell it where to find Miri.
         cargo.env("MIRI", &miri);
+        // Tell it where to put the sysroot.
+        cargo.env("MIRI_SYSROOT", &miri_sysroot);
         // Debug things.
         cargo.env("RUST_BACKTRACE", "1");
 
@@ -535,7 +508,7 @@ fn run(self, builder: &Builder<'_>) {
         cargo.arg("--print-sysroot");
 
         // FIXME: Is there a way in which we can re-use the usual `run` helpers?
-        let miri_sysroot = if builder.config.dry_run {
+        if builder.config.dry_run() {
             String::new()
         } else {
             builder.verbose(&format!("running: {:?}", cargo));
@@ -548,7 +521,48 @@ fn run(self, builder: &Builder<'_>) {
             let sysroot = stdout.trim_end();
             builder.verbose(&format!("`cargo miri setup --print-sysroot` said: {:?}", sysroot));
             sysroot.to_owned()
-        };
+        }
+    }
+}
+
+impl Step for Miri {
+    type Output = ();
+    const ONLY_HOSTS: bool = false;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.path("src/tools/miri")
+    }
+
+    fn make_run(run: RunConfig<'_>) {
+        run.builder.ensure(Miri {
+            stage: run.builder.top_stage,
+            host: run.build_triple(),
+            target: run.target,
+        });
+    }
+
+    /// Runs `cargo test` for miri.
+    fn run(self, builder: &Builder<'_>) {
+        let stage = self.stage;
+        let host = self.host;
+        let target = self.target;
+        let compiler = builder.compiler(stage, host);
+        // We need the stdlib for the *next* stage, as it was built with this compiler that also built Miri.
+        // Except if we are at stage 2, the bootstrap loop is complete and we can stick with our current stage.
+        let compiler_std = builder.compiler(if stage < 2 { stage + 1 } else { stage }, host);
+
+        let miri = builder
+            .ensure(tool::Miri { compiler, target: self.host, extra_features: Vec::new() })
+            .expect("in-tree tool");
+        let _cargo_miri = builder
+            .ensure(tool::CargoMiri { compiler, target: self.host, extra_features: Vec::new() })
+            .expect("in-tree tool");
+        // The stdlib we need might be at a different stage. And just asking for the
+        // sysroot does not seem to populate it, so we do that first.
+        builder.ensure(compile::Std::new(compiler_std, host));
+        let sysroot = builder.sysroot(compiler_std);
+        // We also need a Miri sysroot.
+        let miri_sysroot = Miri::build_miri_sysroot(builder, compiler, &miri, target);
 
         // # Run `cargo test`.
         let mut cargo = tool::prepare_tool_cargo(
@@ -566,7 +580,6 @@ fn run(self, builder: &Builder<'_>) {
         // miri tests need to know about the stage sysroot
         cargo.env("MIRI_SYSROOT", &miri_sysroot);
         cargo.env("MIRI_HOST_SYSROOT", sysroot);
-        cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler));
         cargo.env("MIRI", &miri);
         // propagate --bless
         if builder.config.cmd.bless() {
@@ -607,7 +620,6 @@ fn run(self, builder: &Builder<'_>) {
         // Tell `cargo miri` where to find things.
         cargo.env("MIRI_SYSROOT", &miri_sysroot);
         cargo.env("MIRI_HOST_SYSROOT", sysroot);
-        cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler));
         cargo.env("MIRI", &miri);
         // Debug things.
         cargo.env("RUST_BACKTRACE", "1");
@@ -1525,7 +1537,7 @@ fn run(self, builder: &Builder<'_>) {
         let mut copts_passed = false;
         if builder.config.llvm_enabled() {
             let llvm_config = builder.ensure(native::Llvm { target: builder.config.build });
-            if !builder.config.dry_run {
+            if !builder.config.dry_run() {
                 let llvm_version = output(Command::new(&llvm_config).arg("--version"));
                 let llvm_components = output(Command::new(&llvm_config).arg("--components"));
                 // Remove trailing newline from llvm-config output.
@@ -1543,14 +1555,14 @@ fn run(self, builder: &Builder<'_>) {
             // requirement, but the `-L` library path is not propagated across
             // separate compilations. We can add LLVM's library path to the
             // platform-specific environment variable as a workaround.
-            if !builder.config.dry_run && suite.ends_with("fulldeps") {
+            if !builder.config.dry_run() && suite.ends_with("fulldeps") {
                 let llvm_libdir = output(Command::new(&llvm_config).arg("--libdir"));
                 add_link_lib_path(vec![llvm_libdir.trim().into()], &mut cmd);
             }
 
             // Only pass correct values for these flags for the `run-make` suite as it
             // requires that a C++ compiler was configured which isn't always the case.
-            if !builder.config.dry_run && matches!(suite, "run-make" | "run-make-fulldeps") {
+            if !builder.config.dry_run() && matches!(suite, "run-make" | "run-make-fulldeps") {
                 // The llvm/bin directory contains many useful cross-platform
                 // tools. Pass the path to run-make tests so they can use them.
                 let llvm_bin_path = llvm_config
@@ -1578,7 +1590,7 @@ fn run(self, builder: &Builder<'_>) {
 
         // Only pass correct values for these flags for the `run-make` suite as it
         // requires that a C++ compiler was configured which isn't always the case.
-        if !builder.config.dry_run && matches!(suite, "run-make" | "run-make-fulldeps") {
+        if !builder.config.dry_run() && matches!(suite, "run-make" | "run-make-fulldeps") {
             cmd.arg("--cc")
                 .arg(builder.cc(target))
                 .arg("--cxx")
index d395220694705e7c6c6c586df1bbdc98c88936ac..ba329ea6c759286e37140469dded952b5dcf2850 100644 (file)
@@ -522,7 +522,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
         builder.ensure(compile::Rustc::new(build_compiler, target_compiler.host));
         // NOTE: this implies that `download-rustc` is pretty useless when compiling with the stage0
         // compiler, since you do just as much work.
-        if !builder.config.dry_run && builder.download_rustc() && build_compiler.stage == 0 {
+        if !builder.config.dry_run() && builder.download_rustc() && build_compiler.stage == 0 {
             println!(
                 "warning: `download-rustc` does nothing when building stage1 tools; consider using `--stage 2` instead"
             );
index 1a17744322753f7a431b10b427568c4cf28653b8..1969e0b6f87223021e89915e8fe9d6718d251524 100644 (file)
@@ -158,7 +158,7 @@ impl Step for ToolStateCheck {
     ///   stable tool. That is, the status is not allowed to get worse
     ///   (test-pass to test-fail or build-fail).
     fn run(self, builder: &Builder<'_>) {
-        if builder.config.dry_run {
+        if builder.config.dry_run() {
             return;
         }
 
@@ -265,7 +265,7 @@ pub fn save_toolstate(&self, tool: &str, state: ToolState) {
         // If we're in a dry run setting we don't want to save toolstates as
         // that means if we e.g. panic down the line it'll look like we tested
         // everything (but we actually haven't).
-        if self.config.dry_run {
+        if self.config.dry_run() {
             return;
         }
         // Toolstate isn't tracked for clippy or rustfmt, but since most tools do, we avoid checking
index 20c3801f0a50222cbcc792f98a2786a993d7b5c6..58220783228b2883fae9ba5ca03d646048e41964 100644 (file)
@@ -44,7 +44,13 @@ macro_rules! t {
 /// Given an executable called `name`, return the filename for the
 /// executable for a particular target.
 pub fn exe(name: &str, target: TargetSelection) -> String {
-    if target.contains("windows") { format!("{}.exe", name) } else { name.to_string() }
+    if target.contains("windows") {
+        format!("{}.exe", name)
+    } else if target.contains("uefi") {
+        format!("{}.efi", name)
+    } else {
+        name.to_string()
+    }
 }
 
 /// Returns `true` if the file name given looks like a dynamic library.
@@ -105,7 +111,7 @@ fn link_lib_path() -> Vec<PathBuf> {
 
 /// Returns an RAII structure that prints out how long it took to drop.
 pub fn timeit(builder: &Builder<'_>) -> TimeIt {
-    TimeIt(builder.config.dry_run, Instant::now())
+    TimeIt(builder.config.dry_run(), Instant::now())
 }
 
 impl Drop for TimeIt {
@@ -128,7 +134,7 @@ pub(crate) fn program_out_of_date(stamp: &Path, key: &str) -> bool {
 /// Symlinks two directories, using junctions on Windows and normal symlinks on
 /// Unix.
 pub fn symlink_dir(config: &Config, src: &Path, dest: &Path) -> io::Result<()> {
-    if config.dry_run {
+    if config.dry_run() {
         return Ok(());
     }
     let _ = fs::remove_dir(dest);
index 7d77fdd30d1d8ca6c340801c836053540544a696..43a449b3a1926baa307e1908dbdd1a6a1c2260c8 100644 (file)
@@ -28,5 +28,5 @@ ENV \
 
 ENV HOSTS=s390x-unknown-linux-gnu
 
-ENV RUST_CONFIGURE_ARGS --enable-extended --enable-lld --disable-docs
+ENV RUST_CONFIGURE_ARGS --enable-extended --enable-lld --enable-profiler --disable-docs
 ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS
index 126c292b38ea1f7a179b5ddaea5762ddc648a715..e1adabaac9b568b32723e98201603bc30187ff47 100644 (file)
@@ -118,6 +118,9 @@ ENV TARGETS=$TARGETS,armv7-unknown-linux-gnueabi
 ENV TARGETS=$TARGETS,armv7-unknown-linux-musleabi
 ENV TARGETS=$TARGETS,i686-unknown-freebsd
 ENV TARGETS=$TARGETS,x86_64-unknown-none
+ENV TARGETS=$TARGETS,aarch64-unknown-uefi
+ENV TARGETS=$TARGETS,i686-unknown-uefi
+ENV TARGETS=$TARGETS,x86_64-unknown-uefi
 
 # As per https://bugs.launchpad.net/ubuntu/+source/gcc-defaults/+bug/1300211
 # we need asm in the search path for gcc-8 (for gnux32) but not in the search path of the
index fed4be4c30a74163893253a0f5f72d3e19d801b4..d03c364547e034cbdbd21b8594a98c5b4c1ce298 100644 (file)
@@ -1,7 +1,8 @@
-FROM ubuntu:16.04
+FROM ubuntu:20.04
 
 COPY scripts/cross-apt-packages.sh /scripts/
 RUN sh /scripts/cross-apt-packages.sh
+RUN DEBIAN_FRONTEND=noninteractive apt-get install -y zlib1g-dev
 
 COPY host-x86_64/dist-x86_64-netbsd/build-netbsd-toolchain.sh /tmp/
 RUN /tmp/build-netbsd-toolchain.sh
@@ -9,9 +10,6 @@ RUN /tmp/build-netbsd-toolchain.sh
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
-
 ENV PATH=$PATH:/x-tools/x86_64-unknown-netbsd/bin
 
 ENV \
@@ -21,6 +19,5 @@ ENV \
 
 ENV HOSTS=x86_64-unknown-netbsd
 
-ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs \
-    --set llvm.allow-old-toolchain
+ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
 ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS
index 5dfa47b4eed74e74c8070dc18246b3ded92fea39..e0c008b76fa8bb39744460c79d8cc50751880edb 100755 (executable)
@@ -25,19 +25,19 @@ cd netbsd
 
 mkdir -p /x-tools/x86_64-unknown-netbsd/sysroot
 
-URL=https://ci-mirrors.rust-lang.org/rustc
-
-# Originally from ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-$BSD/source/sets/*.tgz
-curl $URL/2018-03-01-netbsd-src.tgz | tar xzf -
-curl $URL/2018-03-01-netbsd-gnusrc.tgz | tar xzf -
-curl $URL/2018-03-01-netbsd-sharesrc.tgz | tar xzf -
-curl $URL/2018-03-01-netbsd-syssrc.tgz | tar xzf -
-
-# Originally from ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-$BSD/amd64/binary/sets/*.tgz
-curl $URL/2018-03-01-netbsd-base.tgz | \
-  tar xzf - -C /x-tools/x86_64-unknown-netbsd/sysroot ./usr/include ./usr/lib ./lib
-curl $URL/2018-03-01-netbsd-comp.tgz | \
-  tar xzf - -C /x-tools/x86_64-unknown-netbsd/sysroot ./usr/include ./usr/lib
+URL=https://ci-mirrors.rust-lang.org/rustc
+
+SOURCE_URL=https://cdn.netbsd.org/pub/NetBSD/NetBSD-9.0/source/sets
+curl $SOURCE_URL/src.tgz | tar xzf -
+curl $SOURCE_URL/gnusrc.tgz | tar xzf -
+curl $SOURCE_URL/sharesrc.tgz | tar xzf -
+curl $SOURCE_URL/syssrc.tgz | tar xzf -
+
+BINARY_URL=https://cdn.netbsd.org/pub/NetBSD/NetBSD-9.0/amd64/binary/sets
+curl $BINARY_URL/base.tar.xz | \
+  tar xJf - -C /x-tools/x86_64-unknown-netbsd/sysroot ./usr/include ./usr/lib ./lib
+curl $BINARY_URL/comp.tar.xz | \
+  tar xJf - -C /x-tools/x86_64-unknown-netbsd/sysroot ./usr/include ./usr/lib
 
 cd usr/src
 
index cc96715b28572f89ccff9ea637c1fa51124e6a68..ed0d9e9902b995528b86b686a9d445ac07bf4a27 100644 (file)
@@ -1 +1 @@
-0.12.7
\ No newline at end of file
+0.13.1
\ No newline at end of file
index d87384556106ddb65c09151f6753bf61bc62a67c..7dde6370904bb91f4613ae12b33eea6885c4fffa 100755 (executable)
@@ -27,10 +27,7 @@ python3 "$X_PY" test --stage 2 src/tools/rustfmt
 python3 "$X_PY" test --stage 2 src/tools/miri
 # We natively run this script on x86_64-unknown-linux-gnu and x86_64-pc-windows-msvc.
 # Also cover some other targets (on both of these hosts) via cross-testing.
-#
-# Currently disabled -- we end up pulling in a cross-compile of LLVM (maybe
-# just overly eager sanity checks), but in any case this won't work when
-# building LLVM as of this comment.
-#python3 "$X_PY" test --stage 2 src/tools/miri --target i686-pc-windows-msvc
-#FIXME(https://github.com/rust-lang/rust/issues/103519): macOS testing is currently disabled
-# python3 "$X_PY" test --stage 2 src/tools/miri --target aarch64-apple-darwin
+export BOOTSTRAP_SKIP_TARGET_SANITY=1 # we don't need `cc` for these targets
+python3 "$X_PY" test --stage 2 src/tools/miri --target i686-pc-windows-msvc
+python3 "$X_PY" test --stage 2 src/tools/miri --target aarch64-apple-darwin
+unset BOOTSTRAP_SKIP_TARGET_SANITY
index 9a247fb60a8ee0535c20ecc4d5ab0f4e135c8ab4..7de06ec35c36bba75da44543d567f7603835341b 100755 (executable)
@@ -123,6 +123,10 @@ else
   # (And PGO is its own can of worms).
   if [ "$NO_DOWNLOAD_CI_LLVM" = "" ]; then
     RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set llvm.download-ci-llvm=if-available"
+  else
+    # When building for CI we want to use the static C++ Standard library
+    # included with LLVM, since a dynamic libstdcpp may not be available.
+    RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set llvm.static-libstdcpp"
   fi
 fi
 
index aa5ee485bd6bd80d205da7c82fcdd776f92fdd51..3f64052c048c6def93b94a2b514ee88bba918744 160000 (submodule)
@@ -1 +1 @@
-Subproject commit aa5ee485bd6bd80d205da7c82fcdd776f92fdd51
+Subproject commit 3f64052c048c6def93b94a2b514ee88bba918744
index 9c73283775466d22208a0b28afcab44db4c0cc10..05532356e7a4dbea2330aabb77611f5179493bb8 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 9c73283775466d22208a0b28afcab44db4c0cc10
+Subproject commit 05532356e7a4dbea2330aabb77611f5179493bb8
index 4ea7c5def38ac81df33a9e48e5637a82a5ac404d..9f0cc13ffcd27c1fbe1ab766a9491e15ddcf4d19 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 4ea7c5def38ac81df33a9e48e5637a82a5ac404d
+Subproject commit 9f0cc13ffcd27c1fbe1ab766a9491e15ddcf4d19
index 03491f33375c5a2a1661c7fa4be671fe95ce1249..2b15c0abf2bada6e00553814336bc3e2d8399097 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 03491f33375c5a2a1661c7fa4be671fe95ce1249
+Subproject commit 2b15c0abf2bada6e00553814336bc3e2d8399097
index 51a37ad19a15709d0601afbac6581f5aea6a45da..d0dc6c97a6486f68bac782fff135086eae6d77ec 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 51a37ad19a15709d0601afbac6581f5aea6a45da
+Subproject commit d0dc6c97a6486f68bac782fff135086eae6d77ec
index 86bb2c0d3816ae2c94b3fb4ba11f299cdcae8c2c..2d3b830946145825c91580157c78e7de62c3fa95 100644 (file)
@@ -33,6 +33,7 @@
     - [nvptx64-nvidia-cuda](platform-support/nvptx64-nvidia-cuda.md)
     - [riscv32imac-unknown-xous-elf](platform-support/riscv32imac-unknown-xous-elf.md)
     - [*-pc-windows-gnullvm](platform-support/pc-windows-gnullvm.md)
+    - [\*-nto-qnx-\*](platform-support/nto-qnx.md)
     - [*-unknown-openbsd](platform-support/openbsd.md)
     - [\*-unknown-uefi](platform-support/unknown-uefi.md)
     - [wasm64-unknown-unknown](platform-support/wasm64-unknown-unknown.md)
index b1854b22a7cd694b92476d87ff9854dd547d7b96..9272b9ac9b2d45be95b2278b97dc36b0b5c00446 100644 (file)
@@ -131,24 +131,47 @@ able to get around this problem by setting `-Clinker=lld-link` in RUSTFLAGS
 
 ## Toolchain Compatibility
 
-<!-- NOTE: to update the below table, you can use this shell script:
-
-```sh
-rustup toolchain install --profile minimal nightly
-MINOR_VERSION=$(rustc +nightly --version | cut -d . -f 2)
-LOWER_BOUND=61
-
-llvm_version() {
-    toolchain="$1"
-    printf "Rust $toolchain    |    Clang "
-    rustc +"$toolchain" -Vv | grep LLVM | cut -d ':' -f 2 | tr -d ' '
-}
-
-for version in `seq $LOWER_BOUND $((MINOR_VERSION - 2))`; do
-    toolchain=1.$version.0
-    rustup toolchain install --no-self-update --profile  minimal $toolchain >/dev/null 2>&1
-    llvm_version $toolchain
-done
+<!-- NOTE: to update the below table, you can use this Python script:
+
+```python
+from collections import defaultdict
+import subprocess
+
+def minor_version(version):
+    return int(version.split('.')[1])
+
+INSTALL_TOOLCHAIN = ["rustup", "toolchain", "install", "--profile", "minimal"]
+subprocess.run(INSTALL_TOOLCHAIN + ["nightly"])
+
+LOWER_BOUND = 65
+NIGHTLY_VERSION = minor_version(subprocess.run(
+    ["rustc", "+nightly", "--version"],
+    capture_output=True,
+    text=True).stdout)
+
+def llvm_version(toolchain):
+    version_text = subprocess.run(
+        ["rustc", "+{}".format(toolchain), "-Vv"],
+        capture_output=True,
+        text=True).stdout
+    return int(version_text.split("LLVM")[1].split(':')[1].split('.')[0])
+
+version_map = defaultdict(lambda: [])
+for version in range(LOWER_BOUND, NIGHTLY_VERSION - 1):
+    toolchain = "1.{}.0".format(version)
+    subprocess.run(
+        INSTALL_TOOLCHAIN + ["--no-self-update", toolchain],
+        capture_output=True)
+    version_map[llvm_version(toolchain)].append(version)
+
+print("| Rust Version | Clang Version |")
+print("|--------------|---------------|")
+for clang, rust in sorted(version_map.items()):
+    if len(rust) > 1:
+        rust_range = "1.{} - 1.{}".format(rust[0], rust[-1])
+    else:
+        rust_range = "1.{}       ".format(rust[0])
+    print("| {}  |      {}       |".format(rust_range, clang))
 ```
 
 -->
@@ -166,32 +189,13 @@ The following table shows known good combinations of toolchain versions.
 
 | Rust Version | Clang Version |
 |--------------|---------------|
-| Rust 1.34    |    Clang 8    |
-| Rust 1.35    |    Clang 8    |
-| Rust 1.36    |    Clang 8    |
-| Rust 1.37    |    Clang 8    |
-| Rust 1.38    |    Clang 9    |
-| Rust 1.39    |    Clang 9    |
-| Rust 1.40    |    Clang 9    |
-| Rust 1.41    |    Clang 9    |
-| Rust 1.42    |    Clang 9    |
-| Rust 1.43    |    Clang 9    |
-| Rust 1.44    |    Clang 9    |
-| Rust 1.45    |    Clang 10   |
-| Rust 1.46    |    Clang 10   |
-| Rust 1.47    |    Clang 11   |
-| Rust 1.48    |    Clang 11   |
-| Rust 1.49    |    Clang 11   |
-| Rust 1.50    |    Clang 11   |
-| Rust 1.51    |    Clang 11   |
-| Rust 1.52    |    Clang 12   |
-| Rust 1.53    |    Clang 12   |
-| Rust 1.54    |    Clang 12   |
-| Rust 1.55    |    Clang 12   |
-| Rust 1.56    |    Clang 13   |
-| Rust 1.57    |    Clang 13   |
-| Rust 1.58    |    Clang 13   |
-| Rust 1.59    |    Clang 13   |
-| Rust 1.60    |    Clang 14   |
+| 1.34 - 1.37  |       8       |
+| 1.38 - 1.44  |       9       |
+| 1.45 - 1.46  |      10       |
+| 1.47 - 1.51  |      11       |
+| 1.52 - 1.55  |      12       |
+| 1.56 - 1.59  |      13       |
+| 1.60 - 1.64  |      14       |
+| 1.65         |      15       |
 
 Note that the compatibility policy for this feature might change in the future.
index 3ae9872cf62d4e8304d7b34d1bbe63fffa347194..28929acb9b48dd667ef0c937c30013cf16d1b227 100644 (file)
@@ -128,6 +128,7 @@ target | std | notes
 [`aarch64-linux-android`](platform-support/android.md) | ✓ | ARM64 Android
 `aarch64-unknown-none-softfloat` | * | Bare ARM64, softfloat
 `aarch64-unknown-none` | * | Bare ARM64, hardfloat
+[`aarch64-unknown-uefi`](platform-support/unknown-uefi.md) | * | ARM64 UEFI
 [`arm-linux-androideabi`](platform-support/android.md) | ✓ | ARMv7 Android
 `arm-unknown-linux-musleabi` | ✓ | ARMv6 Linux with MUSL
 `arm-unknown-linux-musleabihf` | ✓ | ARMv6 Linux with MUSL, hardfloat
@@ -149,6 +150,7 @@ target | std | notes
 [`i686-linux-android`](platform-support/android.md) | ✓ | 32-bit x86 Android
 `i686-unknown-freebsd` | ✓ | 32-bit FreeBSD
 `i686-unknown-linux-musl` | ✓ | 32-bit Linux with MUSL
+[`i686-unknown-uefi`](platform-support/unknown-uefi.md) | * | 32-bit UEFI
 `mips-unknown-linux-musl` | ✓ | MIPS Linux with MUSL
 `mips64-unknown-linux-muslabi64` | ✓ | MIPS64 Linux, n64 ABI, MUSL
 `mips64el-unknown-linux-muslabi64` | ✓ | MIPS64 (LE) Linux, n64 ABI, MUSL
@@ -181,6 +183,7 @@ target | std | notes
 `x86_64-unknown-linux-gnux32` | ✓ | 64-bit Linux (x32 ABI) (kernel 4.15, glibc 2.27)
 [`x86_64-unknown-none`](platform-support/x86_64-unknown-none.md) | * | Freestanding/bare-metal x86_64, softfloat
 `x86_64-unknown-redox` | ✓ | Redox OS
+[`x86_64-unknown-uefi`](platform-support/unknown-uefi.md) | * | 64-bit UEFI
 
 [Fortanix ABI]: https://edp.fortanix.com/
 
@@ -211,9 +214,9 @@ target | std | host | notes
 [`aarch64-kmc-solid_asp3`](platform-support/kmc-solid.md) | ✓ |  | ARM64 SOLID with TOPPERS/ASP3
 [`aarch64-nintendo-switch-freestanding`](platform-support/aarch64-nintendo-switch-freestanding.md) | * |  | ARM64 Nintendo Switch, Horizon
 [`aarch64-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | ✓ |
+[`aarch64-unknown-nto-qnx7.1.0`](platform-support/nto-qnx.md) | ? |  | ARM64 QNX Neutrino 7.1 RTOS |
 `aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD
 `aarch64-unknown-hermit` | ✓ |  | ARM64 HermitCore
-[`aarch64-unknown-uefi`](platform-support/unknown-uefi.md) | * |  | ARM64 UEFI
 `aarch64-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (ILP32 ABI)
 `aarch64-unknown-netbsd` | ✓ | ✓ |
 [`aarch64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | ARM64 OpenBSD
@@ -252,7 +255,6 @@ target | std | host | notes
 `i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku
 `i686-unknown-netbsd` | ✓ | ✓ | NetBSD/i386 with SSE2
 [`i686-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 32-bit OpenBSD
-[`i686-unknown-uefi`](platform-support/unknown-uefi.md) | * |  | 32-bit UEFI
 `i686-uwp-windows-gnu` | ? |  |
 `i686-uwp-windows-msvc` | ? |  |
 `i686-wrs-vxworks` | ? |  |
@@ -302,6 +304,7 @@ target | std | host | notes
 `x86_64-apple-ios-macabi` | ✓ |  | Apple Catalyst on x86_64
 `x86_64-apple-tvos` | * | | x86 64-bit tvOS
 [`x86_64-apple-watchos-sim`](platform-support/apple-watchos.md) | ✓ | | x86 64-bit Apple WatchOS simulator
+[`x86_64-pc-nto-qnx7.1.0`](platform-support/nto-qnx.md) | ? |  | x86 64-bit QNX Neutrino 7.1 RTOS |
 [`x86_64-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | ✓ |
 `x86_64-pc-windows-msvc` | * |  | 64-bit Windows XP support
 `x86_64-sun-solaris` | ? |  | Deprecated target for 64-bit Solaris 10/11, illumos
@@ -309,9 +312,7 @@ target | std | host | notes
 `x86_64-unknown-haiku` | ✓ | ✓ | 64-bit Haiku
 `x86_64-unknown-hermit` | ✓ |  | HermitCore
 `x86_64-unknown-l4re-uclibc` | ? |  |
-`x86_64-unknown-none-linuxkernel` | * |  | Linux kernel modules
 [`x86_64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 64-bit OpenBSD
-[`x86_64-unknown-uefi`](platform-support/unknown-uefi.md) | * |  | 64-bit UEFI
 `x86_64-uwp-windows-gnu` | ✓ |  |
 `x86_64-uwp-windows-msvc` | ✓ |  |
 `x86_64-wrs-vxworks` | ? |  |
diff --git a/src/doc/rustc/src/platform-support/nto-qnx.md b/src/doc/rustc/src/platform-support/nto-qnx.md
new file mode 100644 (file)
index 0000000..2f6ea94
--- /dev/null
@@ -0,0 +1,118 @@
+# nto-qnx
+
+**Tier: 3**
+
+[BlackBerry® QNX®][BlackBerry] Neutrino (nto) Real-time operating system.
+The support has been implemented jointly by [Elektrobit Automotive GmbH][Elektrobit]
+and [BlackBerry][BlackBerry].
+
+[BlackBerry]: https://blackberry.qnx.com
+[Elektrobit]: https://www.elektrobit.com
+
+## Target maintainers
+
+- Florian Bartels, `Florian.Bartels@elektrobit.com`, https://github.com/flba-eb
+- Tristan Roach, `TRoach@blackberry.com`, https://github.com/gh-tr
+
+## Requirements
+
+Currently, only cross-compilation for QNX Neutrino on AArch64 and x86_64 are supported (little endian).
+Adding other architectures that are supported by QNX Neutrino is possible.
+
+The standard library does not yet support QNX Neutrino. Therefore, only `no_std` code can
+be compiled.
+
+`core` and `alloc` (with default allocator) are supported.
+
+Applications must link against `libc.so` (see example). This is required because applications
+always link against the `crt` library and `crt` depends on `libc.so`.
+
+The correct version of `qcc` must be available by setting the `$PATH` variable (e.g. by sourcing `qnxsdp-env.sh` of the
+QNX Neutrino toolchain).
+
+### Small example application
+
+```rust,ignore (platform-specific)
+#![no_std]
+#![no_main]
+#![feature(lang_items)]
+
+// We must always link against libc, even if no external functions are used
+// "extern C" - Block can be empty but must be present
+#[link(name = "c")]
+extern "C" {
+    pub fn printf(format: *const core::ffi::c_char, ...) -> core::ffi::c_int;
+}
+
+#[no_mangle]
+pub extern "C" fn main(_argc: isize, _argv: *const *const u8) -> isize {
+    const HELLO: &'static str = "Hello World, the answer is %d\n\0";
+    unsafe {
+        printf(HELLO.as_ptr() as *const _, 42);
+    }
+    0
+}
+
+use core::panic::PanicInfo;
+
+#[panic_handler]
+fn panic(_panic: &PanicInfo<'_>) -> ! {
+    loop {}
+}
+
+#[lang = "eh_personality"]
+#[no_mangle]
+pub extern "C" fn rust_eh_personality() {}
+```
+
+The QNX Neutrino support of Rust has been tested with QNX Neutrino 7.1.
+
+There are no further known requirements.
+
+## Conditional compilation
+
+For conditional compilation, following QNX Neutrino specific attributes are defined:
+
+- `target_os` = `"nto"`
+- `target_env` = `"nto71"` (for QNX Neutrino 7.1)
+
+## Building the target
+
+1. Create a `config.toml`
+
+Example content:
+
+```toml
+profile = "compiler"
+changelog-seen = 2
+```
+
+2. Compile the Rust toolchain for an `x86_64-unknown-linux-gnu` host (for both `aarch64` and `x86_64` targets)
+
+Run the following:
+
+```bash
+env \
+    CC_aarch64-unknown-nto-qnx7.1.0="qcc" \
+    CFLAGS_aarch64-unknown-nto-qnx7.1.0="-Vgcc_ntoaarch64le_cxx" \
+    CXX_aarch64-unknown-nto-qnx7.1.0="qcc" \
+    AR_aarch64_unknown_nto_qnx7.1.0="ntoaarch64-ar" \
+    CC_x86_64-pc-nto-qnx7.1.0="qcc" \
+    CFLAGS_x86_64-pc-nto-qnx7.1.0="-Vgcc_ntox86_64_cxx" \
+    CXX_x86_64-pc-nto-qnx7.1.0="qcc" \
+    AR_x86_64_pc_nto_qnx7.1.0="ntox86_64-ar" \
+        ./x.py build --target aarch64-unknown-nto-qnx7.1.0 --target x86_64-pc-nto-qnx7.1.0 --target x86_64-unknown-linux-gnu rustc library/core library/alloc/
+```
+
+## Building Rust programs
+
+Rust does not yet ship pre-compiled artifacts for this target. To compile for this target, you must either build Rust with the target enabled (see "Building the target" above), or build your own copy of  `core` by using
+`build-std` or similar.
+
+## Testing
+
+Compiled executables can directly be run on QNX Neutrino.
+
+## Cross-compilation toolchains and C code
+
+Compiling C code requires the same environment variables to be set as compiling the Rust toolchain (see above), to ensure `qcc` is used with proper arguments. To ensure compatibility, do not specify any further arguments that for example change calling conventions or memory layout.
index 295dec0f0e488aeee419db6e29e380c5d534fb42..e2bdf73a92990cc4879e44ad7cb3ab6118c8adf3 100644 (file)
@@ -1,6 +1,6 @@
 # `*-unknown-uefi`
 
-**Tier: 3**
+**Tier: 2**
 
 Unified Extensible Firmware Interface (UEFI) targets for application, driver,
 and core UEFI binaries.
@@ -72,28 +72,14 @@ target = ["x86_64-unknown-uefi"]
 
 ## Building Rust programs
 
-Rust does not yet ship pre-compiled artifacts for this target. To compile for
-this target, you will either need to build Rust with the target enabled (see
-"Building rust for UEFI targets" above), or build your own copy of `core` by
-using `build-std`, `cargo-buildx`, or similar.
-
-A native build with the unstable `build-std`-feature can be achieved via:
-
-```sh
-cargo +nightly build \
-    -Zbuild-std=core,compiler_builtins \
-    -Zbuild-std-features=compiler-builtins-mem \
-    --target x86_64-unknown-uefi
-```
-
-Alternatively, you can install `cargo-xbuild` via
-`cargo install --force cargo-xbuild` and build for the UEFI targets via:
+Starting with Rust 1.67, precompiled artifacts are provided via
+`rustup`. For example, to use `x86_64-unknown-uefi`:
 
 ```sh
-cargo \
-    +nightly \
-    xbuild \
-    --target x86_64-unknown-uefi
+# install cross-compile toolchain
+rustup target add x86_64-unknown-uefi
+# target flag may be used with any cargo or rustc command
+cargo build --target x86_64-unknown-uefi
 ```
 
 ## Testing
@@ -167,18 +153,10 @@ The following code is a valid UEFI application returning immediately upon
 execution with an exit code of 0. A panic handler is provided. This is executed
 by rust on panic. For simplicity, we simply end up in an infinite loop.
 
-Note that as of rust-1.31.0, all features used here are stabilized. No unstable
-features are required, nor do we rely on nightly compilers. However, if you do
-not compile rustc for the UEFI targets, you need a nightly compiler to support
-the `-Z build-std` flag.
-
 This example can be compiled as binary crate via `cargo`:
 
 ```sh
-cargo +nightly build \
-    -Zbuild-std=core,compiler_builtins \
-    -Zbuild-std-features=compiler-builtins-mem \
-    --target x86_64-unknown-uefi
+cargo build --target x86_64-unknown-uefi
 ```
 
 ```rust,ignore (platform-specific,eh-personality-is-unstable)
index 8a5463c10f210a62f1292e36a37208552f10c8cc..3fc4aae923a60aa2cc0ed8794bb22eccbc89a0e9 100644 (file)
@@ -3,7 +3,7 @@
 use std::iter::once;
 use std::sync::Arc;
 
-use thin_vec::ThinVec;
+use thin_vec::{thin_vec, ThinVec};
 
 use rustc_ast as ast;
 use rustc_data_structures::fx::FxHashSet;
@@ -605,7 +605,7 @@ fn build_module_items(
                         clean::ImportSource {
                             path: clean::Path {
                                 res,
-                                segments: vec![clean::PathSegment {
+                                segments: thin_vec![clean::PathSegment {
                                     name: prim_ty.as_sym(),
                                     args: clean::GenericArgs::AngleBracketed {
                                         args: Default::default(),
index 19276b9b187a03e70bdba8a81c69f79c9c69193b..c2f78fd5950f7148417f6aaba58cdd30210413b5 100644 (file)
@@ -226,7 +226,7 @@ pub(crate) fn clean_middle_const<'tcx>(
     // FIXME: instead of storing the stringified expression, store `self` directly instead.
     Constant {
         type_: clean_middle_ty(constant.ty(), cx, None),
-        kind: ConstantKind::TyConst { expr: constant.to_string() },
+        kind: ConstantKind::TyConst { expr: constant.to_string().into() },
     }
 }
 
@@ -1215,7 +1215,7 @@ fn param_eq_arg(param: &GenericParamDef, arg: &GenericArg) -> bool {
                         true
                     }
                     (GenericParamDefKind::Const { .. }, GenericArg::Const(c)) => match &c.kind {
-                        ConstantKind::TyConst { expr } => expr == param.name.as_str(),
+                        ConstantKind::TyConst { expr } => **expr == *param.name.as_str(),
                         _ => false,
                     },
                     _ => false,
@@ -1554,7 +1554,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
                 }
             };
 
-            Array(Box::new(clean_ty(ty, cx)), length)
+            Array(Box::new(clean_ty(ty, cx)), length.into())
         }
         TyKind::Tup(tys) => Tuple(tys.iter().map(|ty| clean_ty(ty, cx)).collect()),
         TyKind::OpaqueDef(item_id, _, _) => {
@@ -1626,7 +1626,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
         ty::Array(ty, mut n) => {
             n = n.eval(cx.tcx, ty::ParamEnv::reveal_all());
             let n = print_const(cx, n);
-            Array(Box::new(clean_middle_ty(ty, cx, None)), n)
+            Array(Box::new(clean_middle_ty(ty, cx, None)), n.into())
         }
         ty::RawPtr(mt) => RawPointer(mt.mutbl, Box::new(clean_middle_ty(mt.ty, cx, None))),
         ty::Ref(r, ty, mutbl) => BorrowedRef {
@@ -1942,6 +1942,79 @@ fn clean_bare_fn_ty<'tcx>(
     BareFunctionDecl { unsafety: bare_fn.unsafety, abi: bare_fn.abi, decl, generic_params }
 }
 
+/// This visitor is used to go through only the "top level" of a item and not enter any sub
+/// item while looking for a given `Ident` which is stored into `item` if found.
+struct OneLevelVisitor<'hir> {
+    map: rustc_middle::hir::map::Map<'hir>,
+    item: Option<&'hir hir::Item<'hir>>,
+    looking_for: Ident,
+    target_hir_id: hir::HirId,
+}
+
+impl<'hir> OneLevelVisitor<'hir> {
+    fn new(map: rustc_middle::hir::map::Map<'hir>, target_hir_id: hir::HirId) -> Self {
+        Self { map, item: None, looking_for: Ident::empty(), target_hir_id }
+    }
+
+    fn reset(&mut self, looking_for: Ident) {
+        self.looking_for = looking_for;
+        self.item = None;
+    }
+}
+
+impl<'hir> hir::intravisit::Visitor<'hir> for OneLevelVisitor<'hir> {
+    type NestedFilter = rustc_middle::hir::nested_filter::All;
+
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.map
+    }
+
+    fn visit_item(&mut self, item: &'hir hir::Item<'hir>) {
+        if self.item.is_none()
+            && item.ident == self.looking_for
+            && matches!(item.kind, hir::ItemKind::Use(_, _))
+            || item.hir_id() == self.target_hir_id
+        {
+            self.item = Some(item);
+        }
+    }
+}
+
+/// Because a `Use` item directly links to the imported item, we need to manually go through each
+/// import one by one. To do so, we go to the parent item and look for the `Ident` into it. Then,
+/// if we found the "end item" (the imported one), we stop there because we don't need its
+/// documentation. Otherwise, we repeat the same operation until we find the "end item".
+fn get_all_import_attributes<'hir>(
+    mut item: &hir::Item<'hir>,
+    tcx: TyCtxt<'hir>,
+    target_hir_id: hir::HirId,
+    attributes: &mut Vec<ast::Attribute>,
+) {
+    let hir_map = tcx.hir();
+    let mut visitor = OneLevelVisitor::new(hir_map, target_hir_id);
+    // If the item is an import and has at least a path with two parts, we go into it.
+    while let hir::ItemKind::Use(path, _) = item.kind &&
+        path.segments.len() > 1 &&
+        let hir::def::Res::Def(_, def_id) = path.segments[path.segments.len() - 2].res
+    {
+        if let Some(hir::Node::Item(parent_item)) = hir_map.get_if_local(def_id) {
+            // We add the attributes from this import into the list.
+            attributes.extend_from_slice(hir_map.attrs(item.hir_id()));
+            // We get the `Ident` we will be looking for into `item`.
+            let looking_for = path.segments[path.segments.len() - 1].ident;
+            visitor.reset(looking_for);
+            hir::intravisit::walk_item(&mut visitor, parent_item);
+            if let Some(i) = visitor.item {
+                item = i;
+            } else {
+                break;
+            }
+        } else {
+            break;
+        }
+    }
+}
+
 fn clean_maybe_renamed_item<'tcx>(
     cx: &mut DocContext<'tcx>,
     item: &hir::Item<'tcx>,
@@ -2023,13 +2096,20 @@ fn clean_maybe_renamed_item<'tcx>(
             }
             _ => unreachable!("not yet converted"),
         };
-        if let Some(import_id) = import_id {
-            let (attrs, cfg) = inline::merge_attrs(
-                cx,
-                Some(cx.tcx.parent_module(import_id).to_def_id()),
-                inline::load_attrs(cx, def_id),
-                Some(inline::load_attrs(cx, cx.tcx.hir().local_def_id(import_id).to_def_id())),
-            );
+
+        let mut extra_attrs = Vec::new();
+        if let Some(hir::Node::Item(use_node)) =
+            import_id.and_then(|hir_id| cx.tcx.hir().find(hir_id))
+        {
+            // We get all the various imports' attributes.
+            get_all_import_attributes(use_node, cx.tcx, item.hir_id(), &mut extra_attrs);
+        }
+
+        if !extra_attrs.is_empty() {
+            extra_attrs.extend_from_slice(inline::load_attrs(cx, def_id));
+            let attrs = Attributes::from_ast(&extra_attrs);
+            let cfg = extra_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg);
+
             vec![Item::from_def_id_and_attrs_and_parts(
                 def_id,
                 Some(name),
index bbedfdd0eafe09031e5db1a379b62bc8011a0650..3d13f7463cbb09d5428251cf416e01ac1c1c3e3b 100644 (file)
@@ -1625,7 +1625,7 @@ pub(crate) enum Type {
     /// An array type.
     ///
     /// The `String` field is a stringified version of the array's length parameter.
-    Array(Box<Type>, String),
+    Array(Box<Type>, Box<str>),
     /// A raw pointer type: `*const i32`, `*mut i32`
     RawPointer(Mutability, Box<Type>),
     /// A reference type: `&i32`, `&'a mut Foo`
@@ -2210,7 +2210,7 @@ pub(crate) fn cnum(&self, sess: &Session) -> CrateNum {
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
 pub(crate) struct Path {
     pub(crate) res: Res,
-    pub(crate) segments: Vec<PathSegment>,
+    pub(crate) segments: ThinVec<PathSegment>,
 }
 
 impl Path {
@@ -2360,7 +2360,7 @@ pub(crate) enum ConstantKind {
     ///
     /// Note that `ty::Const` includes generic parameters, and may not always be uniquely identified
     /// by a DefId. So this field must be different from `Extern`.
-    TyConst { expr: String },
+    TyConst { expr: Box<str> },
     /// A constant (expression) that's not an item or associated item. These are usually found
     /// nested inside types (e.g., array lengths) or expressions (e.g., repeat counts), and also
     /// used to define explicit discriminant values for enum variants.
@@ -2388,7 +2388,7 @@ pub(crate) fn is_literal(&self, tcx: TyCtxt<'_>) -> bool {
 impl ConstantKind {
     pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> String {
         match *self {
-            ConstantKind::TyConst { ref expr } => expr.clone(),
+            ConstantKind::TyConst { ref expr } => expr.to_string(),
             ConstantKind::Extern { def_id } => print_inlined_const(tcx, def_id),
             ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
                 print_const_expr(tcx, body)
@@ -2574,13 +2574,13 @@ mod size_asserts {
     // tidy-alphabetical-start
     static_assert_size!(Crate, 72); // frequently moved by-value
     static_assert_size!(DocFragment, 32);
-    static_assert_size!(GenericArg, 48);
+    static_assert_size!(GenericArg, 32);
     static_assert_size!(GenericArgs, 32);
     static_assert_size!(GenericParamDef, 56);
     static_assert_size!(Generics, 16);
     static_assert_size!(Item, 56);
-    static_assert_size!(ItemKind, 88);
+    static_assert_size!(ItemKind, 64);
     static_assert_size!(PathSegment, 40);
-    static_assert_size!(Type, 48);
+    static_assert_size!(Type, 32);
     // tidy-alphabetical-end
 }
index 824d98113c8f3a18ae8aa3ffbb4197a74df499d9..21f8fbe36f173fdf318079caa785f9d4116f9dca 100644 (file)
@@ -21,7 +21,7 @@
 use rustc_span::symbol::{kw, sym, Symbol};
 use std::fmt::Write as _;
 use std::mem;
-use thin_vec::ThinVec;
+use thin_vec::{thin_vec, ThinVec};
 
 #[cfg(test)]
 mod tests;
@@ -136,7 +136,7 @@ pub(super) fn external_path<'tcx>(
     let name = cx.tcx.item_name(did);
     Path {
         res: Res::Def(def_kind, did),
-        segments: vec![PathSegment {
+        segments: thin_vec![PathSegment {
             name,
             args: external_generic_args(cx, did, has_self, bindings, substs),
         }],
@@ -242,19 +242,13 @@ pub(crate) fn print_const(cx: &DocContext<'_>, n: ty::Const<'_>) -> String {
 
             s
         }
-        _ => {
-            let mut s = n.to_string();
-            // array lengths are obviously usize
-            if s.ends_with("_usize") {
-                let n = s.len() - "_usize".len();
-                s.truncate(n);
-                if s.ends_with(": ") {
-                    let n = s.len() - ": ".len();
-                    s.truncate(n);
-                }
-            }
-            s
+        // array lengths are obviously usize
+        ty::ConstKind::Value(ty::ValTree::Leaf(scalar))
+            if *n.ty().kind() == ty::Uint(ty::UintTy::Usize) =>
+        {
+            scalar.to_string()
         }
+        _ => n.to_string(),
     }
 }
 
index 9c08eac4edcb0140f000dbb8b1ee93f0e270aaaf..789dd398be50d7298da6dd2bdbfae5e9df742142 100644 (file)
@@ -326,7 +326,7 @@ pub(crate) fn from_matches(
             crate::usage("rustdoc");
             return Err(0);
         } else if matches.opt_present("version") {
-            rustc_driver::version("rustdoc", matches);
+            rustc_driver::version!("rustdoc", matches);
             return Err(0);
         }
 
index a5c3d35b1b594ec9bcbc3ba401c23d7fccfb4944..39e2a90222670250fd8c0c81e75fe50901430435 100644 (file)
@@ -107,10 +107,6 @@ pub(crate) fn into_inner(self) -> String {
         self.buffer
     }
 
-    pub(crate) fn insert_str(&mut self, idx: usize, s: &str) {
-        self.buffer.insert_str(idx, s);
-    }
-
     pub(crate) fn push_str(&mut self, s: &str) {
         self.buffer.push_str(s);
     }
index 48c6abfca90cee5cfb238e401911de2d48cded87..a60e7cb10fa515c8b4f17745808f7f8d3d575f70 100644 (file)
@@ -71,7 +71,7 @@ pub(crate) fn render<T: Print, S: Print>(
     let mut themes: Vec<String> = style_files.iter().map(|s| s.basename().unwrap()).collect();
     themes.sort();
 
-    let rustdoc_version = rustc_interface::util::version_str().unwrap_or("unknown version");
+    let rustdoc_version = rustc_interface::util::version_str!().unwrap_or("unknown version");
     let content = Buffer::html().to_display(t); // Note: This must happen before making the sidebar.
     let sidebar = Buffer::html().to_display(sidebar);
     PageLayout {
index 51843a505f7095963ed97be0ba98f946439c869a..73690c86f4f72b97070c9c42718fe47022c2b468 100644 (file)
@@ -69,11 +69,13 @@ pub(crate) struct Context<'tcx> {
     /// the source files are present in the html rendering, then this will be
     /// `true`.
     pub(crate) include_sources: bool,
+    /// Collection of all types with notable traits referenced in the current module.
+    pub(crate) types_with_notable_traits: FxHashSet<clean::Type>,
 }
 
 // `Context` is cloned a lot, so we don't want the size to grow unexpectedly.
 #[cfg(all(not(windows), target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Context<'_>, 128);
+rustc_data_structures::static_assert_size!(Context<'_>, 160);
 
 /// Shared mutable state used in [`Context`] and elsewhere.
 pub(crate) struct SharedContext<'tcx> {
@@ -532,6 +534,7 @@ fn init(
             deref_id_map: FxHashMap::default(),
             shared: Rc::new(scx),
             include_sources,
+            types_with_notable_traits: FxHashSet::default(),
         };
 
         if emit_crate {
@@ -560,6 +563,7 @@ fn make_child_renderer(&self) -> Self {
             id_map: IdMap::new(),
             shared: Rc::clone(&self.shared),
             include_sources: self.include_sources,
+            types_with_notable_traits: FxHashSet::default(),
         }
     }
 
@@ -803,6 +807,7 @@ fn item(&mut self, item: clean::Item) -> Result<(), Error> {
                 }
             }
         }
+
         Ok(())
     }
 
index 3a041ae15d6185904cb8de0d4d9c2b7ed4ca26af..8731efb5e87469df5771f938ef9dc1521d9d7902 100644 (file)
@@ -59,7 +59,7 @@
     symbol::{sym, Symbol},
     BytePos, FileName, RealFileName,
 };
-use serde::ser::SerializeSeq;
+use serde::ser::{SerializeMap, SerializeSeq};
 use serde::{Serialize, Serializer};
 
 use crate::clean::{self, ItemId, RenderedLink, SelfTy};
@@ -803,7 +803,7 @@ fn assoc_method(
     d: &clean::FnDecl,
     link: AssocItemLink<'_>,
     parent: ItemType,
-    cx: &Context<'_>,
+    cx: &mut Context<'_>,
     render_mode: RenderMode,
 ) {
     let tcx = cx.tcx();
@@ -836,6 +836,8 @@ fn assoc_method(
         + name.as_str().len()
         + generics_len;
 
+    let notable_traits = d.output.as_return().and_then(|output| notable_traits_button(output, cx));
+
     let (indent, indent_str, end_newline) = if parent == ItemType::Trait {
         header_len += 4;
         let indent_str = "    ";
@@ -861,9 +863,9 @@ fn assoc_method(
         name = name,
         generics = g.print(cx),
         decl = d.full_print(header_len, indent, cx),
-        notable_traits = notable_traits_decl(d, cx),
+        notable_traits = notable_traits.unwrap_or_default(),
         where_clause = print_where_clause(g, cx, indent, end_newline),
-    )
+    );
 }
 
 /// Writes a span containing the versions at which an item became stable and/or const-stable. For
@@ -963,7 +965,7 @@ fn render_assoc_item(
     item: &clean::Item,
     link: AssocItemLink<'_>,
     parent: ItemType,
-    cx: &Context<'_>,
+    cx: &mut Context<'_>,
     render_mode: RenderMode,
 ) {
     match &*item.kind {
@@ -1273,88 +1275,133 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) ->
     }
 }
 
-fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String {
-    let mut out = Buffer::html();
+pub(crate) fn notable_traits_button(ty: &clean::Type, cx: &mut Context<'_>) -> Option<String> {
+    let mut has_notable_trait = false;
+
+    let did = ty.def_id(cx.cache())?;
 
-    if let Some((did, ty)) = decl.output.as_return().and_then(|t| Some((t.def_id(cx.cache())?, t)))
+    // Box has pass-through impls for Read, Write, Iterator, and Future when the
+    // boxed type implements one of those. We don't want to treat every Box return
+    // as being notably an Iterator (etc), though, so we exempt it. Pin has the same
+    // issue, with a pass-through impl for Future.
+    if Some(did) == cx.tcx().lang_items().owned_box()
+        || Some(did) == cx.tcx().lang_items().pin_type()
     {
-        // Box has pass-through impls for Read, Write, Iterator, and Future when the
-        // boxed type implements one of those. We don't want to treat every Box return
-        // as being notably an Iterator (etc), though, so we exempt it. Pin has the same
-        // issue, with a pass-through impl for Future.
-        if Some(did) == cx.tcx().lang_items().owned_box()
-            || Some(did) == cx.tcx().lang_items().pin_type()
-        {
-            return "".to_string();
-        }
-        if let Some(impls) = cx.cache().impls.get(&did) {
-            for i in impls {
-                let impl_ = i.inner_impl();
-                if !impl_.for_.without_borrowed_ref().is_same(ty.without_borrowed_ref(), cx.cache())
+        return None;
+    }
+
+    if let Some(impls) = cx.cache().impls.get(&did) {
+        for i in impls {
+            let impl_ = i.inner_impl();
+            if !impl_.for_.without_borrowed_ref().is_same(ty.without_borrowed_ref(), cx.cache()) {
+                // Two different types might have the same did,
+                // without actually being the same.
+                continue;
+            }
+            if let Some(trait_) = &impl_.trait_ {
+                let trait_did = trait_.def_id();
+
+                if cx.cache().traits.get(&trait_did).map_or(false, |t| t.is_notable_trait(cx.tcx()))
                 {
-                    // Two different types might have the same did,
-                    // without actually being the same.
-                    continue;
+                    has_notable_trait = true;
                 }
-                if let Some(trait_) = &impl_.trait_ {
-                    let trait_did = trait_.def_id();
-
-                    if cx
-                        .cache()
-                        .traits
-                        .get(&trait_did)
-                        .map_or(false, |t| t.is_notable_trait(cx.tcx()))
-                    {
-                        if out.is_empty() {
-                            write!(
-                                &mut out,
-                                "<span class=\"notable\">Notable traits for {}</span>\
-                             <code class=\"content\">",
-                                impl_.for_.print(cx)
-                            );
-                        }
+            }
+        }
+    }
+
+    if has_notable_trait {
+        cx.types_with_notable_traits.insert(ty.clone());
+        Some(format!(
+            " <a href=\"#\" class=\"notable-traits\" data-ty=\"{ty}\">ⓘ</a>",
+            ty = Escape(&format!("{:#}", ty.print(cx))),
+        ))
+    } else {
+        None
+    }
+}
 
-                        //use the "where" class here to make it small
-                        write!(
+fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) {
+    let mut out = Buffer::html();
+
+    let did = ty.def_id(cx.cache()).expect("notable_traits_button already checked this");
+
+    let impls = cx.cache().impls.get(&did).expect("notable_traits_button already checked this");
+
+    for i in impls {
+        let impl_ = i.inner_impl();
+        if !impl_.for_.without_borrowed_ref().is_same(ty.without_borrowed_ref(), cx.cache()) {
+            // Two different types might have the same did,
+            // without actually being the same.
+            continue;
+        }
+        if let Some(trait_) = &impl_.trait_ {
+            let trait_did = trait_.def_id();
+
+            if cx.cache().traits.get(&trait_did).map_or(false, |t| t.is_notable_trait(cx.tcx())) {
+                if out.is_empty() {
+                    write!(
+                        &mut out,
+                        "<h3>Notable traits for <code>{}</code></h3>\
+                     <pre class=\"content\"><code>",
+                        impl_.for_.print(cx)
+                    );
+                }
+
+                //use the "where" class here to make it small
+                write!(
+                    &mut out,
+                    "<span class=\"where fmt-newline\">{}</span>",
+                    impl_.print(false, cx)
+                );
+                for it in &impl_.items {
+                    if let clean::AssocTypeItem(ref tydef, ref _bounds) = *it.kind {
+                        out.push_str("<span class=\"where fmt-newline\">    ");
+                        let empty_set = FxHashSet::default();
+                        let src_link = AssocItemLink::GotoSource(trait_did.into(), &empty_set);
+                        assoc_type(
                             &mut out,
-                            "<span class=\"where fmt-newline\">{}</span>",
-                            impl_.print(false, cx)
+                            it,
+                            &tydef.generics,
+                            &[], // intentionally leaving out bounds
+                            Some(&tydef.type_),
+                            src_link,
+                            0,
+                            cx,
                         );
-                        for it in &impl_.items {
-                            if let clean::AssocTypeItem(ref tydef, ref _bounds) = *it.kind {
-                                out.push_str("<span class=\"where fmt-newline\">    ");
-                                let empty_set = FxHashSet::default();
-                                let src_link =
-                                    AssocItemLink::GotoSource(trait_did.into(), &empty_set);
-                                assoc_type(
-                                    &mut out,
-                                    it,
-                                    &tydef.generics,
-                                    &[], // intentionally leaving out bounds
-                                    Some(&tydef.type_),
-                                    src_link,
-                                    0,
-                                    cx,
-                                );
-                                out.push_str(";</span>");
-                            }
-                        }
+                        out.push_str(";</span>");
                     }
                 }
             }
         }
     }
-
-    if !out.is_empty() {
-        out.insert_str(
-            0,
-            "<span class=\"notable-traits\"><span class=\"notable-traits-tooltip\">ⓘ\
-            <span class=\"notable-traits-tooltiptext\"><span class=\"docblock\">",
-        );
-        out.push_str("</code></span></span></span></span>");
+    if out.is_empty() {
+        write!(&mut out, "</code></pre>",);
     }
 
-    out.into_inner()
+    (format!("{:#}", ty.print(cx)), out.into_inner())
+}
+
+pub(crate) fn notable_traits_json<'a>(
+    tys: impl Iterator<Item = &'a clean::Type>,
+    cx: &Context<'_>,
+) -> String {
+    let mut mp: Vec<(String, String)> = tys.map(|ty| notable_traits_decl(ty, cx)).collect();
+    mp.sort_by(|(name1, _html1), (name2, _html2)| name1.cmp(name2));
+    struct NotableTraitsMap(Vec<(String, String)>);
+    impl Serialize for NotableTraitsMap {
+        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+        where
+            S: Serializer,
+        {
+            let mut map = serializer.serialize_map(Some(self.0.len()))?;
+            for item in &self.0 {
+                map.serialize_entry(&item.0, &item.1)?;
+            }
+            map.end()
+        }
+    }
+    serde_json::to_string(&NotableTraitsMap(mp))
+        .expect("serialize (string, string) -> json object cannot fail")
 }
 
 #[derive(Clone, Copy, Debug)]
@@ -2890,9 +2937,6 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite
         })()
         .unwrap_or(rustc_span::DUMMY_SP);
 
-        // The root path is the inverse of Context::current
-        let root_path = vec!["../"; cx.current.len() - 1].join("");
-
         let mut decoration_info = FxHashMap::default();
         decoration_info.insert("highlight focus", vec![byte_ranges.remove(0)]);
         decoration_info.insert("highlight", byte_ranges);
@@ -2902,7 +2946,7 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite
             contents_subset,
             file_span,
             cx,
-            &root_path,
+            &cx.root_path(),
             highlight::DecorationInfo(decoration_info),
             sources::SourceContext::Embedded { offset: line_min, needs_expansion },
         );
index ce4fc4d68fac2452ff2aad0307af05ef4ff77871..ac11a860a4f0b88af87cc192f97674afe7c3afa0 100644 (file)
 
 use super::{
     collect_paths_for_type, document, ensure_trailing_slash, get_filtered_impls_for_reference,
-    item_ty_to_section, notable_traits_decl, render_all_impls, render_assoc_item,
-    render_assoc_items, render_attributes_in_code, render_attributes_in_pre, render_impl,
-    render_rightside, render_stability_since_raw, AssocItemLink, Context, ImplRenderingParameters,
+    item_ty_to_section, notable_traits_button, notable_traits_json, render_all_impls,
+    render_assoc_item, render_assoc_items, render_attributes_in_code, render_attributes_in_pre,
+    render_impl, render_rightside, render_stability_since_raw, AssocItemLink, Context,
+    ImplRenderingParameters,
 };
 use crate::clean;
 use crate::config::ModuleSorting;
@@ -183,6 +184,16 @@ pub(super) fn print_item(
             unreachable!();
         }
     }
+
+    // Render notable-traits.js used for all methods in this module.
+    if !cx.types_with_notable_traits.is_empty() {
+        write!(
+            buf,
+            r#"<script type="text/json" id="notable-traits-data">{}</script>"#,
+            notable_traits_json(cx.types_with_notable_traits.iter(), cx)
+        );
+        cx.types_with_notable_traits.clear();
+    }
 }
 
 /// For large structs, enums, unions, etc, determine whether to hide their fields
@@ -516,6 +527,9 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle
         + name.as_str().len()
         + generics_len;
 
+    let notable_traits =
+        f.decl.output.as_return().and_then(|output| notable_traits_button(output, cx));
+
     wrap_into_item_decl(w, |w| {
         wrap_item(w, "fn", |w| {
             render_attributes_in_pre(w, it, "");
@@ -533,11 +547,11 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle
                 generics = f.generics.print(cx),
                 where_clause = print_where_clause(&f.generics, cx, 0, Ending::Newline),
                 decl = f.decl.full_print(header_len, 0, cx),
-                notable_traits = notable_traits_decl(&f.decl, cx),
+                notable_traits = notable_traits.unwrap_or_default(),
             );
         });
     });
-    document(w, cx, it, None, HeadingOffset::H2)
+    document(w, cx, it, None, HeadingOffset::H2);
 }
 
 fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::Trait) {
index 8a01c01049d6e771d3f89eef9af9783dcd41f193..50135d6019006633eb804053085c1b8bf95a2b51 100644 (file)
@@ -276,25 +276,26 @@ pub(crate) fn print_src(
     let mut line_numbers = Buffer::empty_from(buf);
     let extra;
     line_numbers.write_str("<pre class=\"src-line-numbers\">");
+    let current_href = &context
+        .href_from_span(clean::Span::new(file_span), false)
+        .expect("only local crates should have sources emitted");
     match source_context {
         SourceContext::Standalone => {
             extra = None;
             for line in 1..=lines {
-                writeln!(line_numbers, "<span id=\"{0}\">{0}</span>", line)
+                writeln!(line_numbers, "<a href=\"#{line}\" id=\"{line}\">{line}</a>")
             }
         }
         SourceContext::Embedded { offset, needs_expansion } => {
             extra =
                 if needs_expansion { Some(r#"<span class="expand">&varr;</span>"#) } else { None };
-            for line in 1..=lines {
-                writeln!(line_numbers, "<span>{0}</span>", line + offset)
+            for line_number in 1..=lines {
+                let line = line_number + offset;
+                writeln!(line_numbers, "<span>{line}</span>")
             }
         }
     }
     line_numbers.write_str("</pre>");
-    let current_href = &context
-        .href_from_span(clean::Span::new(file_span), false)
-        .expect("only local crates should have sources emitted");
     highlight::render_source_with_highlighting(
         s,
         buf,
index 301f03a16427a3799b0259431c9293bf64fdece7..54e8b6561f34f9c3e4cb0b7ba1706e3a3e352b57 100644 (file)
@@ -22,3 +22,9 @@ nav.sub {
 .source .sidebar {
        display: none;
 }
+
+.notable-traits {
+       /* layout requires javascript
+           https://github.com/rust-lang/rust/issues/102576 */
+       display: none;
+}
index a38c0e42ab455345017d014801a85d38404e545a..3f295b96dc56d20ba82d8dd8133c9881e04a292b 100644 (file)
@@ -579,15 +579,16 @@ ul.block, .block li {
        border-color: var(--example-line-numbers-border-color);
 }
 
-.src-line-numbers span {
-       cursor: pointer;
+.src-line-numbers a, .src-line-numbers span {
        color: var(--src-line-numbers-span-color);
 }
-.src-line-numbers .line-highlighted {
-       background-color: var(--src-line-number-highlighted-background-color);
-}
 .src-line-numbers :target {
        background-color: transparent;
+       border-right: none;
+       padding-right: 0;
+}
+.src-line-numbers .line-highlighted {
+       background-color: var(--src-line-number-highlighted-background-color);
 }
 
 .search-loading {
@@ -830,6 +831,9 @@ table,
        line-height: 1.5;
        font-weight: 500;
 }
+#crate-search:hover, #crate-search:focus {
+       border-color: var(--crate-search-hover-border);
+}
 /* cancel stylistic differences in padding in firefox
 for "appearance: none"-style (or equivalent) <select>s */
 @-moz-document url-prefix() {
@@ -853,8 +857,13 @@ so that we can apply CSS-filters to change the arrow color in themes */
        background-repeat: no-repeat;
        background-size: 20px;
        background-position: calc(100% - 2px) 56%;
-       /* image is black color, themes should apply a "filter" property to change the color */
-       background-image: url("down-arrow-2d685a4bae708e15.svg");
+       /* image is black color */
+       background-image: url("down-arrow-927217e04c7463ac.svg");
+       /* changes the arrow image color */
+       filter: var(--crate-search-div-filter);
+}
+#crate-search-div:hover::after, #crate-search-div:focus-within::after {
+       filter: var(--crate-search-div-hover-filter);
 }
 #crate-search > option {
        font-size: 1rem;
@@ -920,13 +929,14 @@ so that we can apply CSS-filters to change the arrow color in themes */
        border-radius: 3px;
        border: 1px solid var(--border-color);
        font-size: 1rem;
+       --popover-arrow-offset: 11px;
 }
 
 /* This rule is to draw the little arrow connecting the settings menu to the gear icon. */
 .popover::before {
        content: '';
        position: absolute;
-       right: 11px;
+       right: var(--popover-arrow-offset);
        border: solid var(--border-color);
        border-width: 1px 1px 0 0;
        display: inline-block;
@@ -943,10 +953,7 @@ so that we can apply CSS-filters to change the arrow color in themes */
 /* use larger max-width for help popover, but not for help.html */
 #help.popover {
        max-width: 600px;
-}
-
-#help.popover::before {
-       right: 48px;
+       --popover-arrow-offset: 48px;
 }
 
 #help dt {
@@ -1261,53 +1268,38 @@ h3.variant {
 
 :target {
        padding-right: 3px;
+       background-color: var(--target-background-color);
+       border-right: 3px solid var(--target-border-color);
 }
 
-.notable-traits-tooltip {
-       display: inline-block;
-       cursor: pointer;
-}
-
-.notable-traits:hover .notable-traits-tooltiptext,
-.notable-traits .notable-traits-tooltiptext.force-tooltip {
-       display: inline-block;
+.notable-traits {
+       color: inherit;
+       margin-right: 15px;
+       position: relative;
 }
 
-.notable-traits .notable-traits-tooltiptext {
-       display: none;
-       padding: 5px 3px 3px 3px;
-       border-radius: 6px;
-       margin-left: 5px;
-       z-index: 10;
-       font-size: 1rem;
-       cursor: default;
+/* placeholder thunk so that the mouse can easily travel from "(i)" to popover
+       the resulting "hover tunnel" is a stepped triangle, approximating
+       https://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown */
+.notable-traits:hover::after {
        position: absolute;
-       border: 1px solid;
-}
-
-.notable-traits-tooltip::after {
-       /* The margin on the tooltip does not capture hover events,
-          this extends the area of hover enough so that mouse hover is not
-          lost when moving the mouse to the tooltip */
-       content: "\00a0\00a0\00a0";
-}
-
-.notable-traits .docblock {
-       margin: 0;
+       top: calc(100% - 10px);
+       left: -15px;
+       right: -15px;
+       height: 20px;
+       content: "\00a0";
 }
 
-.notable-traits .notable {
-       margin: 0;
-       margin-bottom: 13px;
-       font-size: 1.1875rem;
-       font-weight: 600;
-       display: block;
+.notable .docblock {
+       margin: 0.25em 0.5em;
 }
 
-.notable-traits .docblock code.content {
+.notable .docblock pre, .notable .docblock code {
+       background: transparent;
        margin: 0;
        padding: 0;
        font-size: 1.25rem;
+       white-space: pre-wrap;
 }
 
 .search-failed {
@@ -1350,12 +1342,6 @@ h3.variant {
        font-size: 1rem;
 }
 
-.notable-traits {
-       cursor: pointer;
-       z-index: 2;
-       margin-left: 5px;
-}
-
 #sidebar-toggle {
        position: sticky;
        top: 0;
@@ -1840,11 +1826,6 @@ in storage.js
                border-bottom: 1px solid;
        }
 
-       .notable-traits .notable-traits-tooltiptext {
-               left: 0;
-               top: 100%;
-       }
-
        /* We don't display the help button on mobile devices. */
        #help-button {
                display: none;
@@ -1969,7 +1950,6 @@ in storage.js
        font-size: 12px;
        position: relative;
        bottom: 1px;
-       background: transparent;
        border-width: 1px;
        border-style: solid;
        border-radius: 50px;
@@ -2031,6 +2011,7 @@ in storage.js
        padding: 14px 0;
 }
 
+.scraped-example .code-wrapper .src-line-numbers a,
 .scraped-example .code-wrapper .src-line-numbers span {
        padding: 0 14px;
 }
index 83939f63b4e852e672dfc5837b25ac32ac604c81..1f6fb961e918d430a5ad45ba293819769717c982 100644 (file)
@@ -8,7 +8,8 @@
        flex-wrap: wrap;
 }
 
-.setting-line .radio-line input {
+.setting-line .radio-line input,
+.setting-line .toggle input {
        margin-right: 0.3em;
        height: 1.2rem;
        width: 1.2rem;
        outline: none;
        -webkit-appearance: none;
        cursor: pointer;
+}
+.setting-line .radio-line input {
        border-radius: 50%;
 }
-.setting-line .radio-line input + span {
+.setting-line .toggle input:checked {
+       content: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40">\
+               <path d="M7,25L17,32L33,12" fill="none" stroke="black" stroke-width="5"/>\
+               <path d="M7,23L17,30L33,10" fill="none" stroke="white" stroke-width="5"/></svg>');
+}
+
+.setting-line .radio-line input + span,
+.setting-line .toggle span {
        padding-bottom: 1px;
 }
 
        cursor: pointer;
 }
 
-.toggle input {
-       opacity: 0;
-       position: absolute;
-}
-
-.slider {
-       position: relative;
-       width: 45px;
-       min-width: 45px;
-       display: block;
-       height: 28px;
-       margin-right: 20px;
-       cursor: pointer;
-       background-color: #ccc;
-       transition: .3s;
-}
-
-.slider:before {
-       position: absolute;
-       content: "";
-       height: 19px;
-       width: 19px;
-       left: 4px;
-       bottom: 4px;
-       transition: .3s;
-}
-
-input:checked + .slider:before {
-       transform: translateX(19px);
-}
-
 .setting-line > .sub-settings {
        padding-left: 42px;
        width: 100%;
@@ -94,7 +73,11 @@ input:checked + .slider:before {
        box-shadow: inset 0 0 0 3px var(--main-background-color);
        background-color: var(--settings-input-color);
 }
-.setting-line .radio-line input:focus {
+.setting-line .toggle input:checked {
+       background-color: var(--settings-input-color);
+}
+.setting-line .radio-line input:focus,
+.setting-line .toggle input:focus {
        box-shadow: 0 0 1px 1px var(--settings-input-color);
 }
 /* In here we combine both `:focus` and `:checked` properties. */
@@ -102,9 +85,7 @@ input:checked + .slider:before {
        box-shadow: inset 0 0 0 3px var(--main-background-color),
                0 0 2px 2px var(--settings-input-color);
 }
-.setting-line .radio-line input:hover {
+.setting-line .radio-line input:hover,
+.setting-line .toggle input:hover {
        border-color: var(--settings-input-color) !important;
 }
-input:checked + .slider {
-       background-color: var(--settings-input-color);
-}
index bf8a60affaa227f980ca8eece943da8ba76005fa..db311bccd6dc4a6997d9c40fe53c58392339af90 100644 (file)
@@ -63,20 +63,18 @@ Original by Dempfi (https://github.com/dempfi/ayu)
        --test-arrow-background-color: rgba(57, 175, 215, 0.09);
        --test-arrow-hover-color: #c5c5c5;
        --test-arrow-hover-background-color: rgba(57, 175, 215, 0.368);
+       --target-background-color: rgba(255, 236, 164, 0.06);
+       --target-border-color: rgba(255, 180, 76, 0.85);
        --rust-logo-filter: drop-shadow(1px 0 0px #fff)
                drop-shadow(0 1px 0 #fff)
                drop-shadow(-1px 0 0 #fff)
                drop-shadow(0 -1px 0 #fff);
-}
-
-.slider {
-       background-color: #ccc;
-}
-.slider:before {
-       background-color: white;
-}
-input:focus + .slider {
-       box-shadow: 0 0 0 2px #0a84ff, 0 0 0 6px rgba(10, 132, 255, 0.3);
+       /* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
+       --crate-search-div-filter: invert(41%) sepia(12%) saturate(487%) hue-rotate(171deg)
+               brightness(94%) contrast(94%);
+       --crate-search-div-hover-filter: invert(98%) sepia(12%) saturate(81%) hue-rotate(343deg)
+               brightness(113%) contrast(76%);
+       --crate-search-hover-border: #e0e0e0;
 }
 
 h1, h2, h3, h4 {
@@ -153,17 +151,6 @@ details.rustdoc-toggle > summary::before {
        filter: invert(100%);
 }
 
-#crate-search-div::after {
-       /* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
-       filter: invert(41%) sepia(12%) saturate(487%) hue-rotate(171deg) brightness(94%) contrast(94%);
-}
-#crate-search:hover, #crate-search:focus {
-       border-color: #e0e0e0 !important;
-}
-#crate-search-div:hover::after, #crate-search-div:focus-within::after {
-       filter: invert(98%) sepia(12%) saturate(81%) hue-rotate(343deg) brightness(113%) contrast(76%);
-}
-
 .module-item .stab,
 .import-item .stab {
        color: #000;
@@ -173,15 +160,6 @@ details.rustdoc-toggle > summary::before {
        color: #788797;
 }
 
-:target {
-       background: rgba(255, 236, 164, 0.06);
-       border-right: 3px solid rgba(255, 180, 76, 0.85);
-}
-
-.search-failed a {
-       color: #39AFD7;
-}
-
 .tooltip::after {
        background-color: #314559;
        color: #c5c5c5;
@@ -191,10 +169,6 @@ details.rustdoc-toggle > summary::before {
        border-color: transparent #314559 transparent transparent;
 }
 
-.notable-traits-tooltiptext {
-       background-color: #314559;
-}
-
 #titles > button.selected {
        background-color: #141920 !important;
        border-bottom: 1px solid #ffb44c !important;
index ac6e527848f613e4853a64708cd4a10e86c09101..b2f2c77f5475ae66f74321bfbf0cd6803f6c6ba1 100644 (file)
        --test-arrow-background-color: rgba(78, 139, 202, 0.2);
        --test-arrow-hover-color: #dedede;
        --test-arrow-hover-background-color: #4e8bca;
+       --target-background-color: #494a3d;
+       --target-border-color: #bb7410;
        --rust-logo-filter: drop-shadow(1px 0 0px #fff)
                drop-shadow(0 1px 0 #fff)
                drop-shadow(-1px 0 0 #fff)
                drop-shadow(0 -1px 0 #fff);
-}
-
-.slider {
-       background-color: #ccc;
-}
-.slider:before {
-       background-color: white;
-}
-input:focus + .slider {
-       box-shadow: 0 0 0 2px #0a84ff, 0 0 0 6px rgba(10, 132, 255, 0.3);
+       /* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
+       --crate-search-div-filter: invert(94%) sepia(0%) saturate(721%) hue-rotate(255deg)
+               brightness(90%) contrast(90%);
+       --crate-search-div-hover-filter: invert(69%) sepia(60%) saturate(6613%) hue-rotate(184deg)
+               brightness(100%) contrast(91%);
+       --crate-search-hover-border: #2196f3;
 }
 
 .content .item-info::before { color: #ccc; }
@@ -84,26 +82,6 @@ details.rustdoc-toggle > summary::before {
        filter: invert(100%);
 }
 
-#crate-search-div::after {
-       /* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
-       filter: invert(94%) sepia(0%) saturate(721%) hue-rotate(255deg) brightness(90%) contrast(90%);
-}
-#crate-search:hover, #crate-search:focus {
-       border-color: #2196f3 !important;
-}
-#crate-search-div:hover::after, #crate-search-div:focus-within::after {
-       filter: invert(69%) sepia(60%) saturate(6613%) hue-rotate(184deg) brightness(100%) contrast(91%);
-}
-
-:target {
-       background-color: #494a3d;
-       border-right: 3px solid #bb7410;
-}
-
-.search-failed a {
-       color: #0089ff;
-}
-
 .tooltip::after {
        background-color: #000;
        color: #fff;
@@ -114,10 +92,6 @@ details.rustdoc-toggle > summary::before {
        border-color: transparent black transparent transparent;
 }
 
-.notable-traits-tooltiptext {
-       background-color: #111;
-}
-
 #titles > button:not(.selected) {
        background-color: #252525;
        border-top-color: #252525;
index 608fc5aba7fd3f6e2bd2ee4c70cd565dca569e10..e81327956888b142befd662515dabab42c3c6ff0 100644 (file)
        --test-arrow-background-color: rgba(78, 139, 202, 0.2);
        --test-arrow-hover-color: #f5f5f5;
        --test-arrow-hover-background-color: #4e8bca;
+       --target-background-color: #fdFfd3;
+       --target-border-color: #ad7c37;
        --rust-logo-filter: initial;
-}
-
-.slider {
-       background-color: #ccc;
-}
-.slider:before {
-       background-color: white;
-}
-input:focus + .slider {
-       box-shadow: 0 0 0 2px #0a84ff, 0 0 0 6px rgba(10, 132, 255, 0.3);
+       /* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
+       --crate-search-div-filter: invert(100%) sepia(0%) saturate(4223%) hue-rotate(289deg)
+               brightness(114%) contrast(76%);
+       --crate-search-div-hover-filter: invert(44%) sepia(18%) saturate(23%) hue-rotate(317deg)
+               brightness(96%) contrast(93%);
+       --crate-search-hover-border: #717171;
 }
 
 .content .item-info::before { color: #ccc; }
@@ -77,26 +75,6 @@ body.source .example-wrap pre.rust a {
        background: #eee;
 }
 
-#crate-search-div::after {
-       /* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
-       filter: invert(100%) sepia(0%) saturate(4223%) hue-rotate(289deg) brightness(114%) contrast(76%);
-}
-#crate-search:hover, #crate-search:focus {
-       border-color: #717171 !important;
-}
-#crate-search-div:hover::after, #crate-search-div:focus-within::after {
-       filter: invert(44%) sepia(18%) saturate(23%) hue-rotate(317deg) brightness(96%) contrast(93%);
-}
-
-:target {
-       background: #FDFFD3;
-       border-right: 3px solid #AD7C37;
-}
-
-.search-failed a {
-       color: #3873AD;
-}
-
 .tooltip::after {
        background-color: #000;
        color: #fff;
@@ -106,10 +84,6 @@ body.source .example-wrap pre.rust a {
        border-color: transparent black transparent transparent;
 }
 
-.notable-traits-tooltiptext {
-       background-color: #eee;
-}
-
 #titles > button:not(.selected) {
        background-color: #e6e6e6;
        border-top-color: #e6e6e6;
index 1c84393cb4e6f890661f398220cd35bcf2a7fe38..0538762e44d031368f822c72857baae46b1bf0ce 100644 (file)
@@ -790,6 +790,19 @@ function loadCss(cssUrl) {
             // we need to switch away from mobile mode and make the main content area scrollable.
             hideSidebar();
         }
+        if (window.CURRENT_NOTABLE_ELEMENT) {
+            // As a workaround to the behavior of `contains: layout` used in doc togglers, the
+            // notable traits popup is positioned using javascript.
+            //
+            // This means when the window is resized, we need to redo the layout.
+            const base = window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE;
+            const force_visible = base.NOTABLE_FORCE_VISIBLE;
+            hideNotable();
+            if (force_visible) {
+                showNotable(base);
+                base.NOTABLE_FORCE_VISIBLE = true;
+            }
+        }
     });
 
     function handleClick(id, f) {
@@ -822,10 +835,121 @@ function loadCss(cssUrl) {
         });
     });
 
+    function showNotable(e) {
+        if (!window.NOTABLE_TRAITS) {
+            const data = document.getElementById("notable-traits-data");
+            if (data) {
+                window.NOTABLE_TRAITS = JSON.parse(data.innerText);
+            } else {
+                throw new Error("showNotable() called on page without any notable traits!");
+            }
+        }
+        if (window.CURRENT_NOTABLE_ELEMENT && window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE === e) {
+            // Make this function idempotent.
+            return;
+        }
+        hideNotable();
+        const ty = e.getAttribute("data-ty");
+        const wrapper = document.createElement("div");
+        wrapper.innerHTML = "<div class=\"docblock\">" + window.NOTABLE_TRAITS[ty] + "</div>";
+        wrapper.className = "notable popover";
+        const focusCatcher = document.createElement("div");
+        focusCatcher.setAttribute("tabindex", "0");
+        focusCatcher.onfocus = hideNotable;
+        wrapper.appendChild(focusCatcher);
+        const pos = e.getBoundingClientRect();
+        // 5px overlap so that the mouse can easily travel from place to place
+        wrapper.style.top = (pos.top + window.scrollY + pos.height) + "px";
+        wrapper.style.left = 0;
+        wrapper.style.right = "auto";
+        wrapper.style.visibility = "hidden";
+        const body = document.getElementsByTagName("body")[0];
+        body.appendChild(wrapper);
+        const wrapperPos = wrapper.getBoundingClientRect();
+        // offset so that the arrow points at the center of the "(i)"
+        const finalPos = pos.left + window.scrollX - wrapperPos.width + 24;
+        if (finalPos > 0) {
+            wrapper.style.left = finalPos + "px";
+        } else {
+            wrapper.style.setProperty(
+                "--popover-arrow-offset",
+                (wrapperPos.right - pos.right + 4) + "px"
+            );
+        }
+        wrapper.style.visibility = "";
+        window.CURRENT_NOTABLE_ELEMENT = wrapper;
+        window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE = e;
+        wrapper.onpointerleave = function(ev) {
+            // If this is a synthetic touch event, ignore it. A click event will be along shortly.
+            if (ev.pointerType !== "mouse") {
+                return;
+            }
+            if (!e.NOTABLE_FORCE_VISIBLE && !elemIsInParent(event.relatedTarget, e)) {
+                hideNotable();
+            }
+        };
+    }
+
+    function notableBlurHandler(event) {
+        if (window.CURRENT_NOTABLE_ELEMENT &&
+            !elemIsInParent(document.activeElement, window.CURRENT_NOTABLE_ELEMENT) &&
+            !elemIsInParent(event.relatedTarget, window.CURRENT_NOTABLE_ELEMENT) &&
+            !elemIsInParent(document.activeElement, window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE) &&
+            !elemIsInParent(event.relatedTarget, window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE)
+        ) {
+            // Work around a difference in the focus behaviour between Firefox, Chrome, and Safari.
+            // When I click the button on an already-opened notable trait popover, Safari
+            // hides the popover and then immediately shows it again, while everyone else hides it
+            // and it stays hidden.
+            //
+            // To work around this, make sure the click finishes being dispatched before
+            // hiding the popover. Since `hideNotable()` is idempotent, this makes Safari behave
+            // consistently with the other two.
+            setTimeout(hideNotable, 0);
+        }
+    }
+
+    function hideNotable() {
+        if (window.CURRENT_NOTABLE_ELEMENT) {
+            if (window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE.NOTABLE_FORCE_VISIBLE) {
+                window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE.focus();
+                window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE.NOTABLE_FORCE_VISIBLE = false;
+            }
+            const body = document.getElementsByTagName("body")[0];
+            body.removeChild(window.CURRENT_NOTABLE_ELEMENT);
+            window.CURRENT_NOTABLE_ELEMENT = null;
+        }
+    }
+
     onEachLazy(document.getElementsByClassName("notable-traits"), e => {
         e.onclick = function() {
-            this.getElementsByClassName("notable-traits-tooltiptext")[0]
-                .classList.toggle("force-tooltip");
+            this.NOTABLE_FORCE_VISIBLE = this.NOTABLE_FORCE_VISIBLE ? false : true;
+            if (window.CURRENT_NOTABLE_ELEMENT && !this.NOTABLE_FORCE_VISIBLE) {
+                hideNotable();
+            } else {
+                showNotable(this);
+                window.CURRENT_NOTABLE_ELEMENT.setAttribute("tabindex", "0");
+                window.CURRENT_NOTABLE_ELEMENT.focus();
+                window.CURRENT_NOTABLE_ELEMENT.onblur = notableBlurHandler;
+            }
+            return false;
+        };
+        e.onpointerenter = function(ev) {
+            // If this is a synthetic touch event, ignore it. A click event will be along shortly.
+            if (ev.pointerType !== "mouse") {
+                return;
+            }
+            showNotable(this);
+        };
+        e.onpointerleave = function(ev) {
+            // If this is a synthetic touch event, ignore it. A click event will be along shortly.
+            if (ev.pointerType !== "mouse") {
+                return;
+            }
+            if (!this.NOTABLE_FORCE_VISIBLE &&
+                !elemIsInParent(event.relatedTarget, window.CURRENT_NOTABLE_ELEMENT)) {
+                hideNotable();
+            }
         };
     });
 
@@ -935,6 +1059,7 @@ function loadCss(cssUrl) {
         onEachLazy(document.querySelectorAll(".search-form .popover"), elem => {
             elem.style.display = "none";
         });
+        hideNotable();
     };
 
     /**
index 141563bd46a19796184109af2590d791561f6202..95cc265f1bdf6b96d05fe637d1295e14b3b8d474 100644 (file)
@@ -66,8 +66,7 @@
 
     function setEvents(settingsElement) {
         updateLightAndDark();
-        onEachLazy(settingsElement.getElementsByClassName("slider"), elem => {
-            const toggle = elem.previousElementSibling;
+        onEachLazy(settingsElement.querySelectorAll("input[type=\"checkbox\"]"), toggle => {
             const settingId = toggle.id;
             const settingValue = getSettingValue(settingId);
             if (settingValue !== null) {
                 const checked = setting["default"] === true ? " checked" : "";
                 output += `<label class="toggle">\
                         <input type="checkbox" id="${js_data_name}"${checked}>\
-                        <span class="slider"></span>\
                         <span class="label">${setting_name}</span>\
                     </label>`;
             }
index 0b9368dd899484a0c167e313e5d5032fa3a303a1..5db768c1c5753aa063d1b9f828b67ef76f005660 100644 (file)
@@ -157,7 +157,7 @@ function highlightSourceLines(match) {
         x.scrollIntoView();
     }
     onEachLazy(document.getElementsByClassName("src-line-numbers"), e => {
-        onEachLazy(e.getElementsByTagName("span"), i_e => {
+        onEachLazy(e.getElementsByTagName("a"), i_e => {
             removeClass(i_e, "line-highlighted");
         });
     });
@@ -188,8 +188,13 @@ const handleSourceHighlight = (function() {
 
     return ev => {
         let cur_line_id = parseInt(ev.target.id, 10);
-        // It can happen when clicking not on a line number span.
-        if (isNaN(cur_line_id)) {
+        // This event handler is attached to the entire line number column, but it should only
+        // be run if one of the anchors is clicked. It also shouldn't do anything if the anchor
+        // is clicked with a modifier key (to open a new browser tab).
+        if (isNaN(cur_line_id) ||
+            ev.ctrlKey ||
+            ev.altKey ||
+            ev.metaKey) {
             return;
         }
         ev.preventDefault();
index cb8b7c18029f02e7812873f1fde215885d211428..091a1ba70cab7d2a3691acb17dde6d8cd1c9220c 100644 (file)
@@ -485,7 +485,7 @@ fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self {
             BareFunction(f) => Type::FunctionPointer(Box::new((*f).into_tcx(tcx))),
             Tuple(t) => Type::Tuple(t.into_tcx(tcx)),
             Slice(t) => Type::Slice(Box::new((*t).into_tcx(tcx))),
-            Array(t, s) => Type::Array { type_: Box::new((*t).into_tcx(tcx)), len: s },
+            Array(t, s) => Type::Array { type_: Box::new((*t).into_tcx(tcx)), len: s.to_string() },
             ImplTrait(g) => Type::ImplTrait(g.into_tcx(tcx)),
             Infer => Type::Infer,
             RawPointer(mutability, type_) => Type::RawPointer {
index 0bd0dbbeb702ca6ef46be3e8a030606c4479da69..37a28b6b7bd84a17282686cdc40dc816d1e70ce6 100644 (file)
@@ -402,6 +402,7 @@ fn resolve_self_ty(&self, path_str: &str, ns: Namespace, item_id: ItemId) -> Opt
             })
             .and_then(|self_id| match tcx.def_kind(self_id) {
                 DefKind::Impl => self.def_id_to_res(self_id),
+                DefKind::Use => None,
                 def_kind => Some(Res::Def(def_kind, self_id)),
             })
     }
@@ -1772,7 +1773,6 @@ fn split(path: &str) -> Option<(&str, &str)> {
 
                     // Otherwise, it must be an associated item or variant
                     let res = partial_res.expect("None case was handled by `last_found_module`");
-                    let name = res.name(tcx);
                     let kind = match res {
                         Res::Def(kind, _) => Some(kind),
                         Res::Primitive(_) => None,
@@ -1814,6 +1814,7 @@ fn split(path: &str) -> Option<(&str, &str)> {
                     } else {
                         "associated item"
                     };
+                    let name = res.name(tcx);
                     let note = format!(
                         "the {} `{}` has no {} named `{}`",
                         res.descr(),
index 2a2ea6b49e79325e0d10d33fac2b10ea3bebcc7c..a1232c451fc27173f8718e05d174b2503ca0b607 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 2a2ea6b49e79325e0d10d33fac2b10ea3bebcc7c
+Subproject commit a1232c451fc27173f8718e05d174b2503ca0b607
index 72308d50c8ebe367197bfd80363df74e9f5f57a7..c3f50272b67c2edf648f79bf129a72cc2b6398c3 100644 (file)
     "tool is executed."
   ],
   "compiler": {
-    "date": "2022-09-20",
+    "date": "2022-11-01",
     "version": "beta"
   },
   "rustfmt": {
-    "date": "2022-09-20",
+    "date": "2022-11-01",
     "version": "nightly"
   },
   "checksums_sha256": {
-    "dist/2022-09-20/cargo-beta-aarch64-apple-darwin.tar.gz": "3186f69cc7efaf3f933ad77798ddf58bf11c0719dc1dec53fadc502a236ef753",
-    "dist/2022-09-20/cargo-beta-aarch64-apple-darwin.tar.xz": "5ad195346a21a80c700ca08223060ea66298fe8e4cbac19148d14b92a9319b01",
-    "dist/2022-09-20/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "6a7647d761ce3adba9d4ceff2e6c1929e9d96d767961a7a062f41ec09a1abb85",
-    "dist/2022-09-20/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "13566a68dd2000fb33a990c21b62b82e77d1bd1f3384152f439cf96318f07f3e",
-    "dist/2022-09-20/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "cc698fe69e27a077c6d2aa8dc7319847b1ecd78ad4e3519161957c7cab90c592",
-    "dist/2022-09-20/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "1cd369b8ab90e85da78784cf08a92aee87f0804b448676637ee48cb3409dc026",
-    "dist/2022-09-20/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "856170acebfd7900448fe02bd835d633b2930e2401c4211d72e5dd8c38943606",
-    "dist/2022-09-20/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "5bbc32a426071c84d39395c64e1f9cfe0db29ab10c255c2a8a8f748b624cdb7a",
-    "dist/2022-09-20/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "50518c889d2408a7edf524c0340c8ff6881fd14f505dca0d419deefdb94c3afb",
-    "dist/2022-09-20/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "8143057e446c169e614c153ffbe2428e94404af96d06b1d3103028f695388211",
-    "dist/2022-09-20/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "987064edfdb30dde07ef9b2cbd072f66ca042bf95ae724909cafbc13bcf69885",
-    "dist/2022-09-20/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "253161f50a399818a77360f97443ef818dfca3d384e86048655b08c8a799bafc",
-    "dist/2022-09-20/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "7b9a0feee8f3e1e3c58df38f947904d76006c938a2395650e094337ede9918e9",
-    "dist/2022-09-20/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "2194b642b8ed595b8534ded204a72f910215c8f42482ac64644f784a3b2ae8b3",
-    "dist/2022-09-20/cargo-beta-i686-pc-windows-gnu.tar.gz": "7cc2c490988dd1ae095198664317cb0b5c8071fc31bf49aed1eca21eb2766cd8",
-    "dist/2022-09-20/cargo-beta-i686-pc-windows-gnu.tar.xz": "32641252e12cdadf0a232b43103fc56af621a48056864ff2ee9a034dd2da8f1f",
-    "dist/2022-09-20/cargo-beta-i686-pc-windows-msvc.tar.gz": "32581e6bf22e7d2c7a147a87158161e3fa07f46ec0252e632a3bafb824382a28",
-    "dist/2022-09-20/cargo-beta-i686-pc-windows-msvc.tar.xz": "a9a68905a4540389d28e40cc2137cf2fcca77c425089cd99072a34ba15e3ab6a",
-    "dist/2022-09-20/cargo-beta-i686-unknown-linux-gnu.tar.gz": "b5d9ecd7be4ab25919cd0731bb28a2612965943c5ccedf35ac09c169ed2c97db",
-    "dist/2022-09-20/cargo-beta-i686-unknown-linux-gnu.tar.xz": "387f7d95d04503293f708f65821f55878449eb5a0efe3344005dca18b84e6563",
-    "dist/2022-09-20/cargo-beta-mips-unknown-linux-gnu.tar.gz": "f8fbf21aac677276cdf246748d59d183e566bfcacabcd3eab6f19d6c857193ef",
-    "dist/2022-09-20/cargo-beta-mips-unknown-linux-gnu.tar.xz": "70e561d77632d1463839a8ea9cb72ff49afb61dbba95fa321bdba74be384b21f",
-    "dist/2022-09-20/cargo-beta-mips64-unknown-linux-gnuabi64.tar.gz": "e81b5a5fc70a1f7ed5920a3860b1259a2cecd9a1d981f2a564cd936de53ecf8a",
-    "dist/2022-09-20/cargo-beta-mips64-unknown-linux-gnuabi64.tar.xz": "ef9de44d1d37812bfeb67b353f1e308bf46d62c9fe191980de3a62fbfe5167a4",
-    "dist/2022-09-20/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "68c1cd309775626f19431f7dbb73789b17ee629b588e05bf0231313913cb6a8a",
-    "dist/2022-09-20/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "db290a98987c8bd527f1efe9ff09055fdce8eea0673d2c5eba0640649396b8d0",
-    "dist/2022-09-20/cargo-beta-mipsel-unknown-linux-gnu.tar.gz": "f4a7da60f164c03bd274f8c98b58a524d7a73476c726e2ef5695f2be950421c7",
-    "dist/2022-09-20/cargo-beta-mipsel-unknown-linux-gnu.tar.xz": "8fc46e05ba0830eec88e1d764b02fb9a4836883fd180800a8edd3a4cf0acbdae",
-    "dist/2022-09-20/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "5f528af9436bfa31d559544220fcb59001a90bff18363390f7fab82f259defde",
-    "dist/2022-09-20/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "502d6da5158075cd997833314f9ca7a527aecc8e28c9e26ee9796c2e9ac91cf5",
-    "dist/2022-09-20/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "16a7b922fa6c6019541e859386dbd38e64507d951376c847f83c6b983c72b417",
-    "dist/2022-09-20/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "7f3e361f9bfcdb5fd765f86ed372e00df62af4ae5714d9a2b3324f3929518677",
-    "dist/2022-09-20/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "f38265c64d6ac34d4632f38368d910bd9471aaf8736595623126cb53e810e307",
-    "dist/2022-09-20/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "99e7f3795aea0abb019b80b1f35aa8e1638fee35e548424ca52fd23c5bf82c71",
-    "dist/2022-09-20/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "bb9e89b65fca9a1fad5293e8a52b27331f08e9660237c0b1e7f750064d45ab1d",
-    "dist/2022-09-20/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "ea81188084da2f2771a1d9414c20065a19544b1af0e56dc71eae7ca00ff72708",
-    "dist/2022-09-20/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "745577c8c52065d84cedd32608ca0e17f1a46bb86b4d619cd01785486dc99480",
-    "dist/2022-09-20/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "85944275d5d05943c89ebf8e487bee35ed8586aa9f1903f83490c12ba74ad8cf",
-    "dist/2022-09-20/cargo-beta-x86_64-apple-darwin.tar.gz": "6c3f841c718404d4917353c7fefee7491df62d7456633bfb99dc850a49aab285",
-    "dist/2022-09-20/cargo-beta-x86_64-apple-darwin.tar.xz": "0c5a5c3ceec9fcf3b8dbb9fd10172251622e873671049b042b55ede34b8797a8",
-    "dist/2022-09-20/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "385a01c7a11a5f51253e8182d82763295037d625e7bcf27d54b5f0349cea488c",
-    "dist/2022-09-20/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "fe498e30198a43586be82c6fbd794093299eddba51fd668d81aed88bef0471ae",
-    "dist/2022-09-20/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "3ee6926fd5f491eecf574aba631d09d97a9332b936eb7bb0ab348ac3fa02db02",
-    "dist/2022-09-20/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "d15a8c24d04b308b91d9114b583087e2a13e75920a1837a78fe330cf6892ce4e",
-    "dist/2022-09-20/cargo-beta-x86_64-unknown-freebsd.tar.gz": "89368ca5eae65a569ae98e66834e93b240ef43a007e02e768ae9bbd5de4a4cf6",
-    "dist/2022-09-20/cargo-beta-x86_64-unknown-freebsd.tar.xz": "20b46e126c900892d576e972e39409c9009bafa4b3c159e624179d77afa912a9",
-    "dist/2022-09-20/cargo-beta-x86_64-unknown-illumos.tar.gz": "1712fd404274c993b95aa44dea6b9ff3b0f9857d8d1646e0cbf454d3386f5e32",
-    "dist/2022-09-20/cargo-beta-x86_64-unknown-illumos.tar.xz": "bd3f848d22bfa19060d459167b6154cc79070e0066f8da79587390fb92404288",
-    "dist/2022-09-20/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "0e5869b406dbaab0ef123459a93d4d6a34e85e9bd72d8a206bef69aac9e84d5c",
-    "dist/2022-09-20/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "5b0b255fb82d0e751187c6cc6b64298ca014ef86782984ef9e57a0b2ab373f24",
-    "dist/2022-09-20/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "09dcaeb783d7c57aa8c708295cf46bdcb3873a20ca30794b3c1a8797b2cc9476",
-    "dist/2022-09-20/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "918ca6c81e9e19f9d84d80e508af0050f2ec2ce2d0d0aa40cd3afd524d69917b",
-    "dist/2022-09-20/cargo-beta-x86_64-unknown-netbsd.tar.gz": "e66e3ecf93bad48573cf34ed44d508908370a8cc0c2764001cddbef022fb6e73",
-    "dist/2022-09-20/cargo-beta-x86_64-unknown-netbsd.tar.xz": "03514df0f9f2193824e227c19b84f282d7cb90145206bcfa21cf4f8223047462",
-    "dist/2022-09-20/rust-std-beta-aarch64-apple-darwin.tar.gz": "7a6a03adcf6481d90d39e929f99a50ed170e98fe61c3fae5264c3aa4d99530ca",
-    "dist/2022-09-20/rust-std-beta-aarch64-apple-darwin.tar.xz": "ccc8d4fb07a0a9c57b60d05bcf6d076a8b3cdb397930182ebfe99a2e5cd629da",
-    "dist/2022-09-20/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "3e70853d9fbc3dab4a39303b2281ad63d36a9ae2fd8d6bb7d96f184644e20531",
-    "dist/2022-09-20/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "59bb5bb6cd8d7269bfd29a952cd26280f5091fb24af4e7bf10cd59b80323d85a",
-    "dist/2022-09-20/rust-std-beta-aarch64-apple-ios.tar.gz": "da321d56c24e6c2aa326cc082912498c27231f0f0fea27ab925807108d6f329e",
-    "dist/2022-09-20/rust-std-beta-aarch64-apple-ios.tar.xz": "21e78983abd4523ac9efb0405734ebfd6c8c09b9cc89b9d052b1a58bb7ab798c",
-    "dist/2022-09-20/rust-std-beta-aarch64-fuchsia.tar.gz": "dd64a476c35b1a6aefed6bcc756cb4562a60ec0277e5661241018678d7a04268",
-    "dist/2022-09-20/rust-std-beta-aarch64-fuchsia.tar.xz": "bcbb6f3457c9b6e1c9109094536445ff208e78b5a24485af6de580ba7e279861",
-    "dist/2022-09-20/rust-std-beta-aarch64-linux-android.tar.gz": "63ab6db951f5cefbd1ab1661ffbac9749fec8d4165047dfbcb76b7dcb1468e48",
-    "dist/2022-09-20/rust-std-beta-aarch64-linux-android.tar.xz": "f3e89fe21779ecd8373280f38e29db8941c0836cba7314414d854ba685e075e4",
-    "dist/2022-09-20/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "fa187421633e7ca45948258e804fd4a8177070b9a4b964ac95231018cd5e724c",
-    "dist/2022-09-20/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "af981f04545aca6d3fe301a22773ff38077e8c8d437b862a3d7f1e8040bfaebc",
-    "dist/2022-09-20/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "22fb1351c35e4d5b12d043cdf1de51a13176fc60518fa89226f3af9dc2e727b6",
-    "dist/2022-09-20/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "690a7880a563138bbd583b537ddb80bd738d8fceb4cab083bc8bbd1fa1ee2f99",
-    "dist/2022-09-20/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "2d5135344f76decf74633d95e2fc98c416093ca962cac608564abf600ff117bc",
-    "dist/2022-09-20/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "8f63623f1e0cae99c5d1c4bb1c636fb773ed06dc1d33a251c9253278f7bc1300",
-    "dist/2022-09-20/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "105123c48c7e0946872b8ca0fcc897c2a1fcccb9b71b1805eca01e713a509c0e",
-    "dist/2022-09-20/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "9c9ec824e1db607bfac14ce8a5d1e73aeb8670e655acb4577a8f6ee783202aeb",
-    "dist/2022-09-20/rust-std-beta-aarch64-unknown-none.tar.gz": "b25fb3d1c41e193b724469898efe9d0f5d282de06d5224ae573c8870ccb5ed4d",
-    "dist/2022-09-20/rust-std-beta-aarch64-unknown-none.tar.xz": "4f87a8fc869f80072ad2a07896e50ee97b3412badeb69bb37f67ef47ff0d00d5",
-    "dist/2022-09-20/rust-std-beta-arm-linux-androideabi.tar.gz": "9ee992110e4bcf9a00bec8635cbe5bbeb241d2fb6b567060fa0507406708c8dd",
-    "dist/2022-09-20/rust-std-beta-arm-linux-androideabi.tar.xz": "aa5981a138a103843462a5a6987fcf0c7c335a5896517505d2e54fb288d7af1e",
-    "dist/2022-09-20/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "854d0d7c9932d4533d642e663ffa465741a3d0ec400a2c4b74324debaa0da27f",
-    "dist/2022-09-20/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "83b7b2dc823608777dc0e2f290fb5a2f8e6e35f4930ce2170309c14a54f136b3",
-    "dist/2022-09-20/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "9c84cc8ff79098be62011d572cd928faa4cf76c9c3e94060babc042073f3b7a1",
-    "dist/2022-09-20/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "b34a7bdd0ddac9e8b4ea8e1db8d86389c623a6629edbbd0052f890df75465fa6",
-    "dist/2022-09-20/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "49ddce546458f47683928fe341f5eacaec11c3c5a378ce8802c4b97425100905",
-    "dist/2022-09-20/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "e64130a854017b921a086749550fe92339cef0890ee645acbe23a30f5169a8ad",
-    "dist/2022-09-20/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "770bab36bd3bbc07739f0cc89c09689189edf7518e740f794be9aa7aed0917f5",
-    "dist/2022-09-20/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "b390f1111f5566b37d3f9384126a6d3dd0cdf9468dea19747394cdaae1c87c7c",
-    "dist/2022-09-20/rust-std-beta-armebv7r-none-eabi.tar.gz": "de22ffe26c7ef21d316933618b37c832353a7e5a1fb8b84af7bca98626fbc78e",
-    "dist/2022-09-20/rust-std-beta-armebv7r-none-eabi.tar.xz": "82b77c48fdb685b63bea0d40437d5dcee41500cec0360e393511b2c69d2c7381",
-    "dist/2022-09-20/rust-std-beta-armebv7r-none-eabihf.tar.gz": "94d427c65134e1e208f662acb3eb65a455016e3bed162bc4fcea9c6455e0474e",
-    "dist/2022-09-20/rust-std-beta-armebv7r-none-eabihf.tar.xz": "cdd71383ec150dbb2514a48300344a8547d7fee2c797e693cd7803354c5fca13",
-    "dist/2022-09-20/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "0241f8f9ffd00c02860158da46e20290d2ba563f93e8fa22324da2b87c347a0d",
-    "dist/2022-09-20/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "a780eb139416f2383f16fa63e72e56f0a77c67d2ac2f10f803802660e8ca30bc",
-    "dist/2022-09-20/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "1628e0c7a8cd8fb2b90db0e3d30f0d36768dbdeca640af967a14b9031d2d4c3f",
-    "dist/2022-09-20/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "4b06bbd8a0ae240bb19c93b54bd9da3bfe6c3f37a70d2b73dfcc9d1eff8fdaae",
-    "dist/2022-09-20/rust-std-beta-armv7-linux-androideabi.tar.gz": "9aaeffdd99e9dedb2bffa79adef2096ef29b48ffd2681ede2ea8d63179082f89",
-    "dist/2022-09-20/rust-std-beta-armv7-linux-androideabi.tar.xz": "d1d0ae4718eb43d4759cbe14a90b422edf0f451c8cb8624368800eff0f05c13e",
-    "dist/2022-09-20/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "5cf573ce6729200cc211924e45796a9aaf85001272a8690803944dbc91b5a2fb",
-    "dist/2022-09-20/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "51cecc72479f18c94620b2b022b89403e8ba519e36cb7a6f8c208a9ab6adb17c",
-    "dist/2022-09-20/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "c6e6962438e0a8ebdc7a7c74712d75642acfeb8c4b0753354a7d3b64da6948cc",
-    "dist/2022-09-20/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "4b812cfa63c380448b0e2ca2e03cfad73ba9951080eff1f76feaee25f67bdf39",
-    "dist/2022-09-20/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "89cdaf10019fc3ddb83ca1848adf8ac3411820a9095dc337b9a962f1e58be058",
-    "dist/2022-09-20/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "e21ac9106eae28b25270f6c1ce70e2c94273919c9c72d22f0fe3ad0b8f0a57f0",
-    "dist/2022-09-20/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "e218b7e7d148379411502023d6ede2831d76e29d5d2427d030f916a0c14c8ffa",
-    "dist/2022-09-20/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "2797698cf0f218c17eb22f43f806663723f9c89084fdc08d40adbbcde5a79f88",
-    "dist/2022-09-20/rust-std-beta-armv7a-none-eabi.tar.gz": "1d5c29d803cb8ef005baf44ca6a0b1fccc4227ab3585046f0d69cbf153be10d7",
-    "dist/2022-09-20/rust-std-beta-armv7a-none-eabi.tar.xz": "50259e9b9672baf54e176c252e9068cf020c4a79a825bafc5ee21fb46b9af815",
-    "dist/2022-09-20/rust-std-beta-armv7r-none-eabi.tar.gz": "805fc5ae72249f27ddbdd8afdc188b4f67dfe51822eb813e681259da51dbc75c",
-    "dist/2022-09-20/rust-std-beta-armv7r-none-eabi.tar.xz": "75151349dc9b6fd3b3a78d38827e517adc6935356bae0c5bc93bae62e1759db8",
-    "dist/2022-09-20/rust-std-beta-armv7r-none-eabihf.tar.gz": "ad4e0347c3e9b3f4936f26798ae2a8c502a4599c3357baf0b0a4cc3516c471bf",
-    "dist/2022-09-20/rust-std-beta-armv7r-none-eabihf.tar.xz": "4de3e5a729597473759b2db1f7e2ab633c98bb1d8125de6f458fe3bd0ee7d8c7",
-    "dist/2022-09-20/rust-std-beta-asmjs-unknown-emscripten.tar.gz": "0b3c92539f3aec14501e09db3aa02854ef98fb4dc89721306798ea163041e669",
-    "dist/2022-09-20/rust-std-beta-asmjs-unknown-emscripten.tar.xz": "26deacf11e62187673718ea8805b23dc2dd352efdedc11b396e117637a96ceae",
-    "dist/2022-09-20/rust-std-beta-i586-pc-windows-msvc.tar.gz": "a11ca7a7f67e225365423a704d7139d3c9193699493f1f193d579c126d492475",
-    "dist/2022-09-20/rust-std-beta-i586-pc-windows-msvc.tar.xz": "08d8aad1d608d2ff626f4e7e4300a31fc3f96c0ef1e5bd0ec179b98d4194fca9",
-    "dist/2022-09-20/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "3524e1ba92b9ccd1fcfd40a6018efa697d63177cc0a8c9cd016be833aff371f4",
-    "dist/2022-09-20/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "a6df83285ba5732eca9adf3f39d0a4087249b29cd0c33ee2272f68930df43191",
-    "dist/2022-09-20/rust-std-beta-i586-unknown-linux-musl.tar.gz": "6951d7aecd555a0dc485f57ad16703af65315c464aebcf73171bbda2273dba0a",
-    "dist/2022-09-20/rust-std-beta-i586-unknown-linux-musl.tar.xz": "f07c4a267740e46a4013b130e9d1e10492e45dc0226a08f5c909076ade466737",
-    "dist/2022-09-20/rust-std-beta-i686-linux-android.tar.gz": "dd47fbd29b3b025388352fafe693f25e43c1287f69c2185fecfb0d60e13a7fc3",
-    "dist/2022-09-20/rust-std-beta-i686-linux-android.tar.xz": "0eebd41330762a4bad438c40f134601e59a7b73043952b2e090a801adff41727",
-    "dist/2022-09-20/rust-std-beta-i686-pc-windows-gnu.tar.gz": "58cd47de74c201bfed62a8980c2447f97e7c129726d3d28c2140d880fa6d7975",
-    "dist/2022-09-20/rust-std-beta-i686-pc-windows-gnu.tar.xz": "7fd68f0f9eea4d8256132af2f2c269c58a278b757888e591716a553b87ffcf8c",
-    "dist/2022-09-20/rust-std-beta-i686-pc-windows-msvc.tar.gz": "816ef343a7ed908706d8f4e7cb915787a4e27c2390cc7c3f6e2210f3ad7c4cda",
-    "dist/2022-09-20/rust-std-beta-i686-pc-windows-msvc.tar.xz": "2475326f3d32e8ae309750c1639cdc6cce3474fb5d4820b31b46c9c12401b63e",
-    "dist/2022-09-20/rust-std-beta-i686-unknown-freebsd.tar.gz": "24a897b9916bcd4ad775d96f9751b06663eed599086d0665b83dd4c16af871ab",
-    "dist/2022-09-20/rust-std-beta-i686-unknown-freebsd.tar.xz": "959725ac2f49d1944c53846d920ab4e8769976d4025bc32bc63e5372b751a8de",
-    "dist/2022-09-20/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "35eb28ff2d3b383ac1b34bf6eded87f824ef93eb2c2d12c300b136c7c735ced7",
-    "dist/2022-09-20/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "31085015fbfa608e6d0828a367d84b48679c6a33d55ae32affe37307818b1086",
-    "dist/2022-09-20/rust-std-beta-i686-unknown-linux-musl.tar.gz": "ef294d01caeba013cc3173b5fab5daac4f0c64e57410f778f2891dff03f23875",
-    "dist/2022-09-20/rust-std-beta-i686-unknown-linux-musl.tar.xz": "4ad7915a9e54f7d911864adbc097941a9c051e0c97c8eee1c04158a5755e4e4a",
-    "dist/2022-09-20/rust-std-beta-mips-unknown-linux-gnu.tar.gz": "cd8e8fe2af17def5bf19a8a0993317af5c33833de850a489ef2dee54c61dbca7",
-    "dist/2022-09-20/rust-std-beta-mips-unknown-linux-gnu.tar.xz": "f2f95555e3564f7b16bcde9ae4c6a30752900519fba68304c4f74b7e508bacc3",
-    "dist/2022-09-20/rust-std-beta-mips-unknown-linux-musl.tar.gz": "7d42b6d7f028c637f7f9a2f0c14fde880e00098bf4141289620232a263fa8eb0",
-    "dist/2022-09-20/rust-std-beta-mips-unknown-linux-musl.tar.xz": "50dc97ba9ce28d4252f03f78e23bc05a702d5c1c5ad67b70a358406419f25721",
-    "dist/2022-09-20/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.gz": "7c14decb2404c616319c99415f65c1383264151f3802ffedfdff4962db310828",
-    "dist/2022-09-20/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.xz": "230849a3b6dff89671bf94c73391eee43107c81ff65c795eb1c9f30b9bb52176",
-    "dist/2022-09-20/rust-std-beta-mips64-unknown-linux-muslabi64.tar.gz": "0a63c8f568d9ef12b75b9bcd53faf727bc029b4a1268c53fef913e58be94eff7",
-    "dist/2022-09-20/rust-std-beta-mips64-unknown-linux-muslabi64.tar.xz": "5b1020d65f651cd1778448618bca55906eef981842b73c18be1b5ec785d6bf06",
-    "dist/2022-09-20/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "3f747d83397942c88ad79a7bde1f98a57d0b416620f08ab57edb64f3b101f493",
-    "dist/2022-09-20/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "babdc0c87bdc8146fc6645da34776be98575019eacb95529c00060f8afcbb1f4",
-    "dist/2022-09-20/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.gz": "f0bc0b5fddf7ff8251fefa4068fdb623b47bbd1e81c2c732ce2304e4ce78bb20",
-    "dist/2022-09-20/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.xz": "33e3cc3766f941f3668a93240d627c7357b22a13facff5937821d92a21afe444",
-    "dist/2022-09-20/rust-std-beta-mipsel-unknown-linux-gnu.tar.gz": "33ae5fdfab257ddb004eb80ff1a8d0351675df06b97951d5c47071ac8b18ba9a",
-    "dist/2022-09-20/rust-std-beta-mipsel-unknown-linux-gnu.tar.xz": "9f16e21c54944afe83a5e1a3e489a2dcad947f367cbb17c6ffcfd2c503e03f25",
-    "dist/2022-09-20/rust-std-beta-mipsel-unknown-linux-musl.tar.gz": "065f8929bef2ff2ec0067c788fe64e0a08af0f5e11ac5d67e29e5225557d6d9a",
-    "dist/2022-09-20/rust-std-beta-mipsel-unknown-linux-musl.tar.xz": "c3c54ba9dfee447e33d76ba8060bb9b6081103fa6809ad77c3221ea064ed3fc8",
-    "dist/2022-09-20/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "5627e25a24792131e8c0a1c605908bd56ab5a55614b8e17c23233fdc14d25e81",
-    "dist/2022-09-20/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "3ee1b5228665f2d5d7ac500d6fa6a2d0fd771eaafb5c393419713a11bf8d0875",
-    "dist/2022-09-20/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "cbf922bba400e798cd32e5404a804400f79ed03ba5cc433173eac96ba9e06976",
-    "dist/2022-09-20/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "bc573b0012568f0bf397870660f7527697b1c65e1a7387d2419c6f63ba001bdd",
-    "dist/2022-09-20/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "917b948988edd4e5c5e441102f55b1541318d47c0cd5d958a69ddc6fbfda84d1",
-    "dist/2022-09-20/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "23e45711ce82b6baf9d27d909d8fe4bc6a5f32c91dfbc280708abfe5c362bc89",
-    "dist/2022-09-20/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "448710ce6f3e72d0831ae882fa37196685a28dacb6f0f499370fc2882427044f",
-    "dist/2022-09-20/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "831bc2bcb21ab9fe82fc64eb377d6d80b47198dc82677b7bd630d89819914e20",
-    "dist/2022-09-20/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "14a61cc3d6740a9033c6570264e6c9356120235f42e5ded8ebec1d592f17b47f",
-    "dist/2022-09-20/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "c73aa37081b4248324a459b48378b4a412a3561a12bad3ae064c8336ec862dd6",
-    "dist/2022-09-20/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "f78a367b9977471dae06fffd6049f03585e826fe648a2d1d8ee20ff19dfc913f",
-    "dist/2022-09-20/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "e8ef0dfd9d7df08fcdb7136619d8b9cd31435e0de130f87c799117dba9614a54",
-    "dist/2022-09-20/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "a7cd118c91f4de3a1e1c5d9326080bf39661f708c675272cf697ab9675001705",
-    "dist/2022-09-20/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "58023f2bd169455d97537aca228749e9a980e18d72f67ae8c0caff4ad2d4fd64",
-    "dist/2022-09-20/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "726efb0f7cbac9d13deac41d0937ce5f707d8e858b3bf9096c40fd41b2663d4a",
-    "dist/2022-09-20/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "73395ddaa22a91a1de120704f22d86b0624de52af773755046ec809b76b88954",
-    "dist/2022-09-20/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "2504e53a04ab1360309dd9e733798a94fa3a92cc575148073dc4870bb26367e9",
-    "dist/2022-09-20/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "f182ac3b6222a333d73f3f612fb31f9d19d4e03456e16b0967cb55d1292ec05a",
-    "dist/2022-09-20/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "9612105b0d40225d54f6b02bcf75e0d7d232331fa22a24de4895f97519dfd6a6",
-    "dist/2022-09-20/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "448b0cd5cc35096e0fd51a7cb1948e87b7c46eafe665dbfda802a4947e08665a",
-    "dist/2022-09-20/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "72459d840371f7203e15622a82ccb5e3559db52934445943fc41b11a58b07302",
-    "dist/2022-09-20/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "39ca5b49d6e909c81deb8c7391e01da9ef51cabea55fa55dc16cf654abb089a1",
-    "dist/2022-09-20/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "ff74af39ca1446f06f891beb22f1e24fb0b450d97c889dc2e27e0f53fc19b26f",
-    "dist/2022-09-20/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "f56aa4d390eb4b25aa51685ee773b589ebc87bbed7495a07d8af0d3b3cc7c715",
-    "dist/2022-09-20/rust-std-beta-sparcv9-sun-solaris.tar.gz": "df727ef09f0549051ff5b4fcd04cb22d4244cea85f97e43880e563c45b558cd6",
-    "dist/2022-09-20/rust-std-beta-sparcv9-sun-solaris.tar.xz": "f575d16acc0a8cc5b96e038d828ac023c302e38efed271d5101a885d3af35cfc",
-    "dist/2022-09-20/rust-std-beta-thumbv6m-none-eabi.tar.gz": "838be75f56d84d88ab01b0897d9b166b6ea26c527705df2d2a7368968439505f",
-    "dist/2022-09-20/rust-std-beta-thumbv6m-none-eabi.tar.xz": "b5b33e2de72e71ef5024fb50f0f6e91f32b4747f666aa7069e695b15119a1963",
-    "dist/2022-09-20/rust-std-beta-thumbv7em-none-eabi.tar.gz": "dbaffcc17215c4342a40c049a9538be44837bcf86a7d65fb2c877f831beca337",
-    "dist/2022-09-20/rust-std-beta-thumbv7em-none-eabi.tar.xz": "14fabdf3f4cda3bdb3ac139c95d31c2a20e3a88cd9f83e803f9c9bd6e3f9f83a",
-    "dist/2022-09-20/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "3acc833a086a9b46db81cbf03fcf2dc366a4b3d32eaeedcc2deee8ceea31449a",
-    "dist/2022-09-20/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "f6cf227b6da03855f1624bb325bd802b8ae6b15d7bbfbfbf8b9de1a74aedb6fe",
-    "dist/2022-09-20/rust-std-beta-thumbv7m-none-eabi.tar.gz": "e5054ca1e295709654b214847691f4fa9f031104725632dc056853382e74e733",
-    "dist/2022-09-20/rust-std-beta-thumbv7m-none-eabi.tar.xz": "b44f0462a5f44e762653fecd816dcd5ba5a2f9d8dd3efcec259b250f3af5237d",
-    "dist/2022-09-20/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "4fb8000ce077d346d85005343284f56ae936eac334c72cb8c170dbe810aad740",
-    "dist/2022-09-20/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "77955483882897980f4365bdc71fca9f39d675ff210519702b9cf3f2a6bcc2a8",
-    "dist/2022-09-20/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "566b9ea01182e6c7e3844911ed08fe5eb1d848c3de89d4f123d80fd70ff37ddd",
-    "dist/2022-09-20/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "33cc9c12d909bd4166be8570e27da8c1884ac1ce82d9548e16d926d9885ff62d",
-    "dist/2022-09-20/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "62a345ea2aa55b1a02053e7c49988c5f14d6b90d487b9c4916e40ad31957d1f5",
-    "dist/2022-09-20/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "37fd80af2188d837e870d3c8399767be15070344fc87d2b37b5126095252afc5",
-    "dist/2022-09-20/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "32a10d7eaaf2189d74700187fbc8c2ebde08b5efa06440c2b4f65fb85eac3ecc",
-    "dist/2022-09-20/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "dae8d6deecc5277be729803ed55dc134c1ef5bae49fa0fe7ea4f0eee9d7d19fb",
-    "dist/2022-09-20/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "44457f84d46ccd201771cdae9520caebf813d3283b08f73fabab59b52b485a98",
-    "dist/2022-09-20/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "1e5bcc82a403c1c4c5fa41fa78de9aa4378a2901e3170d9542eb3b21d130e36a",
-    "dist/2022-09-20/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "b7d31d0ec6fd1355d1323555ec8d1cb4b9f30bab32a75d0d8efaf465ab2aedcc",
-    "dist/2022-09-20/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "a25b5c180ca97d074d563c6fe1d826db23eba9212d12cb3d60d39b7841a5618d",
-    "dist/2022-09-20/rust-std-beta-wasm32-unknown-unknown.tar.gz": "31aeed83d12732c40e51cf59a3dd8dd1fe7ba2ed047cab65f8bfca8c72d158ed",
-    "dist/2022-09-20/rust-std-beta-wasm32-unknown-unknown.tar.xz": "28757fc2c5304b3110b2358d252fb4aaa8d811999bd9881e118bc71b0e6b01a3",
-    "dist/2022-09-20/rust-std-beta-wasm32-wasi.tar.gz": "b69ecad8480c2d33b854ba3387a0563df53546b8a2b55639fa20d1c104f35050",
-    "dist/2022-09-20/rust-std-beta-wasm32-wasi.tar.xz": "a09185a76891928cc65e4139373df6f22fd0060388ccc4530cc0be5310f8aaa7",
-    "dist/2022-09-20/rust-std-beta-x86_64-apple-darwin.tar.gz": "97f5a3dd01a7b5efe44662f2376826c184d212754c730bfaa21cd03235676142",
-    "dist/2022-09-20/rust-std-beta-x86_64-apple-darwin.tar.xz": "131b37e9d3c2335fb51427a7e0ab43362efccf90a4e001ef52e54aa221634eb8",
-    "dist/2022-09-20/rust-std-beta-x86_64-apple-ios.tar.gz": "d900fc396731c95a57d43519a109202cd2ed8e574df300cd6124c6390d1584a3",
-    "dist/2022-09-20/rust-std-beta-x86_64-apple-ios.tar.xz": "694dc51239481fe8f5ec2291b62435e0a7622591f2709ea4709749c7d8c01db3",
-    "dist/2022-09-20/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "c2fad6b25e33e4e52fab6d20b6e1bbf78f230e9b387f260b48f940bff67386f5",
-    "dist/2022-09-20/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "c3fe305a1082cbf1f5bbdaab5a94c0ad88037a4f99e556cf06ff1270a806f437",
-    "dist/2022-09-20/rust-std-beta-x86_64-fuchsia.tar.gz": "75b5aaf5206953d16a418c83f6e6d21a0adcbb0c81b5c1a8f467f3e5aa33c038",
-    "dist/2022-09-20/rust-std-beta-x86_64-fuchsia.tar.xz": "7fc38dbfb7833e9b6336f4aa38706a92e1922231ee875100e16274c571110757",
-    "dist/2022-09-20/rust-std-beta-x86_64-linux-android.tar.gz": "bc4a42ffc51bc3be27907a73de98fe4c8cf3b205fd1e7c75a9cb3bd30bcc5fbb",
-    "dist/2022-09-20/rust-std-beta-x86_64-linux-android.tar.xz": "68e02875090c7d382e8b21d0102712e7c9d583d657b6c51b4f939e3a9b7f884c",
-    "dist/2022-09-20/rust-std-beta-x86_64-pc-solaris.tar.gz": "11edbb1de67f00263f31635bdf006966143aa18423f574cb64ef966301a0fe3a",
-    "dist/2022-09-20/rust-std-beta-x86_64-pc-solaris.tar.xz": "44743e8f113e3e5bc7ce66902533f6ac59538f8f61fa6ab6c311bbf2ebe75e43",
-    "dist/2022-09-20/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "a705945830b23a25f272600470d687a1a9f5d4f8a01c5fed9e495a444b2aa9ee",
-    "dist/2022-09-20/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "9e4a045a2e0f754ec6afd897f1bcb66bccfc2b5bb91f141fa8d3d47723eb6090",
-    "dist/2022-09-20/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "910de4547c1112170b0981fecfc926cff4c47cc622648b83fea9f79c171cb05a",
-    "dist/2022-09-20/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "f9be82ac8c5f64c17cfbf0270b8f71ec71e6b3ba7c9521980a73d6f848f6014c",
-    "dist/2022-09-20/rust-std-beta-x86_64-sun-solaris.tar.gz": "e1097c0bd31baa61902be4a8a47a674faa15466ce9352213cf7808f50d5854ff",
-    "dist/2022-09-20/rust-std-beta-x86_64-sun-solaris.tar.xz": "82866dc52808549acd683d5b7c47fe97c992ea70cb6fff941007960a25f3b645",
-    "dist/2022-09-20/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "2b7c60a6b830d557a6df8865bc8dd658c84037a5893b11db8e11dadb527b5d6f",
-    "dist/2022-09-20/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "14787b285c55ab885d1360897849882eac861f36029cc72ec9819d035998ee9f",
-    "dist/2022-09-20/rust-std-beta-x86_64-unknown-illumos.tar.gz": "4bfdf27eb12af6c4df132603a111ae26f4d06846af366a38e594e66c092373d5",
-    "dist/2022-09-20/rust-std-beta-x86_64-unknown-illumos.tar.xz": "66b602046eaa83cf2b69bc75af4dd11dbc5d0c6878537d0af451d17121fdbbe9",
-    "dist/2022-09-20/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "78d12361e71630978928896a63e6cf7e3e866c09de761029b4e8e959850ac025",
-    "dist/2022-09-20/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "d55f9cb4a8c47fc5d0123cedf622b94b33f57a59022129e31f451e1b80f1815e",
-    "dist/2022-09-20/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "74bbecb0f35ad8a1aae65fb09ef21e38bfbe6d5b4c6b1d741832eb8f40eb4b1f",
-    "dist/2022-09-20/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "135f19e88ac0fb7ed02072c82a17f0d12abaf40055efd0a6b43bbbbc9c4445cd",
-    "dist/2022-09-20/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "0b3abb866d7b82bc5add9fa01d59b9223d2124d69dfd78a13a4dfcc17196f510",
-    "dist/2022-09-20/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "ec5989076c015e5b7d1a307ecb19f2ed12df7b5e2836d3b410f3743f9066683d",
-    "dist/2022-09-20/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "1e236c2ad7aa296aa389751ce64d1cecf86053d23126e1211da71674603e6900",
-    "dist/2022-09-20/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "de43876b381f7b91f7a8e1d1df5b92a3d60b22a62333f9a645f3e6055e91be3b",
-    "dist/2022-09-20/rust-std-beta-x86_64-unknown-none.tar.gz": "568e95b842c3d8f9f733fc3b5b59a8c673d200b4d16d5db36ce24ee355e18c1d",
-    "dist/2022-09-20/rust-std-beta-x86_64-unknown-none.tar.xz": "557727f83c7998b9349bb2c05f5ac5fcb2f0bef28e55f27b165fb7a2d9347396",
-    "dist/2022-09-20/rust-std-beta-x86_64-unknown-redox.tar.gz": "e3c00ab70a0a69a9567bc525cc283318186521a6d57ccf4a42e2eb640ed50ce6",
-    "dist/2022-09-20/rust-std-beta-x86_64-unknown-redox.tar.xz": "757f2208edb49f23adf702a34b093551f0e193f6a6cd8c24b2cf4f199f77b2dd",
-    "dist/2022-09-20/rustc-beta-aarch64-apple-darwin.tar.gz": "a036bf0b4d0c8ab907ef2cb8cf8eacff41f7b82d519a2988a529c3d926539ee8",
-    "dist/2022-09-20/rustc-beta-aarch64-apple-darwin.tar.xz": "3c49210d4b867cefb4050507104b2672fc70e15f42615ced22469831b34b3267",
-    "dist/2022-09-20/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "21fefdaa0b70d7f4839751926ce102e19164a373e4d310c0f0b3655f3adbff47",
-    "dist/2022-09-20/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "7c88775b4efbb2416deb2b0d9ba86d5178d34059b18165b276658973f29d5971",
-    "dist/2022-09-20/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "99e30eb1612fd18b42a1b89602f448788ddcbbac2430577fc963a2c0c4708c55",
-    "dist/2022-09-20/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "385eaeb8f260a187ef828904e5267551062210543614dbf98d1c1e392853b913",
-    "dist/2022-09-20/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "8f3b377a74c586cc8f7cc165eac0794bec560e04c885ae552af4e5cf42490a1b",
-    "dist/2022-09-20/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "2fb2add792a9377cbe86aaedec389d023c35343ef801a97a2392f323e92c386f",
-    "dist/2022-09-20/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "658ec925f51b2a5da9ab8cb193c33c05cc294915d8c0c5a2e93f9ade383375df",
-    "dist/2022-09-20/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "75d19b64530691739654763b89468a7101457d638da04e25f549078594b67b68",
-    "dist/2022-09-20/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "c167fb9f352fed99d427094a5c2b96da0486f30ccb4188756def7c232083319a",
-    "dist/2022-09-20/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "ec1c19536b6fc3020ccfff727bddc934f89da0592797d49bf7149e96f7175451",
-    "dist/2022-09-20/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "05c5e668d5b40db5cd18b21192d8f0f1401d2304f715eff08ff49c3c97d740dc",
-    "dist/2022-09-20/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "ad620c5de3ae9a0b30b3c49dc89bfcd08a061da01f004a724ad5400efd4a7189",
-    "dist/2022-09-20/rustc-beta-i686-pc-windows-gnu.tar.gz": "2be9e0f5fe27b7085f65d32cb20875392bdcb177c582c58d1df842b316dcb9c5",
-    "dist/2022-09-20/rustc-beta-i686-pc-windows-gnu.tar.xz": "5841c0f4558d24ccd0c4e6996e399fe3ff13d5d1ffb2bda38bab6d60020fa649",
-    "dist/2022-09-20/rustc-beta-i686-pc-windows-msvc.tar.gz": "a19c5330c111ad4b19a724b22dc3381eb9f05a85bf9299dd13eefabbf6499504",
-    "dist/2022-09-20/rustc-beta-i686-pc-windows-msvc.tar.xz": "902811dec71e36989af12c8dc15b79759e5cf4e2250841bad2b9db2eb94195a1",
-    "dist/2022-09-20/rustc-beta-i686-unknown-linux-gnu.tar.gz": "36474bb89e67bc867cb7a4a5101d00be221d7a8b6a625535a5b2a74f505d5af4",
-    "dist/2022-09-20/rustc-beta-i686-unknown-linux-gnu.tar.xz": "4329562f89817b02e3eac219ad3051d9de5fab89e0678d91378c02a90fea7d59",
-    "dist/2022-09-20/rustc-beta-mips-unknown-linux-gnu.tar.gz": "bb7f5c8abc99d07a337eaeb3c1dc3861a4f148c364f58b039886f43abf6a7d01",
-    "dist/2022-09-20/rustc-beta-mips-unknown-linux-gnu.tar.xz": "0b02a4d1aac7c9d4b38fd760937020975e5de209ad23b7285cceae7992449d47",
-    "dist/2022-09-20/rustc-beta-mips64-unknown-linux-gnuabi64.tar.gz": "7ceae3da1fb1f865df3315ca450ec3cb4657086dd61c7a47879f98188aa38100",
-    "dist/2022-09-20/rustc-beta-mips64-unknown-linux-gnuabi64.tar.xz": "5a5273ed85d3012b8067dbc3e93f1af105e4cd80ed8055daade24f43dfb41977",
-    "dist/2022-09-20/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "dbd12a141765f29be2a602531db7f9a02bc32617635448f602befc90f1a574c3",
-    "dist/2022-09-20/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "e3abf34a09040149f8725ed1fca6e9c412c4cf290f9424541a819f0e2aa363b2",
-    "dist/2022-09-20/rustc-beta-mipsel-unknown-linux-gnu.tar.gz": "e13b7057525302dc3585a71461aa022ea0c059c0b0069fec44f86549eea94d18",
-    "dist/2022-09-20/rustc-beta-mipsel-unknown-linux-gnu.tar.xz": "b7bedce1d0ce44b4014e10122201c10443c0e8ced80084a6ebf1add1dbd3236f",
-    "dist/2022-09-20/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "fa738ae0d068e85044d2fce10f6a8bebe7b608630b9b7a822b2d7b84c6c59002",
-    "dist/2022-09-20/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "b53d773465368d9484cd36063d7ff202c1ca8d18422b4f6727cba54beb88f4bf",
-    "dist/2022-09-20/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "9fad6a7ae30e5ccb4f0779ffdd117f6cb30e6c5f6efd5247c208f9ee3296a27f",
-    "dist/2022-09-20/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "e8a92259aa371d350dc29171467c3e99fc178b636343ca82188c7b602a39ab58",
-    "dist/2022-09-20/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "5b64e0924a705e267177c8d80970f510487de350dda47cbc9bb758ec1b212a17",
-    "dist/2022-09-20/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "f6ca5a88f0ea25521e1135100cc7404547ffbbc4422b3c9a06177c94d7871ef4",
-    "dist/2022-09-20/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "8db27ac2a1b8322f529428ee7278347263a9ff71101d37bfb04056137f63de78",
-    "dist/2022-09-20/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "2475866ff4afe38755a27ffde9c09302066d0c936a4778883fee9a37c1b59f31",
-    "dist/2022-09-20/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "4cd81c652fd3e59cbdd42872f2e37bdcc1fa61a550eb8ffed7783e7ad3350577",
-    "dist/2022-09-20/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "1f8529e51192433d1a281484072f94d910ff81161efef230e6a2be82765f6f26",
-    "dist/2022-09-20/rustc-beta-x86_64-apple-darwin.tar.gz": "430311100511fe9fe176f01030b78fa8160840bf4d9b4ed798a2a7fe089b4f7c",
-    "dist/2022-09-20/rustc-beta-x86_64-apple-darwin.tar.xz": "57be1bb1dc7d7d0f0479d11e36d6315a9d19eb0102610b7f1dbd5151fe6ff5c2",
-    "dist/2022-09-20/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "826f3f6839c4e18e6d58a32de8f067bb57be2fb2c6cdf74f55d55ef76f5c5e21",
-    "dist/2022-09-20/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "5f8b9704071e6b372a5c67a29bcb9ba5978ffdedd62e057680aaba17dfc91ba1",
-    "dist/2022-09-20/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "06a29a85bfce9981504f1630c5f3ea86171948080a93d8dadb4a306dd678af80",
-    "dist/2022-09-20/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "36c2944aa3db18dfa1632c7b52c67e6bad9effb03960af8cbf82fdf32924019b",
-    "dist/2022-09-20/rustc-beta-x86_64-unknown-freebsd.tar.gz": "c20829efb9888d8097c9f5f472598b06868bf918a9d033d4b6fd031323878492",
-    "dist/2022-09-20/rustc-beta-x86_64-unknown-freebsd.tar.xz": "515b35360865016b7efe6f973730ce4c66021df0edeed8eb490b69f4bf50006d",
-    "dist/2022-09-20/rustc-beta-x86_64-unknown-illumos.tar.gz": "e63231ee48425687c97c654faba961a1b12379696459f284b6a4ea7ea52fb2af",
-    "dist/2022-09-20/rustc-beta-x86_64-unknown-illumos.tar.xz": "fae9048709741bcd21f4dc2ad8119576ba8dbe6b6442e79a443c207a4c52cc47",
-    "dist/2022-09-20/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "3785a8837c6fdf230b79992e4a3fd6a8b6faa269461bf908e427ffbd59728adb",
-    "dist/2022-09-20/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "a238209d54c2f9fea99a18bf43c4c0ae9bbc9cb10075e63d77af131728d64892",
-    "dist/2022-09-20/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "520ba16bf1b892f5c3d3fd6c1ba695ff48e0babd4ed5be97615887589e60c204",
-    "dist/2022-09-20/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "4251abe5dde29e9d2ffd7560e7f8eeb5c1b4ad6078b27896f63fcad5db6dabeb",
-    "dist/2022-09-20/rustc-beta-x86_64-unknown-netbsd.tar.gz": "ccdde196a376d8f06d3457a1b6d85b4b3692acc9e4bd055fb93dcb217ecd4494",
-    "dist/2022-09-20/rustc-beta-x86_64-unknown-netbsd.tar.xz": "22f5defadc7b4b4231315b420b6ee102c188a03381580feb7e22b75e16661017",
-    "dist/2022-09-20/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "8fead022ff05d4112e4cf7e637a459651dc793d9c38f1e823437f6c0c1bf6791",
-    "dist/2022-09-20/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "5e5f06c2c7a0567bb096b676ecde4bc87cd56c1a60d5e99feb0ac0b679280e1a",
-    "dist/2022-09-20/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "f365e910e58e962526bc2ffc01b47ea7b99b2be199baeed82e3bb0609147994b",
-    "dist/2022-09-20/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "3e8a10a285b3c248691e20090d2805d0aabdfc0555a5463bc472899fba085759",
-    "dist/2022-09-20/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "4316414f83c30535f0c46efba5fd011755f4afa6cc3440b39e8ec154ae451b69",
-    "dist/2022-09-20/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "f3bf1d0198db6efb751fd61d096615d09dec94a2732b028728d74a3513e9bc47",
-    "dist/2022-09-20/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "d0f4c30d1ed5144ce0a2931290cb730efa5616375ff846692faba0f04b2fed4a",
-    "dist/2022-09-20/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "3c20a791400f994ea5ae681700e9bd1773b9203821a5458448a038b70fe98794",
-    "dist/2022-09-20/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "587eabfb4ab41ec7fc1f344f8d8674feb1787cb402dbc10754c43eb9352233f6",
-    "dist/2022-09-20/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "0f5c05ce846c42f4afd9127fa5bc0af070e7a03911ed93630177d6304ec66fe9",
-    "dist/2022-09-20/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "dfcab7b0d9b93e1ce639a7a1b9774a41e1e70b67fb91814393531476e7ff6d97",
-    "dist/2022-09-20/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "aa66edb8208b73e3dc939ce82afb78b9104022427fc2278a50ca004c54b1fd5e",
-    "dist/2022-09-20/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "9d31be70cf5aa67219bf85e303651b928e89f54831a14ad004ef606291206991",
-    "dist/2022-09-20/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "8b1249489bbf015af1865ddeb83560fbbc52ca84937e14a2ae928eb4fa854322",
-    "dist/2022-09-20/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "4154363e7fc7888088ba020c7454a2e0ea75a64e01532ccc709dba3a16c48d78",
-    "dist/2022-09-20/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "48ba35bdfe87b78428fde9b7ff6fbd7682d7f94113b874e8308bd3c5e734154c",
-    "dist/2022-09-20/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "bf42294f1c3053b8ff6dcf13219056a5e83fb0680e5e53621c626f825f2f11c6",
-    "dist/2022-09-20/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "a08b27ac0b47af60618f07d884320e80665eab550536e19828b5fe139a59499d",
-    "dist/2022-09-20/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "748c42c63c3363d820b132a96bd95cd5203c5f808fb4885710065b9c609ae183",
-    "dist/2022-09-20/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "a2bfe3e12d0ecb5881a749a3d11652d45efcd9ee3647ea7c6b6cbc94071e34e4",
-    "dist/2022-09-20/rustfmt-nightly-mips-unknown-linux-gnu.tar.gz": "a26f46c9d777ca55db8ef595219aea45c3ff7547ee7cfe07d01b9535dc00e1dd",
-    "dist/2022-09-20/rustfmt-nightly-mips-unknown-linux-gnu.tar.xz": "d3ba043430fb0177023d4028c90a797d9b469d4c2fb2c539bb52e2dd070723cb",
-    "dist/2022-09-20/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "1f7b83d238dcd63de150d5fe457b8c04347626a583f049cac7989644787c2432",
-    "dist/2022-09-20/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "25f682b00e0362c16cb8d9879854d0a9781dd7a1e0f980a0c5064fad3764e8ef",
-    "dist/2022-09-20/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "09aaccf92485ad1d69623410f947b264835236d20472f974e348015bb8d2353f",
-    "dist/2022-09-20/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "cff865ff4979885f158af7b437ebe67ea2645489a6067abd97eeaa97b57041d8",
-    "dist/2022-09-20/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.gz": "1ca400758f5e44fa8ed01d8fc6d5622259cde42597fe80dc5e0e1b4129270c77",
-    "dist/2022-09-20/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.xz": "bd71382043ea4e934640a60660169d8785af453415d88945066bd6b8a42b0099",
-    "dist/2022-09-20/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "86feeca2cb543476419583bc1b10dbf8d91afd25ac77a9f04f789aff4f34e3e6",
-    "dist/2022-09-20/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "2ce655da2899200f9e4a331a45f005f4faea11cfdf5b74397a68d376dab88bf9",
-    "dist/2022-09-20/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "ed7e14c85bb1dd2900991775e812c56a76891a70dbea013bff06f73e7d1beaba",
-    "dist/2022-09-20/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "09710d4622fd7a9695d3907be6433c69f2ff590415fab776a05ba74ea5be63a9",
-    "dist/2022-09-20/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "02da320a5aac0eaffa83cd49b37d0cbcecab7686cef166f30dd5ed02fa9cb023",
-    "dist/2022-09-20/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "1f4465079a5493ec23f433cae4af3f633885b38f6ba7693387ccd355010b955e",
-    "dist/2022-09-20/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "a9a3bdba43897b0ab44c54537ce80fc969c378480348af715e293403b55b83be",
-    "dist/2022-09-20/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "2d58863182dac199cde47e12d3d92a64b5d068afc7e97e1047ae8b369fbe6df9",
-    "dist/2022-09-20/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "002667d802f1ff1224318c2090caaa3eefd18dabd1bcd40ad957b0c09acd047a",
-    "dist/2022-09-20/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "a34aa6451cf5faf985967ec5df78a41b21ae317bba7f8836e09f87571a7f9c16",
-    "dist/2022-09-20/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "8950773a8433fcc68f16c1e07210c3cf07c9e9240df92b0a90c67ca285d932f8",
-    "dist/2022-09-20/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "1ce5bb4a0a3490f95037a1512f4b5539c65bfdc5d7f6d42005019345bedb71e8",
-    "dist/2022-09-20/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "cdbef502285d5eec5788299354f391a2263858d630466cd1cc6d48748aefb1af",
-    "dist/2022-09-20/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "d5e04d0abda5e8ec429794a58f6404a6b95cc66cb218a52299c3bfaf1ec35485",
-    "dist/2022-09-20/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "d1ec51e70918e4f50463839eb86528582424d69eecc6af5cd07987621acc713e",
-    "dist/2022-09-20/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "64a108e60c1ff0e1c004d63e13a8180e5b266382e8434aa94eaff3c654158e51",
-    "dist/2022-09-20/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "d439ce2780177b3123de9a4c6727ea19831a215d19363d12b0bcc3bc19fc5074",
-    "dist/2022-09-20/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "851adf8da102068b4195a78ba587e168b7c4471b5a2e66451385a503362d091d",
-    "dist/2022-09-20/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "7bad988696f60f49c0ab1929f8cfe843effaa455ab1d20b002dadd1e10bc4ded",
-    "dist/2022-09-20/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "8bee32774f9af0b6f382640592b65d4187401a59bd3bea4a139e2dc43471bc0c",
-    "dist/2022-09-20/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "16a3ff01a6bc471da2195c7e8d0a6623b911d956db388b66e39096a7c81ae1d4",
-    "dist/2022-09-20/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "721115ea0ec7902f74d203eaadc71c79c4489caf9a23b0a81c513fddce5fb9b2",
-    "dist/2022-09-20/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "9042aba5f18ef575cff2e106c34b707d8fe013f4140e4a066ce80f2103563809",
-    "dist/2022-09-20/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "9106ee07a9f173ae845ae2b5ce30798e15deffd46149430ec5aacceaed7848b8",
-    "dist/2022-09-20/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "9acb78526c40efdfa0087373d802b30b75238e4c46e0bb18262e16416be49b4b",
-    "dist/2022-09-20/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "c7a73c5b9034417998800dabb08ba71e12713a299457381a4437ea454cead1bd"
+    "dist/2022-11-01/cargo-beta-aarch64-apple-darwin.tar.gz": "ebc0b11a2af0385bf11a5183dc159d890161be45d231acc34c6326aa25b84b95",
+    "dist/2022-11-01/cargo-beta-aarch64-apple-darwin.tar.xz": "a0e44bf77337518e2200c34cb297a91dd4db51f0d331ca4cc496989da61676b3",
+    "dist/2022-11-01/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "a4beae1c53df4d35fe991ebc713e37246d4d89e5543ec740274605a7124806b3",
+    "dist/2022-11-01/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "5f8ec5c8b012d7e6bc28ca3d700c1c7c742f6532adb044539cee3b2280c1056c",
+    "dist/2022-11-01/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "54d8fc5ce70b1f06164e17e34d33abde7260c6b1f3356d98d77271ec89766fb1",
+    "dist/2022-11-01/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "f2debb6ae264fefc49380997759bb0b5022ac1c65ced9bc17bc146671be37116",
+    "dist/2022-11-01/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "7a8e10be17c8cd624fb3ae2bb7eaab3c493b637c2c1c1100b5333982d1dfd962",
+    "dist/2022-11-01/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "553decfc64b56d9967ae067bc942ef7117c81d6976b5fa4cf8e5171397836af7",
+    "dist/2022-11-01/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "64bdb603cdc05b983393d707e9e6e6cd1c71dd8213d08b3d0d1cdf168ceb165b",
+    "dist/2022-11-01/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "0afe4ca54c65668257dcad5941c678498ab917bbf82a808f39c093719a53f2ed",
+    "dist/2022-11-01/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "c7fe3bacc9c4acb9b42677281655904b5ed5aec27042b9a8cf9743b737b6b657",
+    "dist/2022-11-01/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "57f985ccaa2452778c90733e2586a991969dc15697bdbc9547da8a62c871b674",
+    "dist/2022-11-01/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "873b2a0c2990eef29d689984293394e6972b4659bd6e4c31fb9bc9c8f1c679f9",
+    "dist/2022-11-01/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "f8a9e74159594d57ce8dda1f7ce7ee4e1d494b9135a0f32b3afc89a637cad8ae",
+    "dist/2022-11-01/cargo-beta-i686-pc-windows-gnu.tar.gz": "9570141b118c2339237aac12c1e6d71c138ccef784db2effdfd9d02fb12d0d0d",
+    "dist/2022-11-01/cargo-beta-i686-pc-windows-gnu.tar.xz": "183b63cded6c4cc26feaa14be036a619289b155a6718f4964f94c38a9208742b",
+    "dist/2022-11-01/cargo-beta-i686-pc-windows-msvc.tar.gz": "9382bf364c5fc9400fb22b046c0a951001961efac221f5cd0f9bf45b1005d36e",
+    "dist/2022-11-01/cargo-beta-i686-pc-windows-msvc.tar.xz": "aae0a58b9711365ce1d76966af7387f310b496859a9e02ddbff8e23da93226c7",
+    "dist/2022-11-01/cargo-beta-i686-unknown-linux-gnu.tar.gz": "507727f9b5a920ea28e7104c9aae681c50fa8aaea446a3e10b991a9408adaefc",
+    "dist/2022-11-01/cargo-beta-i686-unknown-linux-gnu.tar.xz": "4ebfaf11ffc346eec9f05b2d93123483b784b83a322cca6f5fd406066ecf0fcc",
+    "dist/2022-11-01/cargo-beta-mips-unknown-linux-gnu.tar.gz": "6407889854bee2e45a00585abb4fc8b387103e33e3e67244dba4e140abe46480",
+    "dist/2022-11-01/cargo-beta-mips-unknown-linux-gnu.tar.xz": "1aeba894f0ca756dd9c3d9b99c7c94bf1f49d5d87ea919249fd0fcf195eb9c52",
+    "dist/2022-11-01/cargo-beta-mips64-unknown-linux-gnuabi64.tar.gz": "292a95a8de3387832173d9adde633b3d34a019879f97bf196cb41556c3909337",
+    "dist/2022-11-01/cargo-beta-mips64-unknown-linux-gnuabi64.tar.xz": "872819f00ab0a848401d7dfbb18cf139f85b3d8e48eee0a034cf7f0b970bd865",
+    "dist/2022-11-01/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "15eb49c334688e48e83f2565c620b3f1af29775599406efa1814c78ee80673cc",
+    "dist/2022-11-01/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "e74f6884e71109d36d03f7147b7e506f374ba291aadbe4246f6c429bd6fffd1f",
+    "dist/2022-11-01/cargo-beta-mipsel-unknown-linux-gnu.tar.gz": "7f3cf8b35465e4df5fc18cc7cb4f4db6e1b240a39f7583126d7f8ad6d18e8bf0",
+    "dist/2022-11-01/cargo-beta-mipsel-unknown-linux-gnu.tar.xz": "c59f2893999dd88a55c0a5bdb4436640ae9c18f943baf48f63eff6069f7a3e8d",
+    "dist/2022-11-01/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "566c315b6206a63bf33acf178547bb757a8803e3cfc71f1f63ee033eb6a17138",
+    "dist/2022-11-01/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "814a8e8f8f5caf5bb4018e54ffc2c1bd9d23df94dcaffbc04881b91bb3c8aefe",
+    "dist/2022-11-01/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "5db8a63532be5fb9511238d7976075496aba6c732302dcc27bed9ae61188f917",
+    "dist/2022-11-01/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "6b95c8cc4dda3847f53fb62ea711ca99c1b1b1639249b8b01d54a9ecbc4421ec",
+    "dist/2022-11-01/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "2ad497be28760f7e4ec6dfa6421a6c10ab049e0dbf45ecb3a2dbde5db7a959de",
+    "dist/2022-11-01/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "6e9b982857c64518c10392779528e7065191262a95e091ee289c8668b6cbfc4c",
+    "dist/2022-11-01/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "88a0751ef36816f9e26e9f6d72809687b1f6821b32a3a17c58feaa32f882aecf",
+    "dist/2022-11-01/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "bd6f626002a0c5a3af975419a1258a77c9db91e0db5d4acccbc7dbf25ffd17c8",
+    "dist/2022-11-01/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "69bad5758f27f53d3e48abcd5aa70b16eb29d5445233c65ab50a8ad0a1629077",
+    "dist/2022-11-01/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "06212f4cb605fb79d811060d3096bc4b43cf00e1a4fe4a375154b56ff60c92f5",
+    "dist/2022-11-01/cargo-beta-x86_64-apple-darwin.tar.gz": "741f3490b5562afd57cdda846ab322c69e20940bcc11f3ca5690d662d5de280b",
+    "dist/2022-11-01/cargo-beta-x86_64-apple-darwin.tar.xz": "2d698df7c00b7c227ca388830732a8787b2a85b328b554c0f8c417813d97ef46",
+    "dist/2022-11-01/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "9c22b476f25c3f0946cb834da3904516248137cf22c5eed30432401ff061a4cf",
+    "dist/2022-11-01/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "1604c5d60379227d26d819bd2f7a57c79a9e000a6077ec06e95b418bb0351180",
+    "dist/2022-11-01/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "673d8941202c2113a431fcef396e604d7ea79000c97a64ef6e93b26956f75fe7",
+    "dist/2022-11-01/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "3d613d04b48a2eb8644e2bfbb07a88cefe02c7b5cc7bf061b8ef307980230d47",
+    "dist/2022-11-01/cargo-beta-x86_64-unknown-freebsd.tar.gz": "e0ce6fa69af565e3b79f7059a4de88e39955d7ea6866d56c2b0946b47929192f",
+    "dist/2022-11-01/cargo-beta-x86_64-unknown-freebsd.tar.xz": "de602b7802b1448a861df05c41430dcde4f07358a05711784a1ca37836525b74",
+    "dist/2022-11-01/cargo-beta-x86_64-unknown-illumos.tar.gz": "c4eacf4821c126b321a67e0233d2f84571b3dcf25686165cad00d9645787f03d",
+    "dist/2022-11-01/cargo-beta-x86_64-unknown-illumos.tar.xz": "01ec5ab637010498b784ea2fe6aacea626fc341792eaa5a50756f9b483a765e5",
+    "dist/2022-11-01/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "2e6efadbcf138ab72750c1375bfeaf2d5102559aa9b745294b9973821e193703",
+    "dist/2022-11-01/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "e089b1b4248ad8e05ba54cfb278101a74aa34154bd2d44dd50119026bf436d1d",
+    "dist/2022-11-01/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "ca079fce260accce11c1fb27e550421cd0900027e29b18e24e54a298d78031c3",
+    "dist/2022-11-01/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "ff33e9fd6f06e02277f580f13d82f753987f4dad7d7926405b63dcb362eec498",
+    "dist/2022-11-01/cargo-beta-x86_64-unknown-netbsd.tar.gz": "46101fc5f53595ae53f3ceb755cc72c078471479a337b5319c85e629e5df3b28",
+    "dist/2022-11-01/cargo-beta-x86_64-unknown-netbsd.tar.xz": "b063425ccc69284e8788211bbde5a7843bd16a3b9c779fab68a11d22ebdf319b",
+    "dist/2022-11-01/rust-std-beta-aarch64-apple-darwin.tar.gz": "77bb5db904089e087032c24fa2e011536e13d3982299285a7515beb97f445078",
+    "dist/2022-11-01/rust-std-beta-aarch64-apple-darwin.tar.xz": "63aae4b9f10f15fb48b2ac20aa7f112a685d49bdf94d8997d036472e928fcbde",
+    "dist/2022-11-01/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "8f63b6be668e6a25411582db9145c9de8192d58acb42c490b0de89489a3e36c6",
+    "dist/2022-11-01/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "d862bdeaf2c78b15babaf74cf1c6feaa5c4871a90095f3d4239d81f44217cff4",
+    "dist/2022-11-01/rust-std-beta-aarch64-apple-ios.tar.gz": "e5b1e9420d387a1442c77bed10efebd7b0268713820a728a067bb4ead6088041",
+    "dist/2022-11-01/rust-std-beta-aarch64-apple-ios.tar.xz": "569c667e422ca7ac373d59b6e13c299cdb7f334164c84e6f0c8d0f076352fbf0",
+    "dist/2022-11-01/rust-std-beta-aarch64-fuchsia.tar.gz": "3f945c43c09704b3df6af66a2132da12243b13752094383965d6a8a83c6edb0a",
+    "dist/2022-11-01/rust-std-beta-aarch64-fuchsia.tar.xz": "3662f02892ab184be99f93a9d0f99e030a73cc61447934b74fcba84e05b022b1",
+    "dist/2022-11-01/rust-std-beta-aarch64-linux-android.tar.gz": "ab04a0228074e974d70a15e594d57479fe22ed37c8acfa5104201dbbe57747a7",
+    "dist/2022-11-01/rust-std-beta-aarch64-linux-android.tar.xz": "fb96925878a24dc9e90d356e96cf4fd1fc9152c39f8914f9a9bb676d78069cba",
+    "dist/2022-11-01/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "45e824f75ac530ee9eaf0b0a01cacd5b8dd64ddf5203c032c49fd2bc4fabb245",
+    "dist/2022-11-01/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "a6488faf4c87cabb4467f4cbe7348d553045c2f10f450bc6e000fcf18ca9b073",
+    "dist/2022-11-01/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "e2a66e04b24aad8a8898d6c0270d8dcff63205213cea3b893807ef186e8c0936",
+    "dist/2022-11-01/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "a4244ac1600726b5abe6b5f9a171fc2e4cc57bbe7cecdeaf23b69e906f05e303",
+    "dist/2022-11-01/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "9e3e0f675ca50b7a2a1afeacdaf5d7f2f4ec1536f596ff99aadacfcb59fd42f5",
+    "dist/2022-11-01/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "7e7a8fb4fe0283b71deb79c5ccb1ae61b2099392b3c8e09d03d4a68fbab7a184",
+    "dist/2022-11-01/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "7543df1d71d805b079d19ccd785f777918b3f11b131bca05d079cb5d3952a38b",
+    "dist/2022-11-01/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "eb082e894047cd77ac3fcc9c03eaaef77e6bafbd075cb0d62ba3a3ba277f5d64",
+    "dist/2022-11-01/rust-std-beta-aarch64-unknown-none.tar.gz": "144fc6973b06ffb12b5ad0bbfc9fcdcb2a0732de50bb140d62d6af3d6b462908",
+    "dist/2022-11-01/rust-std-beta-aarch64-unknown-none.tar.xz": "8ee2ba2d4eca35a426fb089e0f0b50b2ac3ad1ab036c5f8f4786e2953405092f",
+    "dist/2022-11-01/rust-std-beta-arm-linux-androideabi.tar.gz": "4a46d6591c1983d0853f7596f7b76e7c82b6b0cbfd97802b565a17aece0d13be",
+    "dist/2022-11-01/rust-std-beta-arm-linux-androideabi.tar.xz": "3888fe036b5fa9a5dfa009462a002a05c70e56eb70db3a0c872fab1432e9c9ed",
+    "dist/2022-11-01/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "529d668389506443f87bd93e98dc72d12be9a4ab41675dc6a1c7373e934ca017",
+    "dist/2022-11-01/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "dffa1a94f4166435d6fe2a76a4d35deb8c128cc93146f181979416816e77e29a",
+    "dist/2022-11-01/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "2913bc06d6b49c52804a8dc18d1d3cb1b564e0272cba93f8594747731d360f9c",
+    "dist/2022-11-01/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "c12bb97fcbeeb0a9a71b2575b2d5113948c515616f720dae3891e2aa886d03a7",
+    "dist/2022-11-01/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "a844ad8a80fa07b9196dc040d5171749daf94443c57348bca04e69b8dad37cba",
+    "dist/2022-11-01/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "c261662fa988748ed03722d6034228c893e02a0e473f906bba61c1f43be7cd79",
+    "dist/2022-11-01/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "1ae5967f4fb80047711519dafea21fed8d6afd308566033e468c11587073d216",
+    "dist/2022-11-01/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "150393cde94d8349eb488a161572589c53fed456c8401e5b1a59d1dd87003f7c",
+    "dist/2022-11-01/rust-std-beta-armebv7r-none-eabi.tar.gz": "b1777a389e4db0ccd80ece774865bc99731c4b483be80c909f1b5a2a185dc5a1",
+    "dist/2022-11-01/rust-std-beta-armebv7r-none-eabi.tar.xz": "877a00491650bac92e93760c2457b644d2b5ee28d410c1e29fc4b40c05da493a",
+    "dist/2022-11-01/rust-std-beta-armebv7r-none-eabihf.tar.gz": "3dfbf001db319a41874e2c0de2f55407285d88156fa0563cfe3c3bb1939998fb",
+    "dist/2022-11-01/rust-std-beta-armebv7r-none-eabihf.tar.xz": "b2d6a543cdf64a5c147001ea30d07bd13b98e2918a343bff08bb57eed1f81462",
+    "dist/2022-11-01/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "cd8f0803ef86052d09606601b09dde05d1997a93fad7a22604fda1176157040e",
+    "dist/2022-11-01/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "748cef6595fcd30da6735c29476639ac80cba94eb627d6654665d656da2979ec",
+    "dist/2022-11-01/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "1dcae3588a3e552778ff1079a92750bee15835f08f8b9ff1123e4e6c5a73c087",
+    "dist/2022-11-01/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "3711105029d28fd91f413f488b7041ea42c70e5a244f992e9259b4e9d52abed1",
+    "dist/2022-11-01/rust-std-beta-armv7-linux-androideabi.tar.gz": "a2af3f6d3681e1c545d0c21bf04fbfe3de1cdb2273fadcbbb4408f5590054d11",
+    "dist/2022-11-01/rust-std-beta-armv7-linux-androideabi.tar.xz": "23e658070e1cbe8011d48678f57bedbbde819cd64f43509858af563a7073a3fd",
+    "dist/2022-11-01/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "ff7b429d5a6d33f0e467b333225f7c42de279ccf3e91f3ef7c5463dc06939579",
+    "dist/2022-11-01/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "8d41b293656c5cf93f46754499e5723a89dd997d3723bfbe56f953a7d864c435",
+    "dist/2022-11-01/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "6dd89ed0f20a0ea4a279dd4f810c7908c3e8a377da8a2983f8890efeea169177",
+    "dist/2022-11-01/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "504fb533fca6c46ad98c728781ab31170d65e5b35cbc9199aab97b1146a24702",
+    "dist/2022-11-01/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "f9a731fd3ea961f0c5eff24e6290aed19d79d5444bf562670abc0cd46ee309fe",
+    "dist/2022-11-01/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "825acb16e4bbba0c9b535e635b972ec581fe6ef115c5a41bace9b85c704eccad",
+    "dist/2022-11-01/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "41da8404f0e3cef386f6efef9b27fde27de77de71140dceeaddd8e15260ce45d",
+    "dist/2022-11-01/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "c8f81fa9cfb40ce92f2c95ef8b57e8a62d819628111e1dfe0c6760fb48802be3",
+    "dist/2022-11-01/rust-std-beta-armv7a-none-eabi.tar.gz": "fa8c3168dff5c167c6ed25f9c605941ab51e73e70c0dd162a5fd17287c5fd5a5",
+    "dist/2022-11-01/rust-std-beta-armv7a-none-eabi.tar.xz": "36a5ff7865f8a16b867ab3fff4ac32f0c62c260a5c27385098e67b75b21790fb",
+    "dist/2022-11-01/rust-std-beta-armv7r-none-eabi.tar.gz": "0417cef6468fd66bf626729e7c0089b47b149cfc43e8e0d4281f76f73ed17edc",
+    "dist/2022-11-01/rust-std-beta-armv7r-none-eabi.tar.xz": "1de6cb38a68ef336e1edf2c1c51d999482898df99e2bc078cafe6ac5380bf3f2",
+    "dist/2022-11-01/rust-std-beta-armv7r-none-eabihf.tar.gz": "91003d4648fb01306d6e0a0214e089d444a57c5ff09138040f07cc81e89af639",
+    "dist/2022-11-01/rust-std-beta-armv7r-none-eabihf.tar.xz": "884306ac77518ece0cb2f22d898e3d2aa50698bd4181ca23a1dada6d82778682",
+    "dist/2022-11-01/rust-std-beta-asmjs-unknown-emscripten.tar.gz": "f17ca8f54eca5d73006659fd08142d537eff23731b6e5a35bd67efafe0dc8cb1",
+    "dist/2022-11-01/rust-std-beta-asmjs-unknown-emscripten.tar.xz": "b04a17d33d7b9b1caae666dfa5ee9a98e5dc079773b6345f6c49733731e14bfe",
+    "dist/2022-11-01/rust-std-beta-i586-pc-windows-msvc.tar.gz": "55e61aa74bdb50df54394a0f62b9edc88682c37b51fe9d8d5c05c0619eacd1e3",
+    "dist/2022-11-01/rust-std-beta-i586-pc-windows-msvc.tar.xz": "ec3d887742289ef9c171ae56ca20c3e9cf1972cc3e6c511611404070c55dac8a",
+    "dist/2022-11-01/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "a36444f0ba0e7e03d06fbf65d830cb7067c675ed061e8f6efd6ed445d5955e88",
+    "dist/2022-11-01/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "dfc07297ee8cb63f76d2019ae822352e6b42e5cccd225eaa5597a63ecff3624f",
+    "dist/2022-11-01/rust-std-beta-i586-unknown-linux-musl.tar.gz": "e8de9f830cf277be584b54d86d6621a249fb2987fdf32d5f16cde9b492722d45",
+    "dist/2022-11-01/rust-std-beta-i586-unknown-linux-musl.tar.xz": "f9d8bd74788e2209ecb8d0cc49d94b4e2752c9239f89bcdff3e8fae315d1d923",
+    "dist/2022-11-01/rust-std-beta-i686-linux-android.tar.gz": "b15636654925fdba1e9ec1704573e4af1fc5f1158a0657b245901e22c06cd378",
+    "dist/2022-11-01/rust-std-beta-i686-linux-android.tar.xz": "9abbfcaa40d86e8a4cf49f2a58b1c7b2f422b6890303cb43feb83cfb8f650a42",
+    "dist/2022-11-01/rust-std-beta-i686-pc-windows-gnu.tar.gz": "30953eb457a397966221dad058ff7ebd99ca4497f184016b5a61db0f122bdee9",
+    "dist/2022-11-01/rust-std-beta-i686-pc-windows-gnu.tar.xz": "f9d6d266eb3bb46c058615786483d817138aa29efc3c62c3cd9c87e572956b12",
+    "dist/2022-11-01/rust-std-beta-i686-pc-windows-msvc.tar.gz": "b55202c349a4e9a493a2de7a3d48788befce32274998d3dfc1d1b6f4a96ba9e3",
+    "dist/2022-11-01/rust-std-beta-i686-pc-windows-msvc.tar.xz": "6dd8d42e5712d699704e85bb90cd42e0142a4fab7cf7f80132cb0902cc415ccb",
+    "dist/2022-11-01/rust-std-beta-i686-unknown-freebsd.tar.gz": "d2a7c9e7f1dba3a317692a46f8efec8d7ba1e9e943c88d3f342a820c34829aa0",
+    "dist/2022-11-01/rust-std-beta-i686-unknown-freebsd.tar.xz": "ecf6abb631dd6887b5630d1ea0b8778fc1539405e6c00d7585c8afa2230ef9ec",
+    "dist/2022-11-01/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "93c5912258a49a003a12ca01101f5935d5894f9a133301a47047cca934a7439e",
+    "dist/2022-11-01/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "f8a6e67723cb968e874827a6148a5e25d3d45c56577faee627010347d0f03d92",
+    "dist/2022-11-01/rust-std-beta-i686-unknown-linux-musl.tar.gz": "8838592167a8d68f463dc18e55d5d2d55c474426e8a4ec0f28fd2cd4230cf638",
+    "dist/2022-11-01/rust-std-beta-i686-unknown-linux-musl.tar.xz": "c8330a06862a7f375b57774b382a54a1280c33ddc1b94d5d5ec45eb6ff0de8cb",
+    "dist/2022-11-01/rust-std-beta-mips-unknown-linux-gnu.tar.gz": "4b50cc174eb1da9dc831de828e6ee2fc8a81abf8e6dd52b041e4ab00eaff73ac",
+    "dist/2022-11-01/rust-std-beta-mips-unknown-linux-gnu.tar.xz": "4820db058569be7350a81396fdedf9a28233b8061c9bcf607cf2d1058cbf437a",
+    "dist/2022-11-01/rust-std-beta-mips-unknown-linux-musl.tar.gz": "dfbc460e8322114bde5614b0b45e90066805adbaca999ccdc4f2aae456fc3f1f",
+    "dist/2022-11-01/rust-std-beta-mips-unknown-linux-musl.tar.xz": "d98c19268b0c84f44f1224f432847a93eb809a85ca48fbe2e4b68fb436bc36aa",
+    "dist/2022-11-01/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.gz": "8617edc6d62591d50dbadc4a7bc41b31b66bee6fee830af46636c5206027217f",
+    "dist/2022-11-01/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.xz": "98a6132c8dd7558eb5f44007fa681a3a91b2dfd98d1f68e59f0a4660dc37b500",
+    "dist/2022-11-01/rust-std-beta-mips64-unknown-linux-muslabi64.tar.gz": "81f794c54d7a8c680c52a8fc1a0e479526744205d51266007fc3c542496957ba",
+    "dist/2022-11-01/rust-std-beta-mips64-unknown-linux-muslabi64.tar.xz": "dedc5b1a76f8454d1b3d7fda0a05398e5a9ae4cf16ddc4b44477799217a1fb75",
+    "dist/2022-11-01/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "6d9b3d469ae92e38144d9578de8cf0c891e4bf3e667e4e465eb6f0d498140c3c",
+    "dist/2022-11-01/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "f9deb84c24bd0f21ed02d763d3ad8dd92c009de4ceb2b78ec06d90d66609c5f6",
+    "dist/2022-11-01/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.gz": "073882815493668dd484b8f107efc047f6e07d8c563703d0e7f73ef33dae0efc",
+    "dist/2022-11-01/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.xz": "d1ab3758d1b08937a3f98737ff9fad20377e5bc43d7ab3a9359b4131ea11dcbc",
+    "dist/2022-11-01/rust-std-beta-mipsel-unknown-linux-gnu.tar.gz": "bc82f3d23dfb7b331558180f474c334ca3798322e19cc64657cbe894d0682901",
+    "dist/2022-11-01/rust-std-beta-mipsel-unknown-linux-gnu.tar.xz": "fcc12f82ea0c02e8434420165f1ee072bf4587a82ff5ecf34d19f754ffc091ef",
+    "dist/2022-11-01/rust-std-beta-mipsel-unknown-linux-musl.tar.gz": "1c4507c7824c02b1af2857c88ff1624e9ead3f38c1456aa031586b43223e9490",
+    "dist/2022-11-01/rust-std-beta-mipsel-unknown-linux-musl.tar.xz": "932598fbcc35ee4958be4778450f5b809ce9eabb2aa3d7573fd79744ed4d18ad",
+    "dist/2022-11-01/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "c17f11707c1edef2353fba7e3f4800cecb8a273233825817b6d07ed78d6acd50",
+    "dist/2022-11-01/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "7e90a819b8887f0b1a3ab02fb9a56a9b9eb752408a7bb934c99c7f6ddda48a71",
+    "dist/2022-11-01/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "c437a6fc7cd7869df7cdbb52c51ae1e602ed1206517c38689deb73da6d7b4877",
+    "dist/2022-11-01/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "76c1fc55b16a809ab1c8dfce894899f40d24b20dc670d318a7679953beb6c3a1",
+    "dist/2022-11-01/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "d62396390fb85d5543a80ffbeaf7c32b5297a513dce14790124c35835813032b",
+    "dist/2022-11-01/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "4595485492c650aa53bb9deaeb425ea956f2052c5b5503bb477778f7bcaf6ac6",
+    "dist/2022-11-01/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "ee841bb8fbb0075a0bf51db2007bee2962830a89649c00fd15c67b31fd9226a3",
+    "dist/2022-11-01/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "cac036fafa93f2860a5a2622394e12938c35e629ff81d7cc5930d99c980f9321",
+    "dist/2022-11-01/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "025d70e57d608b81d61799c84ccce9bca3603736c4d3e006fc662c3a7b39e8db",
+    "dist/2022-11-01/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "9450b1b1f95e188bcb9050085d612c8bef36e819881255fc20d70da1f45fa61e",
+    "dist/2022-11-01/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "ff707c6d209f9d8e421fc530a11d41a46daaebdb4aebd5cfbaab761b2cf192ff",
+    "dist/2022-11-01/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "8eb48a94c58440e2afc8ef7bbdbc725f403fe38724c0afde4e7c29a1ba2c7591",
+    "dist/2022-11-01/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "e921a841b7a9e02e28182e91c921746042330d90f0478fc7e01230cb1b881c1c",
+    "dist/2022-11-01/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "122135e161a4cc7dd857e3cb35b64ff7db450dcc07cbb990c8aa83e06bb4b346",
+    "dist/2022-11-01/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "084824d6daeca6a0662ef1e11df84c651138d8d4e7d5c8ef66c5811354b16211",
+    "dist/2022-11-01/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "09e3df606e10a0a59a67bf7b49825a04c23062e6050cebed674e0bdb2c396fcc",
+    "dist/2022-11-01/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "f9929f62ffec9c6b3342da8dd21b1c14526e033174a4f86015182acdbb93a985",
+    "dist/2022-11-01/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "932450fc6b5e8fa4813886baa389b53c6ff1c5b1e71f7370017b9658b04fd13c",
+    "dist/2022-11-01/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "e7776d188a04779e7f6a7257bf367d8671e7d5d804d74db426592f683cabf562",
+    "dist/2022-11-01/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "bbc765adc116c6a1bcbf659853b7169d95b240ffc15227cbb1d60b46d63e120a",
+    "dist/2022-11-01/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "a0ff6e9ea827d7f93563aaec213eacd00efe4be9c921b448405b2af8bbf0066e",
+    "dist/2022-11-01/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "7603744cbbbbdec5b2a322aabe68751e848ac7379c710866c59dcc22e4b873bd",
+    "dist/2022-11-01/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "1f67446eb09505e87a5218b8504dfc678d0a712a5add763362f3c74306010bea",
+    "dist/2022-11-01/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "1baca6f0e7f18a8eb9efcf35bca4320a493d51f08e62bf96a31036e2f2c433fc",
+    "dist/2022-11-01/rust-std-beta-sparcv9-sun-solaris.tar.gz": "455e52fa3f232c2239112030483c0a657e7f69754d8d36ab72423c76c056fb68",
+    "dist/2022-11-01/rust-std-beta-sparcv9-sun-solaris.tar.xz": "913801ca45eb1d70c9ddfcdd66aa21edaafccc85acf9864e88991bf8a5a7cf25",
+    "dist/2022-11-01/rust-std-beta-thumbv6m-none-eabi.tar.gz": "14e4f69fbf710f16275ccb582a90eee1399ea1226945c7c96f75335df9118966",
+    "dist/2022-11-01/rust-std-beta-thumbv6m-none-eabi.tar.xz": "40549d9d9c923a73381b8e45628cfa1896d0e78caabf2aa921c767e0bc979136",
+    "dist/2022-11-01/rust-std-beta-thumbv7em-none-eabi.tar.gz": "d40bd56883abc142155188674580c4e29100fd7303fccc70b0c55b964721a156",
+    "dist/2022-11-01/rust-std-beta-thumbv7em-none-eabi.tar.xz": "874c97a01d06e1516a89797d7a6effeabf34afb4933956aa34e907a65ea78690",
+    "dist/2022-11-01/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "cf7acd2b4a083522c01f1909891aaba27502ea0a3a5eff93dfb41971f832bba6",
+    "dist/2022-11-01/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "e9544acbefa3effe55537de85311b00077a0567d64345aa80414752037212b5f",
+    "dist/2022-11-01/rust-std-beta-thumbv7m-none-eabi.tar.gz": "247e9dae16f46c64da895528f3e902030110e2aad8270f169c636ca14bfc28aa",
+    "dist/2022-11-01/rust-std-beta-thumbv7m-none-eabi.tar.xz": "b7de9e8bf7b7d04fc9575390d69eacbcc62a39c35c81f37d2170424cffe6a356",
+    "dist/2022-11-01/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "bd3dc986a11967e8ed050a88d03d1c0814b08cc1ab0cf929561fbf5a941a335e",
+    "dist/2022-11-01/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "262b4c4ccbe20c9e913a7417c8ca72c6fb7e71f187103929057dcd0fc0b49cea",
+    "dist/2022-11-01/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "85f6a725e5a726afab9ae019944567b42ee769db98a8d3c335d449eca92344e0",
+    "dist/2022-11-01/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "07e897f4320f249b3f458e44e5440591962105a3b6032b54f4448c0bd21da964",
+    "dist/2022-11-01/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "e92855841ae93990f88f3893a1bf511853fc3f10938eda767d5c7ff7d310aa4f",
+    "dist/2022-11-01/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "3c3412a67f769ead9e8bafbcb5ff6dfc8ef89f0d8234baee7b39ab9df9fadebf",
+    "dist/2022-11-01/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "f3cd623fdd466e5c0b5749dc4e90a75122f1989f6fcae0ace8c76f3b394a0752",
+    "dist/2022-11-01/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "3793ab2a42f1bc59ad560ad1af75ed90c49e25f665330b5b8ce50ed73ef88508",
+    "dist/2022-11-01/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "cc6c715e320c7fc5fd90f446f7c2ce6b356e95934d05f79c4e2d0fc304f212bd",
+    "dist/2022-11-01/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "42a47ce6768b24c2b40c6a724003a401bfb37201a773e3c31ee413cc559cda70",
+    "dist/2022-11-01/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "4c09e5b03a921d8c1d8a10d9535e81be3b3bbed961d229311cc691396ae10cbb",
+    "dist/2022-11-01/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "775f7223bc5d962b5356a4884565a948d3cb5289fafe3e2eb2b8ad67550d72b4",
+    "dist/2022-11-01/rust-std-beta-wasm32-unknown-unknown.tar.gz": "bc027d9170132c36faa47da1ff8f26d26d383a5145cb9dd2dce20e769ea300ba",
+    "dist/2022-11-01/rust-std-beta-wasm32-unknown-unknown.tar.xz": "9a721d3550132930820d9b809074535d2b63ecb91d5c061effded92b503bf0c2",
+    "dist/2022-11-01/rust-std-beta-wasm32-wasi.tar.gz": "047d58ef5e10ab51a81dbc11646fca184945a1c52e7a91552449c67952c8d898",
+    "dist/2022-11-01/rust-std-beta-wasm32-wasi.tar.xz": "a490ce6ebc77a4a49c2fdeec471dd9e586b2aa26f1e7f2fc1323cc06b2b336d5",
+    "dist/2022-11-01/rust-std-beta-x86_64-apple-darwin.tar.gz": "df73bc81d446792d9366772944a04f69ad32f427e1949e05d4f7c202c350c269",
+    "dist/2022-11-01/rust-std-beta-x86_64-apple-darwin.tar.xz": "450aec3ec53594869bbf16ffe1713dfa19b8dcadd812a4af811bd56f1f58c929",
+    "dist/2022-11-01/rust-std-beta-x86_64-apple-ios.tar.gz": "fb698f63336a186983b09c2c49109dd080c22653f3367dabfcbae564144aff35",
+    "dist/2022-11-01/rust-std-beta-x86_64-apple-ios.tar.xz": "0d475ba4a4444f4da5fb39d26c9cdbc0352ea799d7e30f57e2e79d8c3c7a7021",
+    "dist/2022-11-01/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "137234fc37b93ef4fa543f4e33217079137b4dbb51efbea669b93e561932b5e9",
+    "dist/2022-11-01/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "01e1978d9359a5112aa77409ff17c3d0e0dec774815f679065db6c6293aaa623",
+    "dist/2022-11-01/rust-std-beta-x86_64-fuchsia.tar.gz": "662e62862b1586f29372339319680c88b7cebe41e98401b5dd62e320755f0d62",
+    "dist/2022-11-01/rust-std-beta-x86_64-fuchsia.tar.xz": "4a644c6c85c8e427d68a669b0f598669023e2c0db2b69b94a7124c18772052dd",
+    "dist/2022-11-01/rust-std-beta-x86_64-linux-android.tar.gz": "752a57eb3de0060c1ffc6eb0af71d88d5f881b543b11b209593be2b18af1f902",
+    "dist/2022-11-01/rust-std-beta-x86_64-linux-android.tar.xz": "19effccfd9d63e955cb0736968c4c300c6d919217a64cde464c30a499ae9fd9c",
+    "dist/2022-11-01/rust-std-beta-x86_64-pc-solaris.tar.gz": "aa8a36ec1892c68a1c1ea0d9ac1b92b03c975a0d8ee538aaee5d757ad84d5b2e",
+    "dist/2022-11-01/rust-std-beta-x86_64-pc-solaris.tar.xz": "955ad79007d397a9e24d819e95017880b25424bdac01386cb8fc6d50247b1274",
+    "dist/2022-11-01/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "9f15bf80a2384f2fd333dee41289fdd8529170192dcbdd8cba0a73d32715ccc3",
+    "dist/2022-11-01/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "539bcefcd6b888c5f38abca47792dcff1676ef31eeb9a4a045703582262758c1",
+    "dist/2022-11-01/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "748fd22a993be659f85c3799871c4de09a99fcd7805c6d0e9d5a18dddfd2e26b",
+    "dist/2022-11-01/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "68c22dfa2ef5ecd2d43661716e8a8394eaa36e8e960d34dc421bbbe57c3e0d23",
+    "dist/2022-11-01/rust-std-beta-x86_64-sun-solaris.tar.gz": "f06118445fc6671d491c61dd8e6ff83ca21fc1d692058eea072cbe01ff798fb2",
+    "dist/2022-11-01/rust-std-beta-x86_64-sun-solaris.tar.xz": "b3fdd56baadf3a8bffd17730d61b2ccef25ffa25d5cd826bb9a45940bf573fb5",
+    "dist/2022-11-01/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "2dfab0336a523182d200c7a6096fb29c199339b282ba03b469a9a1e5c5a5bb0b",
+    "dist/2022-11-01/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "ee5b9158ca0c2e829bb79ac526d17a2ba27ca4e305e134241ba1f8347a9bace5",
+    "dist/2022-11-01/rust-std-beta-x86_64-unknown-illumos.tar.gz": "fe62b766d11e9ac55db5011a63086af5d87ce560c0656dc214c668db752675e4",
+    "dist/2022-11-01/rust-std-beta-x86_64-unknown-illumos.tar.xz": "e4b1068de2812c62e7ac0ec080f605fa90123a94563dc4f898221275fbd5178b",
+    "dist/2022-11-01/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "c5ce6885405ba4d1694a7eb767837320ece5a02133e94c1c22ac07143d6f752c",
+    "dist/2022-11-01/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "eac46cc9200125be2548d6b9f2c2d37b046b8b43b25dd7f7347d88ef6795a3c7",
+    "dist/2022-11-01/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "1b3d1d051cf355eb26bf9de5096d984f83dc92fdeab3bdcd18d88152c0e2a2bf",
+    "dist/2022-11-01/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "a17cf4a9df1b1be17f5163f05665bc40638e62210d8e0623fb1afeeb96acad2a",
+    "dist/2022-11-01/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "90a2e5712bc37f28a0d1f71c54cc04233049c638e4f0592b50adea352e21038f",
+    "dist/2022-11-01/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "ad76d090357f5e272b1598c35dd24137fb9950e1bdc50b9332fa1d2fcc33a00b",
+    "dist/2022-11-01/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "37e0954add559b24c08ad284fb80294e435491159db63ea78a6183af5926dcec",
+    "dist/2022-11-01/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "d6542bd592edd3924999e690416b6bc559486388add76fa77044114b70700fac",
+    "dist/2022-11-01/rust-std-beta-x86_64-unknown-none.tar.gz": "d021e49b68b8321354d99ae0fe80a6b042ec798ca7fe37cc92d4f0c0480f7ebf",
+    "dist/2022-11-01/rust-std-beta-x86_64-unknown-none.tar.xz": "f6202c50c6d3575fdb398a8c98adeb0d86794b60c3951887c90a9e4acb6a89c0",
+    "dist/2022-11-01/rust-std-beta-x86_64-unknown-redox.tar.gz": "b8ca678975c0c18d0fda1bb118b35366d1261e366639b8bb455b6bc59388082f",
+    "dist/2022-11-01/rust-std-beta-x86_64-unknown-redox.tar.xz": "119f9e65dc3484f677064e068da42a1e7b8dc0be21d0cbf5185c9836589b39be",
+    "dist/2022-11-01/rustc-beta-aarch64-apple-darwin.tar.gz": "11aa79c56a9dea2d5305ed049485a1257912fc0dfca1feff37b768971f4c1701",
+    "dist/2022-11-01/rustc-beta-aarch64-apple-darwin.tar.xz": "a031051ccf97100bd8b4d2e4df7a67371cdf300df4697e1d05a7cec33a7d8c09",
+    "dist/2022-11-01/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "4d015042d7d06929488f607bc56d925002e6f352d74fe192dc30e7feebb9947c",
+    "dist/2022-11-01/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "d72824112c96514d927df46f6e755898d26ddd5b805f6c2c0411c773105ad61f",
+    "dist/2022-11-01/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "3e70261ed7c130cb7256717cec0c37476961932be228e46e028818f9076dfccf",
+    "dist/2022-11-01/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "452f07f63888cf27ca2d061751602bb07a43348eca9cab30db27940a36f496e5",
+    "dist/2022-11-01/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "995a6410305d43234eb94710ddc251bafd9f5fe4ecacc51c4dc1447f364be30a",
+    "dist/2022-11-01/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "2d586e5d1a72194ce2798d4f07c873d52ea441cabe5040ff682664d618b98d4e",
+    "dist/2022-11-01/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "65954bc862cd149cae2702f25b186fa2166d80cb45bfe6867d075381f2614464",
+    "dist/2022-11-01/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "f3a5f8318efee7eb9ba4d861876b0a5415f308c9dc2cea751a10b2e259303627",
+    "dist/2022-11-01/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "d4be89140f0bd4ef9f73a1b54f949973ce560c4dd62c664974f82278ca0d6079",
+    "dist/2022-11-01/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "5b381b513c27f95f9d170e9c532839a27facfe6eb4dd215c078b44fde40e3ba3",
+    "dist/2022-11-01/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "ffdf714a07408901962c861103b062adf334e0febc1abfa8c538c40b0070793e",
+    "dist/2022-11-01/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "ada55533236ef8c629ca72f929bb87db4b68f8c3d4c6fb3e7001f892a84a2b82",
+    "dist/2022-11-01/rustc-beta-i686-pc-windows-gnu.tar.gz": "b7e059973b61a4d7a0c96b4642629bf72668380a5ad8a2962181b1229ac2174c",
+    "dist/2022-11-01/rustc-beta-i686-pc-windows-gnu.tar.xz": "9aa3bc05e1782b8ff5d278f5b5baac4b0ae523ad8bba2bacd46e1bca11cd38b9",
+    "dist/2022-11-01/rustc-beta-i686-pc-windows-msvc.tar.gz": "acab77f5641be0d7102e6b911f134aa36b6fcad5ac594100889ed0e494eccca3",
+    "dist/2022-11-01/rustc-beta-i686-pc-windows-msvc.tar.xz": "e9af106c009e5fa0da36450a7a89a148ec176bd672ff636010846ab978804e4a",
+    "dist/2022-11-01/rustc-beta-i686-unknown-linux-gnu.tar.gz": "546e7b52f7f9e8c9a99163265dbc8a5ce65dac0fef4f6e1dc8b1bed79f0a24c3",
+    "dist/2022-11-01/rustc-beta-i686-unknown-linux-gnu.tar.xz": "b5ea7fc6016a4abcae3337261724ca2bd21025856134e1c2a1a1922d12ec19a8",
+    "dist/2022-11-01/rustc-beta-mips-unknown-linux-gnu.tar.gz": "0f3e0c8e7883dc7ebbec38e1f3446a33651ebba9a725443856b09ae7e8bcfec0",
+    "dist/2022-11-01/rustc-beta-mips-unknown-linux-gnu.tar.xz": "42871f7f098008f61f6cfd3cf78240156280cc7f5e52860d8125e22b3733a207",
+    "dist/2022-11-01/rustc-beta-mips64-unknown-linux-gnuabi64.tar.gz": "ded0d4da36a0658d46c6705c04fa40d0894b6e113776d2ef8e954e9675e98f9a",
+    "dist/2022-11-01/rustc-beta-mips64-unknown-linux-gnuabi64.tar.xz": "2f9ec1ba69a7abbe4efbc5fa00715f520b4c69792b96e98ed8a72e3f798eb137",
+    "dist/2022-11-01/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "090431409021fa0167576c717cf5daac750f9baf7badc3bc031547dad8dedb18",
+    "dist/2022-11-01/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "0542d0336c8cdacf8a830d2a7c3218b76a00ae37db23fb2f12b928bb7b7dd488",
+    "dist/2022-11-01/rustc-beta-mipsel-unknown-linux-gnu.tar.gz": "2d6db76bc5242af8c2199c5e74f152bbd8103477855379e7c5c200b498ccf901",
+    "dist/2022-11-01/rustc-beta-mipsel-unknown-linux-gnu.tar.xz": "0dc803a305497cc905f3937691e4f1679c72a385b57ee931b19ac5347052c502",
+    "dist/2022-11-01/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "809f547fb5c27c7d15816642839f9ff5fee20f03a3ce390d5b2bfdc983a7c7e2",
+    "dist/2022-11-01/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "bd8403226676b78b40c7a494b3a89f9bed956e7eedf3a65a61cba41a6382f5b6",
+    "dist/2022-11-01/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "12cd357dc72d67911a521dc0ea44a8d05bc4c214a7f6b9e88872ddc03811dc15",
+    "dist/2022-11-01/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "d92f790cabb85373455b5adee9e692dc934dff60eccb70c077f29cde35e7cd00",
+    "dist/2022-11-01/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "a175a2b7d948459c12f44592c1ee5c79825a120557ff0c488fb0bd4e45c7ee99",
+    "dist/2022-11-01/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "d047a4ed562cc91469785fed44d97061d60e1f9c677b5de05245648373df111f",
+    "dist/2022-11-01/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "1b1f20032337e6a0b5e4745a3542a5638747bf2f3b62b2eb855c0ea1ac54d81c",
+    "dist/2022-11-01/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "c8a46c9c002ce19e940a449a4787055b4ad45076a606bd68626a1c8d892d8191",
+    "dist/2022-11-01/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "547c670fd6a5f38f98e7b47daaf6822fd5a1abd5a7c11b6f2b5838cb145c615e",
+    "dist/2022-11-01/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "16a0783135c22b64541cbf9201e5f84ab4befbc9ec0117f3e9639cd42dcb81bf",
+    "dist/2022-11-01/rustc-beta-x86_64-apple-darwin.tar.gz": "3121d060a0306c539334fb42c0c6edb6295eb4b5d05b63e55df98d5dc1cb0eba",
+    "dist/2022-11-01/rustc-beta-x86_64-apple-darwin.tar.xz": "4697febb60fdecb5cd70bde0cffad77cdcf8cce057349b4e1f26e3dd4f2f4a51",
+    "dist/2022-11-01/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "c33bb5e98d83f0a7393c631b6b53eb4a8517bdbf506e1ceb6f0bdd8493fa24b9",
+    "dist/2022-11-01/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "167e1ab52c4478e6aa8b2bea563f2d8caf3605158731a892181f9d24b027ffff",
+    "dist/2022-11-01/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "efbe536d85810f2edb6bb7232617f12d3f208e077d177c24f507ff02c8e83a11",
+    "dist/2022-11-01/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "b6acaa3206a3af7fe0e97d4d9211fc76ba972afcdd188443a72027dd34236658",
+    "dist/2022-11-01/rustc-beta-x86_64-unknown-freebsd.tar.gz": "8eb739094411afb56ad791b84aa2ddcd2c98b6ca5a4c1cd7fa631571702f1d67",
+    "dist/2022-11-01/rustc-beta-x86_64-unknown-freebsd.tar.xz": "4572c19bf416c188a3691cc9542422b92a124594bdf83c82213d07a3aaeef465",
+    "dist/2022-11-01/rustc-beta-x86_64-unknown-illumos.tar.gz": "eca080758173b3bee5a1ed7d04473a8334422fc58c762031877e690a255202c8",
+    "dist/2022-11-01/rustc-beta-x86_64-unknown-illumos.tar.xz": "68b1ced7efbd6bb4cac647e7417b2ad982f58a1cc546b9391213e85e5852ce6c",
+    "dist/2022-11-01/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "3a4870b33c0f223dc295fcf3f1c4e331a2631dbc07279f4ca7452d86c5f6e730",
+    "dist/2022-11-01/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "556821823576a5c0387f0dc89139d3cddc2a17072199607c352fe4b190b7f02f",
+    "dist/2022-11-01/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "4e1723c8f268eecc9bf3efb16241ce03bf109b9f7c6f4f62e430b7ccd1c092cb",
+    "dist/2022-11-01/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "47bb3fb8f8529f19fa9725a43a57abd8bc3c7b2a30e17f86b137df0c57a3c549",
+    "dist/2022-11-01/rustc-beta-x86_64-unknown-netbsd.tar.gz": "530c24d950028d0745110672fad230da8a2a0e4cd4e5ac5afcf1ff8562288925",
+    "dist/2022-11-01/rustc-beta-x86_64-unknown-netbsd.tar.xz": "cd3654b33b3a8e7fbcde2e380bf2914cb07fe6f8355c8810a5bcfe3a05d63f84",
+    "dist/2022-11-01/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "47527c62b813c0612b80c864b3720b7e0673eb2dd762887254fd6a80f11c94b0",
+    "dist/2022-11-01/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "82248dd276ecc0fd45031ba131cb2c870a4b3c09b822d8ad4454f26f506d7810",
+    "dist/2022-11-01/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "fdc9cc842850023e7c22ac22173a18aa5383a2e2fecb713c802e59d55cc5232d",
+    "dist/2022-11-01/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "10ddbe6a89cadde47f6f52ef0c4f9ab08f4ced2281fadd1ecbc6a0e4736c9787",
+    "dist/2022-11-01/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "2135c6d129fa7ecd831e451e173c38677ea39975a91cd6092252e4c0bd93eeaa",
+    "dist/2022-11-01/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "387d43021bd0ec1586155d1b977470646a68e2625fc192331b76180755687d37",
+    "dist/2022-11-01/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "41da916cbac667f5f238c3aee3bfb230c3345a4d625779c1fcf57813c9138696",
+    "dist/2022-11-01/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "f28cf712bc617f1755e78a7a442633a7aff78857b98d9aae473effc5684ce8aa",
+    "dist/2022-11-01/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "065fd7fdcb9f38a9c08b256b46627c8ce38a6433dc162034a306f4d4f4627a31",
+    "dist/2022-11-01/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "1fc14261867b540e6d014cc5a21c557d0a4bb31d2619ae98a330585915365614",
+    "dist/2022-11-01/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "1a9ebea072c333e99a3339a87ac3971deb4fe2baca9bd0e8429321a81cce847f",
+    "dist/2022-11-01/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "1c7a72cf8e9cda52d02bd5f4244164aea829914087501cb0bedd75f05f464a91",
+    "dist/2022-11-01/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "1f8405178138601f65dbe10f93d326c705ea91f9e7200f253d6123f618d09ad8",
+    "dist/2022-11-01/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "00365767eb739ecd82c6264795768baba07a101aacec59e137a7495afd0b3288",
+    "dist/2022-11-01/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "b2e4c4672f440e1f97913497ee158280cb8ed70c81cb47a85e5382cb3de0b03c",
+    "dist/2022-11-01/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "01bea91a3ab8203b32cbd1fb2945a1eca68179e8f4011e387a230587fc2736a4",
+    "dist/2022-11-01/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "2d0db2a9f187d300c183cfe2ac6778547ab6492720c0e9df3e78f5b06004e758",
+    "dist/2022-11-01/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "b89b02b9fdedb9a93dee602dd9c818e97c397ef73c3f1d0164ddd2ab809cddc2",
+    "dist/2022-11-01/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "4498a8e6d0ae7a793a9f3c84e3bbe9218c37053a1f3dd6a0b4ad7edd1a41493f",
+    "dist/2022-11-01/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "27041aa61921b767be6670f0f08aad1a1ab8d09d0e86cd2e431e54744ed25d0b",
+    "dist/2022-11-01/rustfmt-nightly-mips-unknown-linux-gnu.tar.gz": "870923556049bd4be8da03fa6d876fa8249e4acf0ea2c83850c4e23a09fe577f",
+    "dist/2022-11-01/rustfmt-nightly-mips-unknown-linux-gnu.tar.xz": "8c05e1f60a59064c05db7522245d482b559ae858a5c9c772db81a05daa60a4c6",
+    "dist/2022-11-01/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "1a88c20701cc6f7dd2b3e32bef72a78936c39095a35237fc4a4b5a497790a048",
+    "dist/2022-11-01/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "9b5ccf5413650144a79f382efd12204aeddf3421ea6f06615afc489cdf30691e",
+    "dist/2022-11-01/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "4bcf264ba7ce42aee79d76ba0f19818aff71ee666ac4ac417c2a60b0dafa8865",
+    "dist/2022-11-01/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "fd6ff248063cd53ee6b0538c8b3c8af1758ae5c42cc2f5fc805ab96799033f7d",
+    "dist/2022-11-01/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.gz": "a03cf4d831ba58d1e562d6fd48dd7558d9034046ae7050883eb1d0fc2cad6895",
+    "dist/2022-11-01/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.xz": "30be7166fa091929d1a4b5eed4b72c4b5c94898861f4e91fb45a2b9ad4333ca6",
+    "dist/2022-11-01/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "59f3910a559994863f1910ffcf34cae348d0c07128d00ce5ac085bbca349f7f5",
+    "dist/2022-11-01/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "817df1ddab344e47df34c73918c5bbb3a7b33048f8ac5c5794cb35624f5bce24",
+    "dist/2022-11-01/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "7825a5f19cb29245de96eb22183fbfc38b75eda0ba63d2255fa062f9c6764bbf",
+    "dist/2022-11-01/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "0d6384aa1162d821edb6d22326b0a1d481e6735d4343a70df7bead694bb71567",
+    "dist/2022-11-01/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "aef195c86920cfecafc29f80ce6a88c704f09d72011ad1fd462564bf858c75a6",
+    "dist/2022-11-01/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "da43e621a113d88f7c4805f70cb5208bac66f97c68485a60f95cf11f5ae0f55c",
+    "dist/2022-11-01/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "2603b5061d059655e3298df94875fa4876d5ea9af1e04dd197ec5cefa3e1eb4c",
+    "dist/2022-11-01/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "f79606c20ce3bf64a9ede63e878cda199e7f1b0b13f40bd51d7108b3d4c72cb0",
+    "dist/2022-11-01/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "f6c46ffbb38f8838c496e1eddea7d6f27392699abfafd0d13b234eee39238181",
+    "dist/2022-11-01/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "9244fc29cd3c32c971f44fcdaa26623b8976efaf0a4705b573798af5b0b0896e",
+    "dist/2022-11-01/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "bd502f9105d56af252da1038687a4e942a477c7047cac9730de7414cdbbfbc48",
+    "dist/2022-11-01/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "426785558da44683a554c542475c9402932c72d63148c37917e8cc6e429ad413",
+    "dist/2022-11-01/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "52646c86ad464c5803f74ab37166dc1692383bc5fd94818bd579e518c327251e",
+    "dist/2022-11-01/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "67d1490a41932c2a89981e18c9735d4437faedd1e708e26f75dfd21d4709488b",
+    "dist/2022-11-01/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "9feb7b704a6d3e6b019a99ecd033042ce81a4b126e4288e0b4772266c6e0a65e",
+    "dist/2022-11-01/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "fba240009d3f27e04200133120c46112ac64281e99952da44d6fe8a01557f236",
+    "dist/2022-11-01/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "ce15bda4992ada52f94dae6b1a0e220f26324acefb62094035abe112aa878fec",
+    "dist/2022-11-01/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "189a8579cf3fe99b9c084821ce1ee9bec6977470341e2ae45b859dcdacf65d21",
+    "dist/2022-11-01/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "15abcd9e43f2c87fc894b3e280a99865508f9079badcbe7be07c6b79e85f01b4",
+    "dist/2022-11-01/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "f52dab31a428e568518b00d3afc1426569810bcd20a7db1c0093200c6db86d24",
+    "dist/2022-11-01/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "57ec35b95a5fd803b2d4dacf7657847111a6cc9bda3cda962174965cd6005085",
+    "dist/2022-11-01/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "96987349e20e3f602bb6f518924660c09a4575887730b1bbe36adee921921956",
+    "dist/2022-11-01/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "76d6f5882573169985f5b8a9e13cee8bbe3bd3b423ad287280a0809c6a5efc5a",
+    "dist/2022-11-01/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "9a2c79685b4ac57efea65e43dafa28b59cead1c14e98f10e0196cb2cfd2fa0b6",
+    "dist/2022-11-01/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "0be98b45af7e666955e6e0adb5b4cc3f5517c8d144702b10daedd053450cd5d5",
+    "dist/2022-11-01/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "ae9ac6e1c0e14bfba746f3a85bfa3f009113d0edbf880a2cf20ece6046ee27bb"
   }
 }
diff --git a/src/test/assembly/strict_provenance.rs b/src/test/assembly/strict_provenance.rs
new file mode 100644 (file)
index 0000000..01f1957
--- /dev/null
@@ -0,0 +1,37 @@
+// assembly-output: emit-asm
+// compile-flags: -Copt-level=1
+// only-x86_64
+// min-llvm-version: 15.0
+#![crate_type = "rlib"]
+
+// CHECK-LABEL: old_style
+// CHECK: movq %{{.*}}, %rax
+// CHECK: orq $1, %rax
+// CHECK: retq
+#[no_mangle]
+pub fn old_style(a: *mut u8) -> *mut u8 {
+    (a as usize | 1) as *mut u8
+}
+
+// CHECK-LABEL: cheri_compat
+// CHECK: movq %{{.*}}, %rax
+// CHECK: orq $1, %rax
+// CHECK: retq
+#[no_mangle]
+pub fn cheri_compat(a: *mut u8) -> *mut u8 {
+    let old = a as usize;
+    let new = old | 1;
+    let diff = new.wrapping_sub(old);
+    a.wrapping_add(diff)
+}
+
+// CHECK-LABEL: definitely_not_a_null_pointer
+// CHECK: movq %{{.*}}, %rax
+// CHECK: orq $1, %rax
+// CHECK: retq
+#[no_mangle]
+pub fn definitely_not_a_null_pointer(a: *mut u8) -> *mut u8 {
+    let old = a as usize;
+    let new = old | 1;
+    a.wrapping_sub(old).wrapping_add(new)
+}
index b4fda5f8c8428d0c879382dbf0a6e616af8315f6..9061d7432a3fa862018919df76baa71f36febb2e 100644 (file)
@@ -27,7 +27,7 @@ trait Copy { }
 //x86_64: define win64cc void @has_efiapi
 //i686: define void @has_efiapi
 //aarch64: define dso_local void @has_efiapi
-//arm: define dso_local void @has_efiapi
+//arm: define dso_local arm_aapcscc void @has_efiapi
 //riscv: define dso_local void @has_efiapi
 #[no_mangle]
 pub extern "efiapi" fn has_efiapi() {}
diff --git a/src/test/codegen/auxiliary/static_dllimport_aux.rs b/src/test/codegen/auxiliary/static_dllimport_aux.rs
new file mode 100644 (file)
index 0000000..afb0dc4
--- /dev/null
@@ -0,0 +1,13 @@
+use std::sync::atomic::{AtomicPtr, Ordering};
+
+#[inline(always)]
+pub fn memrchr() {
+    fn detect() {}
+
+    static CROSS_CRATE_STATIC_ITEM: AtomicPtr<()> = AtomicPtr::new(detect as *mut ());
+
+    unsafe {
+        let fun = CROSS_CRATE_STATIC_ITEM.load(Ordering::SeqCst);
+        std::mem::transmute::<*mut (), fn()>(fun)()
+    }
+}
diff --git a/src/test/codegen/enum-match.rs b/src/test/codegen/enum-match.rs
new file mode 100644 (file)
index 0000000..efab189
--- /dev/null
@@ -0,0 +1,112 @@
+// compile-flags: -Copt-level=1
+// only-x86_64
+
+#![crate_type = "lib"]
+
+// Check each of the 3 cases for `codegen_get_discr`.
+
+// Case 0: One tagged variant.
+pub enum Enum0 {
+    A(bool),
+    B,
+}
+
+// CHECK: define i8 @match0{{.*}}
+// CHECK-NEXT: start:
+// CHECK-NEXT: %1 = icmp eq i8 %0, 2
+// CHECK-NEXT: %2 = and i8 %0, 1
+// CHECK-NEXT: %.0 = select i1 %1, i8 13, i8 %2
+#[no_mangle]
+pub fn match0(e: Enum0) -> u8 {
+    use Enum0::*;
+    match e {
+        A(b) => b as u8,
+        B => 13,
+    }
+}
+
+// Case 1: Niche values are on a boundary for `range`.
+pub enum Enum1 {
+    A(bool),
+    B,
+    C,
+}
+
+// CHECK: define i8 @match1{{.*}}
+// CHECK-NEXT: start:
+// CHECK-NEXT: %1 = icmp ugt i8 %0, 1
+// CHECK-NEXT: %2 = zext i8 %0 to i64
+// CHECK-NEXT: %3 = add nsw i64 %2, -1
+// CHECK-NEXT: %_2 = select i1 %1, i64 %3, i64 0
+// CHECK-NEXT: switch i64 %_2, label {{.*}} [
+#[no_mangle]
+pub fn match1(e: Enum1) -> u8 {
+    use Enum1::*;
+    match e {
+        A(b) => b as u8,
+        B => 13,
+        C => 100,
+    }
+}
+
+// Case 2: Special cases don't apply.
+pub enum X {
+    _2=2, _3, _4, _5, _6, _7, _8, _9, _10, _11,
+    _12, _13, _14, _15, _16, _17, _18, _19, _20,
+    _21, _22, _23, _24, _25, _26, _27, _28, _29,
+    _30, _31, _32, _33, _34, _35, _36, _37, _38,
+    _39, _40, _41, _42, _43, _44, _45, _46, _47,
+    _48, _49, _50, _51, _52, _53, _54, _55, _56,
+    _57, _58, _59, _60, _61, _62, _63, _64, _65,
+    _66, _67, _68, _69, _70, _71, _72, _73, _74,
+    _75, _76, _77, _78, _79, _80, _81, _82, _83,
+    _84, _85, _86, _87, _88, _89, _90, _91, _92,
+    _93, _94, _95, _96, _97, _98, _99, _100, _101,
+    _102, _103, _104, _105, _106, _107, _108, _109,
+    _110, _111, _112, _113, _114, _115, _116, _117,
+    _118, _119, _120, _121, _122, _123, _124, _125,
+    _126, _127, _128, _129, _130, _131, _132, _133,
+    _134, _135, _136, _137, _138, _139, _140, _141,
+    _142, _143, _144, _145, _146, _147, _148, _149,
+    _150, _151, _152, _153, _154, _155, _156, _157,
+    _158, _159, _160, _161, _162, _163, _164, _165,
+    _166, _167, _168, _169, _170, _171, _172, _173,
+    _174, _175, _176, _177, _178, _179, _180, _181,
+    _182, _183, _184, _185, _186, _187, _188, _189,
+    _190, _191, _192, _193, _194, _195, _196, _197,
+    _198, _199, _200, _201, _202, _203, _204, _205,
+    _206, _207, _208, _209, _210, _211, _212, _213,
+    _214, _215, _216, _217, _218, _219, _220, _221,
+    _222, _223, _224, _225, _226, _227, _228, _229,
+    _230, _231, _232, _233, _234, _235, _236, _237,
+    _238, _239, _240, _241, _242, _243, _244, _245,
+    _246, _247, _248, _249, _250, _251, _252, _253,
+}
+
+pub enum Enum2 {
+    A(X),
+    B,
+    C,
+    D,
+    E,
+}
+
+// CHECK: define i8 @match2{{.*}}
+// CHECK-NEXT: start:
+// CHECK-NEXT: %1 = add i8 %0, 2
+// CHECK-NEXT: %2 = zext i8 %1 to i64
+// CHECK-NEXT: %3 = icmp ult i8 %1, 4
+// CHECK-NEXT: %4 = add nuw nsw i64 %2, 1
+// CHECK-NEXT: %_2 = select i1 %3, i64 %4, i64 0
+// CHECK-NEXT: switch i64 %_2, label {{.*}} [
+#[no_mangle]
+pub fn match2(e: Enum2) -> u8 {
+    use Enum2::*;
+    match e {
+        A(b) => b as u8,
+        B => 13,
+        C => 100,
+        D => 200,
+        E => 250,
+    }
+}
diff --git a/src/test/codegen/issue-81408-dllimport-thinlto-windows.rs b/src/test/codegen/issue-81408-dllimport-thinlto-windows.rs
new file mode 100644 (file)
index 0000000..0b6ab4f
--- /dev/null
@@ -0,0 +1,15 @@
+// compile-flags: -O -C lto=thin -C prefer-dynamic=no
+// only-windows
+// aux-build:static_dllimport_aux.rs
+
+// Test that on Windows, when performing ThinLTO, we do not mark cross-crate static items with
+// dllimport because lld does not fix the symbol names for us.
+
+extern crate static_dllimport_aux;
+
+// CHECK-LABEL: @{{.+}}CROSS_CRATE_STATIC_ITEM{{.+}} =
+// CHECK-SAME: external local_unnamed_addr global %"{{.+}}AtomicPtr
+
+pub fn main() {
+    static_dllimport_aux::memrchr();
+}
index 314ba40b0e3d0b8a4208d565fca78fd0a80d34ca..61ec6a81243d5f2214da54b30e523cf26a64cb09 100644 (file)
@@ -10,7 +10,7 @@
 //
 // cdb-command:dx m,d
 // cdb-check:m,d              [Type: std::sync::mutex::Mutex<i32>]
-// cdb-check:    [...] inner            [Type: std::sys_common::mutex::MovableMutex]
+// cdb-check:    [...] inner            [Type: std::sys::windows::locks::mutex::Mutex]
 // cdb-check:    [...] poison           [Type: std::sync::poison::Flag]
 // cdb-check:    [...] data             : 0 [Type: core::cell::UnsafeCell<i32>]
 
index ed9aae16b0db15271cbe518254ad3cd7fe64eb9b..bc42f92f053d525b4d0d34907b7435d9196c6955 100644 (file)
@@ -16,7 +16,7 @@
 // cdb-command:dx r
 // cdb-check:r                [Type: std::sync::rwlock::RwLockReadGuard<i32>]
 // cdb-check:    [...] data             : NonNull([...]: 0) [Type: core::ptr::non_null::NonNull<i32>]
-// cdb-check:    [...] inner_lock       : [...] [Type: std::sys_common::rwlock::MovableRwLock *]
+// cdb-check:    [...] inner_lock       : [...] [Type: std::sys::windows::locks::rwlock::RwLock *]
 
 #[allow(unused_variables)]
 
diff --git a/src/test/incremental/issue-101518.rs b/src/test/incremental/issue-101518.rs
new file mode 100644 (file)
index 0000000..501be17
--- /dev/null
@@ -0,0 +1,31 @@
+// revisions: cfail1
+// should-ice
+// error-pattern: forcing query
+// known-bug: #101518
+
+#[derive(PartialEq, Eq)]
+struct Id<'a> {
+    ns: &'a str,
+}
+fn visit_struct() {
+    let id = Id { ns: "random1" };
+    const FLAG: Id<'static> = Id {
+        ns: "needs_to_be_the_same",
+    };
+    match id {
+        FLAG => {}
+        _ => {}
+    }
+}
+fn visit_struct2() {
+    let id = Id { ns: "random2" };
+    const FLAG: Id<'static> = Id {
+        ns: "needs_to_be_the_same",
+    };
+    match id {
+        FLAG => {}
+        _ => {}
+    }
+}
+
+fn main() {}
diff --git a/src/test/mir-opt/building/custom/references.immut_ref.built.after.mir b/src/test/mir-opt/building/custom/references.immut_ref.built.after.mir
new file mode 100644 (file)
index 0000000..4a5ddde
--- /dev/null
@@ -0,0 +1,14 @@
+// MIR for `immut_ref` after built
+
+fn immut_ref(_1: &i32) -> &i32 {
+    let mut _0: &i32;                    // return place in scope 0 at $DIR/references.rs:+0:30: +0:34
+    let mut _2: *const i32;              // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+
+    bb0: {
+        _2 = &raw const (*_1);           // scope 0 at $DIR/references.rs:+0:1: +0:34
+        Retag([raw] _2);                 // scope 0 at $DIR/references.rs:+0:1: +0:34
+        _0 = &(*_2);                     // scope 0 at $DIR/references.rs:+0:1: +0:34
+        Retag(_0);                       // scope 0 at $DIR/references.rs:+0:1: +0:34
+        return;                          // scope 0 at $DIR/references.rs:+0:1: +0:34
+    }
+}
diff --git a/src/test/mir-opt/building/custom/references.mut_ref.built.after.mir b/src/test/mir-opt/building/custom/references.mut_ref.built.after.mir
new file mode 100644 (file)
index 0000000..ec8509f
--- /dev/null
@@ -0,0 +1,14 @@
+// MIR for `mut_ref` after built
+
+fn mut_ref(_1: &mut i32) -> &mut i32 {
+    let mut _0: &mut i32;                // return place in scope 0 at $DIR/references.rs:+0:32: +0:40
+    let mut _2: *mut i32;                // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+
+    bb0: {
+        _2 = &raw mut (*_1);             // scope 0 at $DIR/references.rs:+0:1: +0:40
+        Retag([raw] _2);                 // scope 0 at $DIR/references.rs:+0:1: +0:40
+        _0 = &mut (*_2);                 // scope 0 at $DIR/references.rs:+0:1: +0:40
+        Retag(_0);                       // scope 0 at $DIR/references.rs:+0:1: +0:40
+        return;                          // scope 0 at $DIR/references.rs:+0:1: +0:40
+    }
+}
diff --git a/src/test/mir-opt/building/custom/references.rs b/src/test/mir-opt/building/custom/references.rs
new file mode 100644 (file)
index 0000000..dee8572
--- /dev/null
@@ -0,0 +1,43 @@
+#![feature(custom_mir, core_intrinsics)]
+
+extern crate core;
+use core::intrinsics::mir::*;
+use core::ptr::{addr_of, addr_of_mut};
+
+// EMIT_MIR references.mut_ref.built.after.mir
+#[custom_mir(dialect = "runtime", phase = "optimized")]
+pub fn mut_ref(x: &mut i32) -> &mut i32 {
+    mir!(
+        let t: *mut i32;
+
+        {
+            t = addr_of_mut!(*x);
+            RetagRaw(t);
+            RET = &mut *t;
+            Retag(RET);
+            Return()
+        }
+    )
+}
+
+// EMIT_MIR references.immut_ref.built.after.mir
+#[custom_mir(dialect = "runtime", phase = "optimized")]
+pub fn immut_ref(x: &i32) -> &i32 {
+    mir!(
+        let t: *const i32;
+
+        {
+            t = addr_of!(*x);
+            RetagRaw(t);
+            RET = & *t;
+            Retag(RET);
+            Return()
+        }
+    )
+}
+
+fn main() {
+    let mut x = 5;
+    assert_eq!(*mut_ref(&mut x), 5);
+    assert_eq!(*immut_ref(&x), 5);
+}
diff --git a/src/test/mir-opt/building/custom/simple_assign.rs b/src/test/mir-opt/building/custom/simple_assign.rs
new file mode 100644 (file)
index 0000000..ec6dbe1
--- /dev/null
@@ -0,0 +1,37 @@
+#![feature(custom_mir, core_intrinsics)]
+
+extern crate core;
+use core::intrinsics::mir::*;
+
+// EMIT_MIR simple_assign.simple.built.after.mir
+#[custom_mir(dialect = "built")]
+pub fn simple(x: i32) -> i32 {
+    mir!(
+        let temp1: i32;
+        let temp2: _;
+
+        {
+            temp1 = x;
+            Goto(exit)
+        }
+
+        exit = {
+            temp2 = Move(temp1);
+            RET = temp2;
+            Return()
+        }
+    )
+}
+
+// EMIT_MIR simple_assign.simple_ref.built.after.mir
+#[custom_mir(dialect = "built")]
+pub fn simple_ref(x: &mut i32) -> &mut i32 {
+    mir!({
+        RET = Move(x);
+        Return()
+    })
+}
+
+fn main() {
+    assert_eq!(5, simple(5));
+}
diff --git a/src/test/mir-opt/building/custom/simple_assign.simple.built.after.mir b/src/test/mir-opt/building/custom/simple_assign.simple.built.after.mir
new file mode 100644 (file)
index 0000000..a5a2834
--- /dev/null
@@ -0,0 +1,18 @@
+// MIR for `simple` after built
+
+fn simple(_1: i32) -> i32 {
+    let mut _0: i32;                     // return place in scope 0 at $DIR/simple_assign.rs:+0:26: +0:29
+    let mut _2: i32;                     // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+    let mut _3: i32;                     // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+
+    bb0: {
+        _2 = _1;                         // scope 0 at $DIR/simple_assign.rs:+0:1: +0:29
+        goto -> bb1;                     // scope 0 at $DIR/simple_assign.rs:+0:1: +0:29
+    }
+
+    bb1: {
+        _3 = move _2;                    // scope 0 at $DIR/simple_assign.rs:+0:1: +0:29
+        _0 = _3;                         // scope 0 at $DIR/simple_assign.rs:+0:1: +0:29
+        return;                          // scope 0 at $DIR/simple_assign.rs:+0:1: +0:29
+    }
+}
diff --git a/src/test/mir-opt/building/custom/simple_assign.simple_ref.built.after.mir b/src/test/mir-opt/building/custom/simple_assign.simple_ref.built.after.mir
new file mode 100644 (file)
index 0000000..6c90f01
--- /dev/null
@@ -0,0 +1,10 @@
+// MIR for `simple_ref` after built
+
+fn simple_ref(_1: &mut i32) -> &mut i32 {
+    let mut _0: &mut i32;                // return place in scope 0 at $DIR/simple_assign.rs:+0:35: +0:43
+
+    bb0: {
+        _0 = move _1;                    // scope 0 at $DIR/simple_assign.rs:+0:1: +0:43
+        return;                          // scope 0 at $DIR/simple_assign.rs:+0:1: +0:43
+    }
+}
index 5c9603352989ab091cfc994a8d6b96c605792d68..eff18ab48ab4f216f2e08207b8fef693608ab898 100644 (file)
@@ -9,4 +9,4 @@ all:
        $(RUSTC) empty.rs --cfg bar 2>&1 | $(CGREP) '"-ltesta" "-ltestb" "-ltesta"'
        $(RUSTC) empty.rs 2>&1 | $(CGREP) '"-ltesta"'
        $(RUSTC) empty.rs 2>&1 | $(CGREP) -v '"-ltestb"'
-       $(RUSTC) empty.rs 2>&1 | $(CGREP) -v '"-ltesta" "-ltesta"'
+       $(RUSTC) empty.rs 2>&1 | $(CGREP) -v '"-ltesta" "-ltesta" "-ltesta"'
index e48ffd6413cd078d7fe10922038a1ba51a9315d9..19178c5bd49573296acba514aa1a2c3b2fe9d5a3 100644 (file)
@@ -5,3 +5,6 @@
 
 #[link(name = "testa")]
 extern "C" {}
+
+#[link(name = "testa")]
+extern "C" {}
index 1032f3408f062a9a93f76feddcfe895fff403901..1831ab38fab49d9728505491e3d15e4e9b653773 100644 (file)
@@ -3,7 +3,7 @@ include ../tools.mk
 all: off packed unpacked
 
 ifeq ($(UNAME),Darwin)
-# If disabled, don't run dsymutil
+# If disabled, don't run `dsymutil`.
 off:
        rm -rf $(TMPDIR)/*.dSYM
        $(RUSTC) foo.rs -g -C split-debuginfo=off
@@ -29,98 +29,280 @@ unpacked:
        [ ! -d $(TMPDIR)/foo.dSYM ]
 else
 ifdef IS_WINDOWS
-# Windows only supports =packed
+# Windows only supports packed debuginfo - nothing to test.
 off:
 packed:
 unpacked:
 else
+# Some non-Windows, non-Darwin platforms are not stable, and some are.
 ifeq ($(UNAME),Linux)
   UNSTABLEOPTS :=
 else
   UNSTABLEOPTS := -Zunstable-options
 endif
 
+# - Debuginfo in `.o` files
+# - `.o` deleted
+# - `.dwo` never created
+# - `.dwp` never created
 off:
        $(RUSTC) foo.rs -g -C $(UNSTABLEOPTS) split-debuginfo=off
        [ ! -f $(TMPDIR)/*.dwp ]
        [ ! -f $(TMPDIR)/*.dwo ]
-
        $(RUSTC) foo.rs -g
        [ ! -f $(TMPDIR)/*.dwp ]
        [ ! -f $(TMPDIR)/*.dwo ]
 
-packed: packed-split packed-single
+packed: packed-split packed-single packed-lto packed-remapped packed-crosscrate
 
+# - Debuginfo in `.dwo` files
+# - `.o` deleted
+# - `.dwo` deleted
+# - `.dwp` present
 packed-split:
        $(RUSTC) foo.rs -g $(UNSTABLEOPTS) -C split-debuginfo=packed -Zsplit-dwarf-kind=split
-       ls $(TMPDIR)/*.dwp
-       rm -rf $(TMPDIR)/*.dwp $(TMPDIR)/*.dwo
+       ls $(TMPDIR)/*.o && exit 1 || exit 0
+       ls $(TMPDIR)/*.dwo && exit 1 || exit 0
+       rm $(TMPDIR)/foo.dwp
+       rm $(TMPDIR)/$(call BIN,foo)
 
+# - Debuginfo in `.o` files
+# - `.o` deleted
+# - `.dwo` never created
+# - `.dwp` present
 packed-single:
        $(RUSTC) foo.rs -g $(UNSTABLEOPTS) -C split-debuginfo=packed -Zsplit-dwarf-kind=single
-       ls $(TMPDIR)/*.dwp
+       ls $(TMPDIR)/*.o && exit 1 || exit 0
+       ls $(TMPDIR)/*.dwo && exit 1 || exit 0
+       rm $(TMPDIR)/foo.dwp
+       rm $(TMPDIR)/$(call BIN,foo)
+
+packed-lto: packed-lto-split packed-lto-single
+
+# - rmeta file added to rlib, no object files are generated and thus no debuginfo is generated
+# - `.o` never created
+# - `.dwo` never created
+# - `.dwp` never created
+packed-lto-split:
+       $(RUSTC) baz.rs -g $(UNSTABLEOPTS) -Csplit-debuginfo=packed -Zsplit-dwarf-kind=split \
+               --crate-type=rlib -Clinker-plugin-lto
+       ls $(TMPDIR)/*.o && exit 1 || exit 0
+       ls $(TMPDIR)/*.dwo && exit 1 || exit 0
+       ls $(TMPDIR)/*.dwp && exit 1 || exit 0
+       rm $(TMPDIR)/libbaz.rlib
+
+# - rmeta file added to rlib, no object files are generated and thus no debuginfo is generated
+# - `.o` never created
+# - `.dwo` never created
+# - `.dwp` never created
+packed-lto-single:
+       $(RUSTC) baz.rs -g $(UNSTABLEOPTS) -Csplit-debuginfo=packed -Zsplit-dwarf-kind=single \
+               --crate-type=rlib -Clinker-plugin-lto
+       ls $(TMPDIR)/*.o && exit 1 || exit 0
        ls $(TMPDIR)/*.dwo && exit 1 || exit 0
-       rm -rf $(TMPDIR)/*.dwp
+       ls $(TMPDIR)/*.dwp && exit 1 || exit 0
+       rm $(TMPDIR)/libbaz.rlib
 
 packed-remapped: packed-remapped-split packed-remapped-single
 
+# - Debuginfo in `.dwo` files
+# - `.o` and binary refer to remapped `.dwo` paths which do not exist
+# - `.o` deleted
+# - `.dwo` deleted
+# - `.dwp` present
 packed-remapped-split:
        $(RUSTC) $(UNSTABLEOPTS) -C split-debuginfo=packed -C debuginfo=2 \
                -Z split-dwarf-kind=split --remap-path-prefix $(TMPDIR)=/a foo.rs -g
        objdump -Wi $(TMPDIR)/foo | grep DW_AT_GNU_dwo_name | (! grep $(TMPDIR)) || exit 1
+       ls $(TMPDIR)/*.o && exit 1 || exit 0
+       ls $(TMPDIR)/*.dwo && exit 1 || exit 0
+       rm $(TMPDIR)/foo.dwp
+       rm $(TMPDIR)/$(call BIN,foo)
 
+# - Debuginfo in `.o` files
+# - `.o` and binary refer to remapped `.o` paths which do not exist
+# - `.o` deleted
+# - `.dwo` never created
+# - `.dwp` present
 packed-remapped-single:
        $(RUSTC) $(UNSTABLEOPTS) -C split-debuginfo=packed -C debuginfo=2 \
                -Z split-dwarf-kind=single --remap-path-prefix $(TMPDIR)=/a foo.rs -g
        objdump -Wi $(TMPDIR)/foo | grep DW_AT_GNU_dwo_name | (! grep $(TMPDIR)) || exit 1
+       ls $(TMPDIR)/*.o && exit 1 || exit 0
+       ls $(TMPDIR)/*.dwo && exit 1 || exit 0
+       rm $(TMPDIR)/foo.dwp
+       rm $(TMPDIR)/$(call BIN,foo)
 
 packed-crosscrate: packed-crosscrate-split packed-crosscrate-single
 
+# - Debuginfo in `.dwo` files
+# - (bar) `.rlib` file created, contains `.dwo`
+# - (bar) `.o` deleted
+# - (bar) `.dwo` deleted
+# - (bar) `.dwp` never created
+# - (main) `.o` deleted
+# - (main) `.dwo` deleted
+# - (main) `.dwp` present
 packed-crosscrate-split:
        $(RUSTC) --crate-type lib $(UNSTABLEOPTS) -C split-debuginfo=packed \
                -Zsplit-dwarf-kind=split -C debuginfo=2 -g bar.rs
        ls $(TMPDIR)/*.rlib
+       ls $(TMPDIR)/*.o && exit 1 || exit 0
        ls $(TMPDIR)/*.dwo && exit 1 || exit 0
        ls $(TMPDIR)/*.dwp && exit 1 || exit 0
-       $(RUSTC) --extern bar=$(TMPDIR)/libbar.rlib -Z unstable-options $(UNSTABLEOPTS) \
+       $(RUSTC) --extern bar=$(TMPDIR)/libbar.rlib $(UNSTABLEOPTS) \
                -C split-debuginfo=packed -Zsplit-dwarf-kind=split -C debuginfo=2 -g main.rs
-       rm $(TMPDIR)/*.dwo
+       ls $(TMPDIR)/*.o && exit 1 || exit 0
+       ls $(TMPDIR)/*.dwo && exit 1 || exit 0
        rm $(TMPDIR)/main.dwp
        rm $(TMPDIR)/$(call BIN,main)
 
+# - Debuginfo in `.o` files
+# - (bar) `.rlib` file created, contains `.o`
+# - (bar) `.o` deleted
+# - (bar) `.dwo` never created
+# - (bar) `.dwp` never created
+# - (main) `.o` deleted
+# - (main) `.dwo` never created
+# - (main) `.dwp` present
 packed-crosscrate-single:
        $(RUSTC) --crate-type lib $(UNSTABLEOPTS) -C split-debuginfo=packed \
                -Zsplit-dwarf-kind=single -C debuginfo=2 -g bar.rs
        ls $(TMPDIR)/*.rlib
+       ls $(TMPDIR)/*.o && exit 1 || exit 0
        ls $(TMPDIR)/*.dwo && exit 1 || exit 0
        ls $(TMPDIR)/*.dwp && exit 1 || exit 0
-       $(RUSTC) --extern bar=$(TMPDIR)/libbar.rlib -Z unstable-options $(UNSTABLEOPTS) \
+       $(RUSTC) --extern bar=$(TMPDIR)/libbar.rlib $(UNSTABLEOPTS) \
                -C split-debuginfo=packed -Zsplit-dwarf-kind=single -C debuginfo=2 -g main.rs
+       ls $(TMPDIR)/*.o && exit 1 || exit 0
        ls $(TMPDIR)/*.dwo && exit 1 || exit 0
        rm $(TMPDIR)/main.dwp
        rm $(TMPDIR)/$(call BIN,main)
 
-unpacked: unpacked-split unpacked-single unpacked-remapped-split unpacked-remapped-single
+unpacked: unpacked-split unpacked-single unpacked-lto unpacked-remapped unpacked-crosscrate
 
+# - Debuginfo in `.dwo` files
+# - `.o` deleted
+# - `.dwo` present
+# - `.dwp` never created
 unpacked-split:
        $(RUSTC) foo.rs -g $(UNSTABLEOPTS) -C split-debuginfo=unpacked -Zsplit-dwarf-kind=split
+       ls $(TMPDIR)/*.o && exit 1 || exit 0
+       rm $(TMPDIR)/*.dwo
        ls $(TMPDIR)/*.dwp && exit 1 || exit 0
-       ls $(TMPDIR)/*.dwo
-       rm -rf $(TMPDIR)/*.dwp $(TMPDIR)/*.dwo
+       rm $(TMPDIR)/$(call BIN,foo)
 
+# - Debuginfo in `.o` files
+# - `.o` present
+# - `.dwo` never created
+# - `.dwp` never created
 unpacked-single:
        $(RUSTC) foo.rs -g $(UNSTABLEOPTS) -C split-debuginfo=unpacked -Zsplit-dwarf-kind=single
+       ls $(TMPDIR)/*.o
+       ls $(TMPDIR)/*.dwo && exit 1 || exit 0
+       ls $(TMPDIR)/*.dwp && exit 1 || exit 0
+       rm $(TMPDIR)/$(call BIN,foo)
+
+unpacked-lto: packed-lto-split packed-lto-single
+
+# - rmeta file added to rlib, no object files are generated and thus no debuginfo is generated
+# - `.o` never created
+# - `.dwo` never created
+# - `.dwp` never created
+unpacked-lto-split:
+       $(RUSTC) baz.rs -g $(UNSTABLEOPTS) -Csplit-debuginfo=unpacked -Zsplit-dwarf-kind=split \
+               --crate-type=rlib -Clinker-plugin-lto
+       ls $(TMPDIR)/*.o && exit 1 || exit 0
+       ls $(TMPDIR)/*.dwo && exit 1 || exit 0
        ls $(TMPDIR)/*.dwp && exit 1 || exit 0
+       rm $(TMPDIR)/libbaz.rlib
+
+# - rmeta file added to rlib, no object files are generated and thus no debuginfo is generated
+# - `.o` never created
+# - `.dwo` never created
+# - `.dwp` never created
+unpacked-lto-single:
+       $(RUSTC) baz.rs -g $(UNSTABLEOPTS) -Csplit-debuginfo=unpacked -Zsplit-dwarf-kind=single \
+               --crate-type=rlib -Clinker-plugin-lto
+       ls $(TMPDIR)/*.o && exit 1 || exit 0
        ls $(TMPDIR)/*.dwo && exit 1 || exit 0
+       ls $(TMPDIR)/*.dwp && exit 1 || exit 0
+       rm $(TMPDIR)/libbaz.rlib
+
+unpacked-remapped: unpacked-remapped-split unpacked-remapped-single
 
+# - Debuginfo in `.dwo` files
+# - `.o` and binary refer to remapped `.dwo` paths which do not exist
+# - `.o` deleted
+# - `.dwo` present
+# - `.dwp` never created
 unpacked-remapped-split:
        $(RUSTC) $(UNSTABLEOPTS) -C split-debuginfo=unpacked -C debuginfo=2 \
                -Z split-dwarf-kind=split --remap-path-prefix $(TMPDIR)=/a foo.rs -g
        objdump -Wi $(TMPDIR)/foo | grep DW_AT_GNU_dwo_name | (! grep $(TMPDIR)) || exit 1
+       ls $(TMPDIR)/*.o && exit 1 || exit 0
+       rm $(TMPDIR)/*.dwo
+       ls $(TMPDIR)/*.dwp && exit 1 || exit 0
+       rm $(TMPDIR)/$(call BIN,foo)
 
+# - Debuginfo in `.o` files
+# - `.o` and binary refer to remapped `.o` paths which do not exist
+# - `.o` present
+# - `.dwo` never created
+# - `.dwp` never created
 unpacked-remapped-single:
        $(RUSTC) $(UNSTABLEOPTS) -C split-debuginfo=unpacked -C debuginfo=2 \
                -Z split-dwarf-kind=single --remap-path-prefix $(TMPDIR)=/a foo.rs -g
        objdump -Wi $(TMPDIR)/foo | grep DW_AT_GNU_dwo_name | (! grep $(TMPDIR)) || exit 1
+       ls $(TMPDIR)/*.o
+       ls $(TMPDIR)/*.dwo && exit 1 || exit 0
+       ls $(TMPDIR)/*.dwp && exit 1 || exit 0
+       rm $(TMPDIR)/$(call BIN,foo)
+
+unpacked-crosscrate: packed-crosscrate-split packed-crosscrate-single
+
+# - Debuginfo in `.dwo` files
+# - (bar) `.rlib` file created, contains `.dwo`
+# - (bar) `.o` deleted
+# - (bar) `.dwo` present
+# - (bar) `.dwp` never created
+# - (main) `.o` deleted
+# - (main) `.dwo` present
+# - (main) `.dwp` never created
+unpacked-crosscrate-split:
+       $(RUSTC) --crate-type lib $(UNSTABLEOPTS) -C split-debuginfo=unpacked \
+               -Zsplit-dwarf-kind=split -C debuginfo=2 -g bar.rs
+       ls $(TMPDIR)/*.rlib
+       ls $(TMPDIR)/*.o && exit 1 || exit 0
+       ls $(TMPDIR)/*.dwo
+       ls $(TMPDIR)/*.dwp && exit 1 || exit 0
+       $(RUSTC) --extern bar=$(TMPDIR)/libbar.rlib $(UNSTABLEOPTS) \
+               -C split-debuginfo=unpacked -Zsplit-dwarf-kind=split -C debuginfo=2 -g main.rs
+       ls $(TMPDIR)/*.o && exit 1 || exit 0
+       rm $(TMPDIR)/*.dwo
+       ls $(TMPDIR)/*.dwp && exit 1 || exit 0
+       rm $(TMPDIR)/$(call BIN,main)
+
+# - Debuginfo in `.o` files
+# - (bar) `.rlib` file created, contains `.o`
+# - (bar) `.o` present
+# - (bar) `.dwo` never created
+# - (bar) `.dwp` never created
+# - (main) `.o` present
+# - (main) `.dwo` never created
+# - (main) `.dwp` never created
+unpacked-crosscrate-single:
+       $(RUSTC) --crate-type lib $(UNSTABLEOPTS) -C split-debuginfo=unpacked \
+               -Zsplit-dwarf-kind=single -C debuginfo=2 -g bar.rs
+       ls $(TMPDIR)/*.rlib
+       ls $(TMPDIR)/*.o
+       ls $(TMPDIR)/*.dwo && exit 1 || exit 0
+       ls $(TMPDIR)/*.dwp && exit 1 || exit 0
+       $(RUSTC) --extern bar=$(TMPDIR)/libbar.rlib $(UNSTABLEOPTS) \
+               -C split-debuginfo=unpacked -Zsplit-dwarf-kind=single -C debuginfo=2 -g main.rs
+       ls $(TMPDIR)/*.o
+       ls $(TMPDIR)/*.dwo && exit 1 || exit 0
+       ls $(TMPDIR)/*.dwp && exit 1 || exit 0
+       rm $(TMPDIR)/$(call BIN,main)
 endif
 endif
diff --git a/src/test/run-make-fulldeps/split-debuginfo/baz.rs b/src/test/run-make-fulldeps/split-debuginfo/baz.rs
new file mode 100644 (file)
index 0000000..8b1a393
--- /dev/null
@@ -0,0 +1 @@
+// empty
index 85782866d125a2e25bc21952e2f107225075dd75..5191e4676486a8fb5635572339d4b94c42b9ebdd 100644 (file)
@@ -1,2 +1,2 @@
-error: unknown print request `uwu`. Valid print requests are: `crate-name`, `file-names`, `sysroot`, `target-libdir`, `cfg`, `calling-conventions`, `target-list`, `target-cpus`, `target-features`, `relocation-models`, `code-models`, `tls-models`, `native-static-libs`, `stack-protector-strategies`, `target-spec-json`, `link-args`
+error: unknown print request `uwu`. Valid print requests are: `crate-name`, `file-names`, `sysroot`, `target-libdir`, `cfg`, `calling-conventions`, `target-list`, `target-cpus`, `target-features`, `relocation-models`, `code-models`, `tls-models`, `native-static-libs`, `stack-protector-strategies`, `target-spec-json`, `link-args`, `split-debuginfo`
 
index 837a2c1d57f5a53313c68b988bbdc3799ea93a69..94c1a6525aaa5e08bfbce9db7531c71cdcca5384 100644 (file)
@@ -1,4 +1,8 @@
 // This test ensures that items and documentation code blocks are wrapped in <pre><code>
+
+// We need to disable this check because `implementors/test_docs/trait.AnotherOne.js`
+// doesn't exist.
+fail-on-request-error: false
 goto: "file://" + |DOC_PATH| + "/test_docs/fn.foo.html"
 size: (1080, 600)
 // There should be four doc codeblocks.
index 911ee34be94e5aa034c9724b292fc168363b5c99..fec21ad35c3ebe098cbebcd4d24d7bf1e87d249f 100644 (file)
@@ -30,10 +30,10 @@ wait-for: "#settings"
 assert-css: ("#settings", {"display": "block"})
 
 // Then, click the toggle button.
-click: "input#line-numbers + .slider"
+click: "input#line-numbers"
 wait-for: 100 // wait-for-false does not exist
 assert-false: "pre.example-line-numbers"
 
 // Finally, turn it on again.
-click: "input#line-numbers + .slider"
+click: "input#line-numbers"
 wait-for: "pre.example-line-numbers"
index ce688287a743363dab3548a68e061ddfe9c0ba50..9a46f256056f9eda2efc74e17750911e70332065 100644 (file)
@@ -1,4 +1,9 @@
 // This test ensures that the color of the items in the type decl are working as expected.
+
+// We need to disable this check because `implementors/test_docs/trait.TraitWithoutGenerics.js`
+// doesn't exist.
+fail-on-request-error: false
+
 define-function: (
     "check-colors",
     (
index 2366a60f5c61d1458fa5af5a25a8ea6c2ef96e3b..17a955064d733f5583ded2f11dca520e581b5cc1 100644 (file)
@@ -1,4 +1,9 @@
 // This test checks that there are margins applied to methods with no docblocks.
+
+// We need to disable this check because `implementors/test_docs/trait.TraitWithNoDocblock.js`
+// doesn't exist.
+fail-on-request-error: false
+
 goto: "file://" + |DOC_PATH| + "/test_docs/trait.TraitWithNoDocblocks.html"
 // Check that the two methods are more than 24px apart.
 compare-elements-position-near-false: ("//*[@id='tymethod.first_fn']", "//*[@id='tymethod.second_fn']", {"y": 24})
index efe0cb15f08a08bbd0543f937a5f534e4081c7be..4c3943d8858307c729e5493042344d87c6be68f2 100644 (file)
@@ -22,25 +22,26 @@ assert-position: (
 )
 assert-position: (
     "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
-    {"x": 951},
+    {"x": 955},
 )
-// The tooltip should be beside the `i`
+// The tooltip should be below the `i`
+// Also, clicking the tooltip should bring its text into the DOM
+assert-count: ("//*[@class='notable popover']", 0)
 click: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"
+assert-count: ("//*[@class='notable popover']", 1)
 compare-elements-position-near: (
     "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
-    "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits-tooltiptext force-tooltip']",
-    {"y": 2}
+    "//*[@class='notable popover']",
+    {"y": 30}
 )
 compare-elements-position-false: (
     "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
-    "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits-tooltiptext force-tooltip']",
+    "//*[@class='notable popover']",
     ("x")
 )
-// The docblock should be flush with the border.
-assert-css: (
-    "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits-tooltiptext force-tooltip']/*[@class='docblock']",
-    {"margin-left": "0px"}
-)
+click: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"
+move-cursor-to: "//h1"
+assert-count: ("//*[@class='notable popover']", 0)
 
 // Now only the `i` should be on the next line.
 size: (1055, 600)
@@ -71,7 +72,7 @@ assert-position: (
 )
 assert-position: (
     "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
-    {"x": 519},
+    {"x": 523},
 )
 
 // Checking on mobile now.
@@ -95,34 +96,126 @@ assert-position: (
 )
 assert-position: (
     "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
-    {"x": 289},
+    {"x": 293},
 )
-// The tooltip should be below `i`
-compare-elements-position-near-false: (
+// The tooltip should STILL be below `i`
+click: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"
+assert-count: ("//*[@class='notable popover']", 1)
+compare-elements-position-near: (
     "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
-    "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits-tooltiptext force-tooltip']",
-    {"y": 2}
+    "//*[@class='notable popover']",
+    {"y": 30}
 )
 compare-elements-position-false: (
     "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
-    "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits-tooltiptext force-tooltip']",
+    "//*[@class='notable popover']",
     ("x")
 )
-compare-elements-position-near: (
-    "//*[@id='method.create_an_iterator_from_read']/parent::*",
-    "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits-tooltiptext force-tooltip']",
-    {"x": 5}
+assert-position: (
+    "//*[@class='notable popover']",
+    {"x": 0}
 )
-// The docblock should be flush with the border.
-assert-css: (
-    "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits-tooltiptext force-tooltip']/*[@class='docblock']",
-    {"margin-left": "0px"}
+click: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"
+move-cursor-to: "//h1"
+assert-count: ("//*[@class='notable popover']", 0)
+
+// Now check the colors.
+define-function: (
+    "check-colors",
+    (theme, header_color, content_color, type_color, trait_color),
+    [
+        ("goto", "file://" + |DOC_PATH| + "/test_docs/struct.NotableStructWithLongName.html"),
+        // This is needed to ensure that the text color is computed.
+        ("show-text", true),
+
+        // Setting the theme.
+        ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
+        // We reload the page so the local storage settings are being used.
+        ("reload"),
+
+        ("move-cursor-to", "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"),
+        ("assert-count", (".notable.popover", 1)),
+
+        ("assert-css", (
+             ".notable.popover h3",
+             {"color": |header_color|},
+             ALL,
+        )),
+        ("assert-css", (
+             ".notable.popover pre",
+             {"color": |content_color|},
+             ALL,
+        )),
+        ("assert-css", (
+             ".notable.popover pre a.struct",
+             {"color": |type_color|},
+             ALL,
+        )),
+        ("assert-css", (
+             ".notable.popover pre a.trait",
+             {"color": |trait_color|},
+             ALL,
+        )),
+    ]
 )
 
-// Checking on very small mobile. The `i` should be on its own line.
-size: (365, 600)
-compare-elements-position-false: (
-    "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
-    "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
-    ("y", "x"),
+call-function: (
+    "check-colors",
+    {
+        "theme": "ayu",
+        "content_color": "rgb(230, 225, 207)",
+        "header_color": "rgb(255, 255, 255)",
+        "type_color": "rgb(255, 160, 165)",
+        "trait_color": "rgb(57, 175, 215)",
+    },
+)
+
+call-function: (
+    "check-colors",
+    {
+        "theme": "dark",
+        "content_color": "rgb(221, 221, 221)",
+        "header_color": "rgb(221, 221, 221)",
+        "type_color": "rgb(45, 191, 184)",
+        "trait_color": "rgb(183, 140, 242)",
+    },
 )
+
+call-function: (
+    "check-colors",
+    {
+        "theme": "light",
+        "content_color": "rgb(0, 0, 0)",
+        "header_color": "rgb(0, 0, 0)",
+        "type_color": "rgb(173, 55, 138)",
+        "trait_color": "rgb(110, 79, 201)",
+    },
+)
+
+reload:
+
+// Check that pressing escape works
+click: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"
+move-cursor-to: "//*[@class='notable popover']"
+assert-count: ("//*[@class='notable popover']", 1)
+press-key: "Escape"
+assert-count: ("//*[@class='notable popover']", 0)
+
+// Check that clicking outside works.
+click: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"
+assert-count: ("//*[@class='notable popover']", 1)
+click: ".search-input"
+assert-count: ("//*[@class='notable popover']", 0)
+
+// Check that pressing tab over and over works.
+click: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"
+move-cursor-to: "//*[@class='notable popover']"
+assert-count: ("//*[@class='notable popover']", 1)
+press-key: "Tab"
+press-key: "Tab"
+press-key: "Tab"
+press-key: "Tab"
+press-key: "Tab"
+press-key: "Tab"
+press-key: "Tab"
+assert-count: ("//*[@class='notable popover']", 0)
diff --git a/src/test/rustdoc-gui/search-no-result.goml b/src/test/rustdoc-gui/search-no-result.goml
new file mode 100644 (file)
index 0000000..b88be32
--- /dev/null
@@ -0,0 +1,36 @@
+// The goal of this test is to check the color of the "no result" links.
+goto: "file://" + |DOC_PATH| + "/lib2/index.html?search=sdkfskjfsdks"
+show-text: true
+
+define-function: (
+    "check-no-result",
+    (theme, link, link_hover),
+    [
+        // Changing theme.
+        ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
+        ("reload"),
+        ("wait-for", "#results"),
+        ("assert", ".search-failed.active"),
+        ("assert-css", ("#results a", {"color": |link|}, ALL)),
+        ("move-cursor-to", "#results a"),
+        ("assert-css", ("#results a:hover", {"color": |link_hover|})),
+        // Moving the cursor to some other place to not create issues with next function run.
+        ("move-cursor-to", ".search-input"),
+    ]
+)
+
+call-function: ("check-no-result", {
+    "theme": "ayu",
+    "link": "rgb(57, 175, 215)",
+    "link_hover": "rgb(57, 175, 215)",
+})
+call-function: ("check-no-result", {
+    "theme": "dark",
+    "link": "rgb(210, 153, 29)",
+    "link_hover": "rgb(210, 153, 29)",
+})
+call-function: ("check-no-result", {
+    "theme": "light",
+    "link": "rgb(56, 115, 173)",
+    "link_hover": "rgb(56, 115, 173)",
+})
index b8abd9f906242864018b5bc6216272276b77c9a6..fa349c872ae205b183f0329dab696620d9720d38 100644 (file)
@@ -35,3 +35,43 @@ assert-css: ("#crate-search", {"width": "527px"})
 assert-css: (".search-results-title", {"height": "44px", "width": "640px"})
 // And we check that the `<select>` isn't bigger than its container (".search-results-title").
 assert-css: ("#search", {"width": "640px"})
+
+// Now checking that the crate filter is working as expected too.
+show-text: true
+define-function: (
+    "check-filter",
+    (theme, border, filter, hover_border, hover_filter),
+    [
+        ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
+        ("reload"),
+        ("wait-for", "#crate-search"),
+        ("assert-css", ("#crate-search", {"border": "1px solid " + |border|})),
+        ("assert-css", ("#crate-search-div::after", {"filter": |filter|})),
+        ("move-cursor-to", "#crate-search"),
+        ("assert-css", ("#crate-search", {"border": "1px solid " + |hover_border|})),
+        ("assert-css", ("#crate-search-div::after", {"filter": |hover_filter|})),
+        ("move-cursor-to", ".search-input"),
+    ],
+)
+
+call-function: ("check-filter", {
+    "theme": "ayu",
+    "border": "rgb(92, 103, 115)",
+    "filter": "invert(0.41) sepia(0.12) saturate(4.87) hue-rotate(171deg) brightness(0.94) contrast(0.94)",
+    "hover_border": "rgb(224, 224, 224)",
+    "hover_filter": "invert(0.98) sepia(0.12) saturate(0.81) hue-rotate(343deg) brightness(1.13) contrast(0.76)",
+})
+call-function: ("check-filter", {
+    "theme": "dark",
+    "border": "rgb(224, 224, 224)",
+    "filter": "invert(0.94) sepia(0) saturate(7.21) hue-rotate(255deg) brightness(0.9) contrast(0.9)",
+    "hover_border": "rgb(33, 150, 243)",
+    "hover_filter": "invert(0.69) sepia(0.6) saturate(66.13) hue-rotate(184deg) brightness(1) contrast(0.91)",
+})
+call-function: ("check-filter", {
+    "theme": "light",
+    "border": "rgb(224, 224, 224)",
+    "filter": "invert(1) sepia(0) saturate(42.23) hue-rotate(289deg) brightness(1.14) contrast(0.76)",
+    "hover_border": "rgb(113, 113, 113)",
+    "hover_filter": "invert(0.44) sepia(0.18) saturate(0.23) hue-rotate(317deg) brightness(0.96) contrast(0.93)",
+})
index f258f4d2a838e12fd7588256f3d662c04f46fdf7..7e7971d47fbcaf7d200d92c682ee738f2a6d3c79 100644 (file)
@@ -48,7 +48,8 @@ assert: ".setting-line.hidden #preferred-light-theme"
 assert-property: ("#theme .choices #theme-dark", {"checked": "true"})
 
 // Some style checks...
-// First we check the "default" display.
+move-cursor-to: "#settings-menu > a"
+// First we check the "default" display for radio buttons.
 assert-css: (
     "#theme-dark",
     {
@@ -57,7 +58,7 @@ assert-css: (
     },
 )
 assert-css: ("#theme-light", {"border-color": "rgb(221, 221, 221)", "box-shadow": "none"})
-// Let's start with the hover.
+// Let's start with the hover for radio buttons.
 move-cursor-to: "#theme-dark"
 assert-css: (
     "#theme-dark",
@@ -69,7 +70,7 @@ assert-css: (
 move-cursor-to: "#theme-light"
 assert-css: ("#theme-light", {"border-color": "rgb(33, 150, 243)", "box-shadow": "none"})
 move-cursor-to: "#theme-ayu"
-// Let's now check with the focus.
+// Let's now check with the focus for radio buttons.
 focus: "#theme-dark"
 assert-css: (
     "#theme-dark",
@@ -86,7 +87,7 @@ assert-css: (
         "box-shadow": "rgb(33, 150, 243) 0px 0px 1px 1px",
     },
 )
-// Now we check we both focus and hover.
+// Now we check we both focus and hover for radio buttons.
 move-cursor-to: "#theme-dark"
 focus: "#theme-dark"
 assert-css: (
@@ -106,6 +107,80 @@ assert-css: (
     },
 )
 
+// First we check the "default" display for toggles.
+assert-css: (
+    "#auto-hide-large-items",
+    {
+        "background-color": "rgb(33, 150, 243)",
+        "border-color": "rgb(221, 221, 221)",
+    },
+)
+assert-css: (
+    "#use-system-theme",
+    {
+        "background-color": "rgba(0, 0, 0, 0)",
+        "border-color": "rgb(221, 221, 221)",
+    }
+)
+// Let's start with the hover for toggles.
+move-cursor-to: "#auto-hide-large-items"
+assert-css: (
+    "#auto-hide-large-items",
+    {
+        "background-color": "rgb(33, 150, 243)",
+        "border-color": "rgb(33, 150, 243)",
+    },
+)
+move-cursor-to: "#use-system-theme"
+assert-css: (
+    "#use-system-theme",
+    {
+        "background-color": "rgba(0, 0, 0, 0)",
+        "border-color": "rgb(33, 150, 243)",
+    }
+)
+move-cursor-to: "#settings-menu > a"
+// Let's now check with the focus for toggles.
+focus: "#auto-hide-large-items"
+assert-css: (
+    "#auto-hide-large-items",
+    {
+        "background-color": "rgb(33, 150, 243)",
+        "border-color": "rgb(221, 221, 221)",
+        "box-shadow": "rgb(33, 150, 243) 0px 0px 1px 1px",
+    },
+)
+focus: "#use-system-theme"
+assert-css: (
+    "#use-system-theme",
+    {
+        "background-color": "rgba(0, 0, 0, 0)",
+        "border-color": "rgb(221, 221, 221)",
+        "box-shadow": "rgb(33, 150, 243) 0px 0px 1px 1px",
+    },
+)
+// Now we check we both focus and hover for toggles.
+move-cursor-to: "#auto-hide-large-items"
+focus: "#auto-hide-large-items"
+assert-css: (
+    "#auto-hide-large-items",
+    {
+        "background-color": "rgb(33, 150, 243)",
+        "border-color": "rgb(33, 150, 243)",
+        "box-shadow": "rgb(33, 150, 243) 0px 0px 1px 1px",
+    },
+)
+move-cursor-to: "#use-system-theme"
+focus: "#use-system-theme"
+assert-css: (
+    "#use-system-theme",
+    {
+        "background-color": "rgba(0, 0, 0, 0)",
+        "border-color": "rgb(33, 150, 243)",
+        "box-shadow": "rgb(33, 150, 243) 0px 0px 1px 1px",
+    },
+)
+
 // We now switch the display.
 click: "#use-system-theme"
 // Wait for the hidden element to show up.
@@ -118,7 +193,7 @@ assert: ".setting-line.hidden #theme"
 assert-text: ("#preferred-dark-theme .setting-name", "Preferred dark theme")
 assert-text: ("#preferred-light-theme .setting-name", "Preferred light theme")
 
-// We now check that clicking on the "sliders"' text is like clicking on the slider.
+// We now check that clicking on the toggles' text is like clicking on the checkbox.
 // To test it, we use the "Disable keyboard shortcuts".
 local-storage: {"rustdoc-disable-shortcuts": "false"}
 click: ".setting-line:last-child .toggle .label"
@@ -141,10 +216,7 @@ assert-css: ("#settings-menu .popover", {"display": "none"})
 // Now we go to the settings page to check that the CSS is loaded as expected.
 goto: "file://" + |DOC_PATH| + "/settings.html"
 wait-for: "#settings"
-assert-css: (
-    ".setting-line .toggle .slider",
-    {"width": "45px", "margin-right": "20px", "border": "0px none rgb(0, 0, 0)"},
-)
+assert-css: (".setting-line", {"position": "relative"})
 
 assert-attribute-false: ("#settings", {"class": "popover"}, CONTAINS)
 compare-elements-position: (".sub form", "#settings", ("x"))
@@ -162,4 +234,4 @@ reload:
 size: (300, 1000)
 click: "#settings-menu"
 wait-for: "#settings"
-assert-css: ("#settings .slider", {"width": "45px"}, ALL)
+assert-css: (".setting-line", {"position": "relative"})
index 3c4db978d5fb2f309debde24152448fdfdea883d..b3b837ad377c80bb74e8b2a7e81a181e8bb44fa0 100644 (file)
@@ -2,17 +2,22 @@
 goto: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html"
 show-text: true
 // Check that we can click on the line number.
-click: ".src-line-numbers > span:nth-child(4)" // This is the span for line 4.
+click: ".src-line-numbers > a:nth-child(4)" // This is the anchor for line 4.
 // Ensure that the page URL was updated.
 assert-document-property: ({"URL": "lib.rs.html#4"}, ENDS_WITH)
 assert-attribute: ("//*[@id='4']", {"class": "line-highlighted"})
-// We now check that the good spans are highlighted
+// Ensure that the default style, with the right border, isn't used.
+assert-css: ("//*[@id='4']", {"border-right-width": "0px"})
+reload:
+assert-attribute: ("//*[@id='4']", {"class": "line-highlighted"})
+assert-css: ("//*[@id='4']", {"border-right-width": "0px"})
+// We now check that the good anchors are highlighted
 goto: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html#4-6"
-assert-attribute-false: (".src-line-numbers > span:nth-child(3)", {"class": "line-highlighted"})
-assert-attribute: (".src-line-numbers > span:nth-child(4)", {"class": "line-highlighted"})
-assert-attribute: (".src-line-numbers > span:nth-child(5)", {"class": "line-highlighted"})
-assert-attribute: (".src-line-numbers > span:nth-child(6)", {"class": "line-highlighted"})
-assert-attribute-false: (".src-line-numbers > span:nth-child(7)", {"class": "line-highlighted"})
+assert-attribute-false: (".src-line-numbers > a:nth-child(3)", {"class": "line-highlighted"})
+assert-attribute: (".src-line-numbers > a:nth-child(4)", {"class": "line-highlighted"})
+assert-attribute: (".src-line-numbers > a:nth-child(5)", {"class": "line-highlighted"})
+assert-attribute: (".src-line-numbers > a:nth-child(6)", {"class": "line-highlighted"})
+assert-attribute-false: (".src-line-numbers > a:nth-child(7)", {"class": "line-highlighted"})
 
 define-function: (
     "check-colors",
@@ -21,12 +26,12 @@ define-function: (
         ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
         ("reload"),
         ("assert-css", (
-            ".src-line-numbers > span:not(.line-highlighted)",
+            ".src-line-numbers > a:not(.line-highlighted)",
             {"color": |color|, "background-color": |background_color|},
             ALL,
         )),
         ("assert-css", (
-            ".src-line-numbers > span.line-highlighted",
+            ".src-line-numbers > a.line-highlighted",
             {"color": |highlight_color|, "background-color": |highlight_background_color|},
             ALL,
         )),
@@ -57,6 +62,25 @@ call-function: ("check-colors", {
 
 // This is to ensure that the content is correctly align with the line numbers.
 compare-elements-position: ("//*[@id='1']", ".rust > code > span", ("y"))
+// Check the `href` property so that users can treat anchors as links.
+assert-property: (".src-line-numbers > a:nth-child(1)", {
+    "href": "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html#1"
+})
+assert-property: (".src-line-numbers > a:nth-child(2)", {
+    "href": "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html#2"
+})
+assert-property: (".src-line-numbers > a:nth-child(3)", {
+    "href": "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html#3"
+})
+assert-property: (".src-line-numbers > a:nth-child(4)", {
+    "href": "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html#4"
+})
+assert-property: (".src-line-numbers > a:nth-child(5)", {
+    "href": "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html#5"
+})
+assert-property: (".src-line-numbers > a:nth-child(6)", {
+    "href": "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html#6"
+})
 
 // Assert that the line numbers text is aligned to the right.
 assert-css: (".src-line-numbers", {"text-align": "right"})
@@ -66,7 +90,7 @@ assert-css: (".src-line-numbers", {"text-align": "right"})
 goto: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html"
 // We use this assert-position to know where we will click.
 assert-position: ("//*[@id='1']", {"x": 104, "y": 112})
-// We click on the left of the "1" span but still in the "src-line-number" `<pre>`.
+// We click on the left of the "1" anchor but still in the "src-line-number" `<pre>`.
 click: (103, 103)
 assert-document-property: ({"URL": "/lib.rs.html"}, ENDS_WITH)
 
index b17dfd94cf0e9f27e19994fb6384100351950e40..9233f37444b6ed9bd2846854b4b64afcc39e32bf 100644 (file)
@@ -9,3 +9,8 @@ assert-css: (".impl.has-srclink .code-header", {"font-size": "18px", "font-weigh
 // Check the impl items.
 assert-css: (".impl-items .has-srclink .srclink", {"font-size": "16px", "font-weight": 400}, ALL)
 assert-css: (".impl-items .has-srclink .code-header", {"font-size": "16px", "font-weight": 600}, ALL)
+
+// Check that we can click on source link
+store-document-property: (url, "URL")
+click: ".impl-items .has-srclink .srclink"
+assert-document-property-false: {"URL": |url|}
diff --git a/src/test/rustdoc-gui/target.goml b/src/test/rustdoc-gui/target.goml
new file mode 100644 (file)
index 0000000..3e5c30d
--- /dev/null
@@ -0,0 +1,35 @@
+// Check that the targetted element has the expected styles.
+goto: "file://" + |DOC_PATH| + "/lib2/struct.Foo.html#method.a_method"
+show-text: true
+
+// Confirming that the method is the target.
+assert: "#method\.a_method:target"
+
+define-function: (
+    "check-style",
+    (theme, background, border),
+    [
+        ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
+        ("reload"),
+        ("assert-css", ("#method\.a_method:target", {
+            "background-color": |background|,
+            "border-right": "3px solid " + |border|,
+        })),
+    ],
+)
+
+call-function: ("check-style", {
+    "theme": "ayu",
+    "background": "rgba(255, 236, 164, 0.06)",
+    "border": "rgba(255, 180, 76, 0.85)",
+})
+call-function: ("check-style", {
+    "theme": "dark",
+    "background": "rgb(73, 74, 61)",
+    "border": "rgb(187, 116, 16)",
+})
+call-function: ("check-style", {
+    "theme": "light",
+    "background": "rgb(253, 255, 211)",
+    "border": "rgb(173, 124, 55)",
+})
index a799444a1087e97a6511d611fa29f1c5171c99d5..e5d023544d682824b41dfbb88267264507dc2d76 100644 (file)
@@ -1,4 +1,9 @@
 // Checks that the elements in the sidebar are alphabetically sorted.
+
+// We need to disable this check because `implementors/test_docs/trait.AnotherOne.js`
+// doesn't exist.
+fail-on-request-error: false
+
 goto: "file://" + |DOC_PATH| + "/test_docs/trait.AnotherOne.html"
 assert-text: (".sidebar-elems section .block li:nth-of-type(1) > a", "another")
 assert-text: (".sidebar-elems section .block li:nth-of-type(2) > a", "func1")
index fce3002e7508f89d1f4fe0f5b7f9377d9498c67a..dcffe956c21975132859f6239e806eee969af005 100644 (file)
@@ -1,4 +1,10 @@
 // This test ensures that the items declaration content overflow is handled inside the <pre> directly.
+
+// We need to disable this check because
+// `implementors/test_docs/trait.ALongNameBecauseItHelpsTestingTheCurrentProblem.js`
+// doesn't exist.
+fail-on-request-error: false
+
 goto: "file://" + |DOC_PATH| + "/lib2/long_trait/trait.ALongNameBecauseItHelpsTestingTheCurrentProblem.html"
 // We set a fixed size so there is no chance of "random" resize.
 size: (1100, 800)
diff --git a/src/test/rustdoc-ui/issue-103997.rs b/src/test/rustdoc-ui/issue-103997.rs
new file mode 100644 (file)
index 0000000..36f42fb
--- /dev/null
@@ -0,0 +1,6 @@
+// check-pass
+
+pub fn foo() {}
+
+/// [`foo`](Self::foo) //~ WARNING unresolved link to `Self::foo`
+pub use foo as bar;
diff --git a/src/test/rustdoc-ui/issue-103997.stderr b/src/test/rustdoc-ui/issue-103997.stderr
new file mode 100644 (file)
index 0000000..c06db91
--- /dev/null
@@ -0,0 +1,10 @@
+warning: unresolved link to `Self::foo`
+  --> $DIR/issue-103997.rs:5:13
+   |
+LL | /// [`foo`](Self::foo)
+   |             ^^^^^^^^^ no item named `Self` in scope
+   |
+   = note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default
+
+warning: 1 warning emitted
+
index d00a3e3551991d63aa14b22f3817ea87a2451851..5959f9c7c5992338ce20676b568415b2ea1eb890 100644 (file)
 
 // @has 'src/foo/check-source-code-urls-to-def.rs.html'
 
-// @has - '//a[@href="auxiliary/source-code-bar.rs.html#1-17"]' 'bar'
+// @has - '//pre[@class="rust"]//a[@href="auxiliary/source-code-bar.rs.html#1-17"]' 'bar'
 #[path = "auxiliary/source-code-bar.rs"]
 pub mod bar;
 
-// @count - '//a[@href="auxiliary/source-code-bar.rs.html#5"]' 4
+// @count - '//pre[@class="rust"]//a[@href="auxiliary/source-code-bar.rs.html#5"]' 4
 use bar::Bar;
-// @has - '//a[@href="auxiliary/source-code-bar.rs.html#13"]' 'self'
-// @has - '//a[@href="auxiliary/source-code-bar.rs.html#14"]' 'Trait'
+// @has - '//pre[@class="rust"]//a[@href="auxiliary/source-code-bar.rs.html#13"]' 'self'
+// @has - '//pre[@class="rust"]//a[@href="auxiliary/source-code-bar.rs.html#14"]' 'Trait'
 use bar::sub::{self, Trait};
 
 pub struct Foo;
@@ -28,29 +28,29 @@ fn hello(&self) {}
 
 fn babar() {}
 
-// @has - '//a/@href' '/struct.String.html'
-// @has - '//a/@href' '/primitive.u32.html'
-// @has - '//a/@href' '/primitive.str.html'
-// @count - '//a[@href="#23"]' 5
-// @has - '//a[@href="../../source_code/struct.SourceCode.html"]' 'source_code::SourceCode'
+// @has - '//pre[@class="rust"]//a/@href' '/struct.String.html'
+// @has - '//pre[@class="rust"]//a/@href' '/primitive.u32.html'
+// @has - '//pre[@class="rust"]//a/@href' '/primitive.str.html'
+// @count - '//pre[@class="rust"]//a[@href="#23"]' 5
+// @has - '//pre[@class="rust"]//a[@href="../../source_code/struct.SourceCode.html"]' 'source_code::SourceCode'
 pub fn foo(a: u32, b: &str, c: String, d: Foo, e: bar::Bar, f: source_code::SourceCode) {
     let x = 12;
     let y: Foo = Foo;
     let z: Bar = bar::Bar { field: Foo };
     babar();
-    // @has - '//a[@href="#26"]' 'hello'
+    // @has - '//pre[@class="rust"]//a[@href="#26"]' 'hello'
     y.hello();
 }
 
-// @has - '//a[@href="auxiliary/source-code-bar.rs.html#14"]' 'bar::sub::Trait'
-// @has - '//a[@href="auxiliary/source-code-bar.rs.html#14"]' 'Trait'
+// @has - '//pre[@class="rust"]//a[@href="auxiliary/source-code-bar.rs.html#14"]' 'bar::sub::Trait'
+// @has - '//pre[@class="rust"]//a[@href="auxiliary/source-code-bar.rs.html#14"]' 'Trait'
 pub fn foo2<T: bar::sub::Trait, V: Trait>(t: &T, v: &V, b: bool) {}
 
 pub trait AnotherTrait {}
 pub trait WhyNot {}
 
-// @has - '//a[@href="#49"]' 'AnotherTrait'
-// @has - '//a[@href="#50"]' 'WhyNot'
+// @has - '//pre[@class="rust"]//a[@href="#49"]' 'AnotherTrait'
+// @has - '//pre[@class="rust"]//a[@href="#50"]' 'WhyNot'
 pub fn foo3<T, V>(t: &T, v: &V)
 where
     T: AnotherTrait,
@@ -59,11 +59,11 @@ pub fn foo3<T, V>(t: &T, v: &V)
 
 pub trait AnotherTrait2 {}
 
-// @has - '//a[@href="#60"]' 'AnotherTrait2'
+// @has - '//pre[@class="rust"]//a[@href="#60"]' 'AnotherTrait2'
 pub fn foo4() {
     let x: Vec<AnotherTrait2> = Vec::new();
 }
 
-// @has - '//a[@href="../../foo/primitive.bool.html"]' 'bool'
+// @has - '//pre[@class="rust"]//a[@href="../../foo/primitive.bool.html"]' 'bool'
 #[doc(primitive = "bool")]
 mod whatever {}
diff --git a/src/test/rustdoc/doc-notable_trait-slice.bare_fn_matches.html b/src/test/rustdoc/doc-notable_trait-slice.bare_fn_matches.html
new file mode 100644 (file)
index 0000000..f2ec832
--- /dev/null
@@ -0,0 +1 @@
+<script type="text/json" id="notable-traits-data">{"&amp;'static [SomeStruct]":"&lt;h3&gt;Notable traits for &lt;code&gt;&amp;amp;[&lt;a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait_slice::SomeStruct\"&gt;SomeStruct&lt;/a&gt;]&lt;/code&gt;&lt;/h3&gt;&lt;pre class=\"content\"&gt;&lt;code&gt;&lt;span class=\"where fmt-newline\"&gt;impl &lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait_slice::SomeTrait\"&gt;SomeTrait&lt;/a&gt; for &amp;amp;[&lt;a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait_slice::SomeStruct\"&gt;SomeStruct&lt;/a&gt;]&lt;/span&gt;"}</script>
\ No newline at end of file
index b0d414027216ac7ca1ad7558479c463272151ea2..2411da8cd45493d0aa0813f26076351186ed8bf2 100644 (file)
@@ -8,13 +8,13 @@ pub trait SomeTrait {}
 impl SomeTrait for &[SomeStruct] {}
 
 // @has doc_notable_trait_slice/fn.bare_fn_matches.html
-// @has - '//code[@class="content"]' 'impl SomeTrait for &[SomeStruct]'
+// @snapshot bare_fn_matches - '//script[@id="notable-traits-data"]'
 pub fn bare_fn_matches() -> &'static [SomeStruct] {
     &[]
 }
 
 // @has doc_notable_trait_slice/fn.bare_fn_no_matches.html
-// @!has - '//code[@class="content"]' 'impl SomeTrait for &[SomeStruct]'
+// @count - '//script[@id="notable-traits-data"]' 0
 pub fn bare_fn_no_matches() -> &'static [OtherStruct] {
     &[]
 }
diff --git a/src/test/rustdoc/doc-notable_trait.bare-fn.html b/src/test/rustdoc/doc-notable_trait.bare-fn.html
new file mode 100644 (file)
index 0000000..b426a4d
--- /dev/null
@@ -0,0 +1 @@
+<script type="text/json" id="notable-traits-data">{"SomeStruct":"&lt;h3&gt;Notable traits for &lt;code&gt;&lt;a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait::SomeStruct\"&gt;SomeStruct&lt;/a&gt;&lt;/code&gt;&lt;/h3&gt;&lt;pre class=\"content\"&gt;&lt;code&gt;&lt;span class=\"where fmt-newline\"&gt;impl &lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\"&gt;SomeTrait&lt;/a&gt; for &lt;a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait::SomeStruct\"&gt;SomeStruct&lt;/a&gt;&lt;/span&gt;"}</script>
\ No newline at end of file
index 58a24b855d6e2f528c1da360719a0687c978e2fb..279faf5540140ee760add8ca75f6c0a16b15ae21 100644 (file)
@@ -9,7 +9,8 @@ impl<T: SomeTrait> SomeTrait for Wrapper<T> {}
 #[doc(notable_trait)]
 pub trait SomeTrait {
     // @has doc_notable_trait/trait.SomeTrait.html
-    // @has - '//code[@class="content"]' 'impl<T: SomeTrait> SomeTrait for Wrapper<T>'
+    // @has - '//a[@class="notable-traits"]/@data-ty' 'Wrapper<Self>'
+    // @snapshot wrap-me - '//script[@id="notable-traits-data"]'
     fn wrap_me(self) -> Wrapper<Self> where Self: Sized {
         Wrapper {
             inner: self,
@@ -22,15 +23,16 @@ impl SomeTrait for SomeStruct {}
 
 impl SomeStruct {
     // @has doc_notable_trait/struct.SomeStruct.html
-    // @has - '//code[@class="content"]' 'impl SomeTrait for SomeStruct'
-    // @has - '//code[@class="content"]' 'impl<T: SomeTrait> SomeTrait for Wrapper<T>'
+    // @has - '//a[@class="notable-traits"]/@data-ty' 'SomeStruct'
+    // @snapshot some-struct-new - '//script[@id="notable-traits-data"]'
     pub fn new() -> SomeStruct {
         SomeStruct
     }
 }
 
 // @has doc_notable_trait/fn.bare_fn.html
-// @has - '//code[@class="content"]' 'impl SomeTrait for SomeStruct'
+// @has - '//a[@class="notable-traits"]/@data-ty' 'SomeStruct'
+// @snapshot bare-fn - '//script[@id="notable-traits-data"]'
 pub fn bare_fn() -> SomeStruct {
     SomeStruct
 }
diff --git a/src/test/rustdoc/doc-notable_trait.some-struct-new.html b/src/test/rustdoc/doc-notable_trait.some-struct-new.html
new file mode 100644 (file)
index 0000000..4f80638
--- /dev/null
@@ -0,0 +1 @@
+<script type="text/json" id="notable-traits-data">{"SomeStruct":"&lt;h3&gt;Notable traits for &lt;code&gt;&lt;a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait::SomeStruct\"&gt;SomeStruct&lt;/a&gt;&lt;/code&gt;&lt;/h3&gt;&lt;pre class=\"content\"&gt;&lt;code&gt;&lt;span class=\"where fmt-newline\"&gt;impl &lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\"&gt;SomeTrait&lt;/a&gt; for &lt;a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait::SomeStruct\"&gt;SomeStruct&lt;/a&gt;&lt;/span&gt;","Wrapper&lt;Self&gt;":"&lt;h3&gt;Notable traits for &lt;code&gt;&lt;a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct doc_notable_trait::Wrapper\"&gt;Wrapper&lt;/a&gt;&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/h3&gt;&lt;pre class=\"content\"&gt;&lt;code&gt;&lt;span class=\"where fmt-newline\"&gt;impl&amp;lt;T:&amp;nbsp;&lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\"&gt;SomeTrait&lt;/a&gt;&amp;gt; &lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\"&gt;SomeTrait&lt;/a&gt; for &lt;a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct doc_notable_trait::Wrapper\"&gt;Wrapper&lt;/a&gt;&amp;lt;T&amp;gt;&lt;/span&gt;"}</script>
\ No newline at end of file
diff --git a/src/test/rustdoc/doc-notable_trait.wrap-me.html b/src/test/rustdoc/doc-notable_trait.wrap-me.html
new file mode 100644 (file)
index 0000000..bed2a38
--- /dev/null
@@ -0,0 +1 @@
+<script type="text/json" id="notable-traits-data">{"Wrapper&lt;Self&gt;":"&lt;h3&gt;Notable traits for &lt;code&gt;&lt;a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct doc_notable_trait::Wrapper\"&gt;Wrapper&lt;/a&gt;&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/h3&gt;&lt;pre class=\"content\"&gt;&lt;code&gt;&lt;span class=\"where fmt-newline\"&gt;impl&amp;lt;T:&amp;nbsp;&lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\"&gt;SomeTrait&lt;/a&gt;&amp;gt; &lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\"&gt;SomeTrait&lt;/a&gt; for &lt;a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct doc_notable_trait::Wrapper\"&gt;Wrapper&lt;/a&gt;&amp;lt;T&amp;gt;&lt;/span&gt;"}</script>
\ No newline at end of file
diff --git a/src/test/rustdoc/multiple-import-levels.rs b/src/test/rustdoc/multiple-import-levels.rs
new file mode 100644 (file)
index 0000000..1daae49
--- /dev/null
@@ -0,0 +1,34 @@
+// The goal of this test is to ensure that the attributes of all imports are taken into
+// account.
+
+#![crate_name = "foo"]
+
+mod a {
+    /// 1
+    pub struct Type;
+}
+
+mod b {
+    /// 2
+    pub use crate::a::Type;
+}
+
+mod c {
+    /// 3
+    pub use crate::b::Type;
+    /// 4
+    pub use crate::b::Type as Woof;
+}
+
+// @has 'foo/struct.Type.html'
+// @has - '//*[@class="rustdoc-toggle top-doc"]/*[@class="docblock"]' 'foo 2 1'
+/// foo
+pub use b::Type;
+// @has 'foo/struct.Whatever.html'
+// @has - '//*[@class="rustdoc-toggle top-doc"]/*[@class="docblock"]' 'whatever 3 2 1'
+/// whatever
+pub use c::Type as Whatever;
+// @has 'foo/struct.Woof.html'
+// @has - '//*[@class="rustdoc-toggle top-doc"]/*[@class="docblock"]' 'a dog 4 2 1'
+/// a dog
+pub use c::Woof;
diff --git a/src/test/rustdoc/spotlight-from-dependency.odd.html b/src/test/rustdoc/spotlight-from-dependency.odd.html
new file mode 100644 (file)
index 0000000..1d02c13
--- /dev/null
@@ -0,0 +1 @@
+<script type="text/json" id="notable-traits-data">{"Odd":"&lt;h3&gt;Notable traits for &lt;code&gt;&lt;a class=\"struct\" href=\"struct.Odd.html\" title=\"struct foo::Odd\"&gt;Odd&lt;/a&gt;&lt;/code&gt;&lt;/h3&gt;&lt;pre class=\"content\"&gt;&lt;code&gt;&lt;span class=\"where fmt-newline\"&gt;impl &lt;a class=\"trait\" href=\"{{channel}}/core/iter/traits/iterator/trait.Iterator.html\" title=\"trait core::iter::traits::iterator::Iterator\"&gt;Iterator&lt;/a&gt; for &lt;a class=\"struct\" href=\"struct.Odd.html\" title=\"struct foo::Odd\"&gt;Odd&lt;/a&gt;&lt;/span&gt;&lt;span class=\"where fmt-newline\"&gt;    type &lt;a href=\"{{channel}}/core/iter/traits/iterator/trait.Iterator.html#associatedtype.Item\" class=\"associatedtype\"&gt;Item&lt;/a&gt; = &lt;a class=\"primitive\" href=\"{{channel}}/std/primitive.usize.html\"&gt;usize&lt;/a&gt;;&lt;/span&gt;"}</script>
\ No newline at end of file
index 5245789212d8c9e777f6984e7e999eea18415c81..090ad187d9cc0a103fe7d0349b8d20dba7c8cd53 100644 (file)
@@ -3,7 +3,8 @@
 use std::iter::Iterator;
 
 // @has foo/struct.Odd.html
-// @has - '//*[@id="method.new"]//span[@class="notable-traits"]//code/span' 'impl Iterator for Odd'
+// @has - '//*[@id="method.new"]//a[@class="notable-traits"]/@data-ty' 'Odd'
+// @snapshot odd - '//script[@id="notable-traits-data"]'
 pub struct Odd {
     current: usize,
 }
diff --git a/src/test/ui/abi/homogenous-floats-target-feature-mixup.rs b/src/test/ui/abi/homogenous-floats-target-feature-mixup.rs
new file mode 100644 (file)
index 0000000..d7f5e19
--- /dev/null
@@ -0,0 +1,192 @@
+// This test check that even if we mixup target feature of function with homogenous floats,
+// the abi is sound and still produce the right answer.
+//
+// This is basically the same test as src/test/ui/simd/target-feature-mixup.rs but for floats and
+// without #[repr(simd)]
+
+// run-pass
+// ignore-emscripten
+// ignore-sgx no processes
+
+#![feature(avx512_target_feature)]
+
+#![allow(overflowing_literals)]
+#![allow(unused_variables)]
+
+use std::process::{Command, ExitStatus};
+use std::env;
+
+fn main() {
+    if let Some(level) = env::args().nth(1) {
+        return test::main(&level)
+    }
+
+    match std::env::var("TARGET") {
+        Ok(s) => {
+            // Skip this tests on i586-unknown-linux-gnu where sse2 is disabled
+            if s.contains("i586") {
+                return
+            }
+        }
+        Err(_) => return,
+    }
+
+    let me = env::current_exe().unwrap();
+    for level in ["sse", "avx", "avx512"].iter() {
+        let status = Command::new(&me).arg(level).status().unwrap();
+        if status.success() {
+            println!("success with {}", level);
+            continue
+        }
+
+        // We don't actually know if our computer has the requisite target features
+        // for the test below. Testing for that will get added to libstd later so
+        // for now just assume sigill means this is a machine that can't run this test.
+        if is_sigill(status) {
+            println!("sigill with {}, assuming spurious", level);
+            continue
+        }
+        panic!("invalid status at {}: {}", level, status);
+    }
+}
+
+#[cfg(unix)]
+fn is_sigill(status: ExitStatus) -> bool {
+    use std::os::unix::prelude::*;
+    status.signal() == Some(4)
+}
+
+#[cfg(windows)]
+fn is_sigill(status: ExitStatus) -> bool {
+    status.code() == Some(0xc000001d)
+}
+
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+#[allow(nonstandard_style)]
+mod test {
+    #[derive(PartialEq, Debug, Clone, Copy)]
+    struct f32x2(f32, f32);
+
+    #[derive(PartialEq, Debug, Clone, Copy)]
+    struct f32x4(f32, f32, f32, f32);
+
+    #[derive(PartialEq, Debug, Clone, Copy)]
+    struct f32x8(f32, f32, f32, f32, f32, f32, f32, f32);
+
+    pub fn main(level: &str) {
+        unsafe {
+            main_normal(level);
+            main_sse(level);
+            if level == "sse" {
+                return
+            }
+            main_avx(level);
+            if level == "avx" {
+                return
+            }
+            main_avx512(level);
+        }
+    }
+
+    macro_rules! mains {
+        ($(
+            $(#[$attr:meta])*
+            unsafe fn $main:ident(level: &str) {
+                ...
+            }
+        )*) => ($(
+            $(#[$attr])*
+            unsafe fn $main(level: &str) {
+                let m128 = f32x2(1., 2.);
+                let m256 = f32x4(3., 4., 5., 6.);
+                let m512 = f32x8(7., 8., 9., 10., 11., 12., 13., 14.);
+                assert_eq!(id_sse_128(m128), m128);
+                assert_eq!(id_sse_256(m256), m256);
+                assert_eq!(id_sse_512(m512), m512);
+
+                if level == "sse" {
+                    return
+                }
+                assert_eq!(id_avx_128(m128), m128);
+                assert_eq!(id_avx_256(m256), m256);
+                assert_eq!(id_avx_512(m512), m512);
+
+                if level == "avx" {
+                    return
+                }
+                assert_eq!(id_avx512_128(m128), m128);
+                assert_eq!(id_avx512_256(m256), m256);
+                assert_eq!(id_avx512_512(m512), m512);
+            }
+        )*)
+    }
+
+    mains! {
+        unsafe fn main_normal(level: &str) { ... }
+        #[target_feature(enable = "sse2")]
+        unsafe fn main_sse(level: &str) { ... }
+        #[target_feature(enable = "avx")]
+        unsafe fn main_avx(level: &str) { ... }
+        #[target_feature(enable = "avx512bw")]
+        unsafe fn main_avx512(level: &str) { ... }
+    }
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn id_sse_128(a: f32x2) -> f32x2 {
+        assert_eq!(a, f32x2(1., 2.));
+        a.clone()
+    }
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn id_sse_256(a: f32x4) -> f32x4 {
+        assert_eq!(a, f32x4(3., 4., 5., 6.));
+        a.clone()
+    }
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn id_sse_512(a: f32x8) -> f32x8 {
+        assert_eq!(a, f32x8(7., 8., 9., 10., 11., 12., 13., 14.));
+        a.clone()
+    }
+
+    #[target_feature(enable = "avx")]
+    unsafe fn id_avx_128(a: f32x2) -> f32x2 {
+        assert_eq!(a, f32x2(1., 2.));
+        a.clone()
+    }
+
+    #[target_feature(enable = "avx")]
+    unsafe fn id_avx_256(a: f32x4) -> f32x4 {
+        assert_eq!(a, f32x4(3., 4., 5., 6.));
+        a.clone()
+    }
+
+    #[target_feature(enable = "avx")]
+    unsafe fn id_avx_512(a: f32x8) -> f32x8 {
+        assert_eq!(a, f32x8(7., 8., 9., 10., 11., 12., 13., 14.));
+        a.clone()
+    }
+
+    #[target_feature(enable = "avx512bw")]
+    unsafe fn id_avx512_128(a: f32x2) -> f32x2 {
+        assert_eq!(a, f32x2(1., 2.));
+        a.clone()
+    }
+
+    #[target_feature(enable = "avx512bw")]
+    unsafe fn id_avx512_256(a: f32x4) -> f32x4 {
+        assert_eq!(a, f32x4(3., 4., 5., 6.));
+        a.clone()
+    }
+
+    #[target_feature(enable = "avx512bw")]
+    unsafe fn id_avx512_512(a: f32x8) -> f32x8 {
+        assert_eq!(a, f32x8(7., 8., 9., 10., 11., 12., 13., 14.));
+        a.clone()
+    }
+}
+
+#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
+mod test {
+    pub fn main(level: &str) {}
+}
diff --git a/src/test/ui/argument-suggestions/formal-and-expected-differ.rs b/src/test/ui/argument-suggestions/formal-and-expected-differ.rs
new file mode 100644 (file)
index 0000000..5e3b55c
--- /dev/null
@@ -0,0 +1,25 @@
+pub trait Foo {
+    type T;
+}
+
+impl Foo for i32 {
+    type T = f32;
+}
+
+pub struct U<T1, T2>(T1, S<T2>)
+where
+    T1: Foo<T = T2>;
+
+pub struct S<T>(T);
+
+fn main() {
+    // The error message here isn't great -- it has to do with the fact that the
+    // `expected_inputs_for_expected_output` deduced inputs differs from the inputs
+    // that we infer from the constraints of the signature.
+    //
+    // I am not really sure what the best way of presenting this error message is,
+    // since right now it just suggests changing `3u32` <=> `3f32` back and forth.
+    let _: U<_, u32> = U(1, S(3u32));
+    //~^ ERROR mismatched types
+    //~| ERROR mismatched types
+}
diff --git a/src/test/ui/argument-suggestions/formal-and-expected-differ.stderr b/src/test/ui/argument-suggestions/formal-and-expected-differ.stderr
new file mode 100644 (file)
index 0000000..905875b
--- /dev/null
@@ -0,0 +1,30 @@
+error[E0308]: mismatched types
+  --> $DIR/formal-and-expected-differ.rs:22:29
+   |
+LL |     let _: U<_, u32> = U(1, S(3u32));
+   |                        -    ^^^^^^^ expected `f32`, found `u32`
+   |                        |
+   |                        arguments to this struct are incorrect
+   |
+   = note: expected struct `S<f32>`
+              found struct `S<u32>`
+note: tuple struct defined here
+  --> $DIR/formal-and-expected-differ.rs:9:12
+   |
+LL | pub struct U<T1, T2>(T1, S<T2>)
+   |            ^
+
+error[E0308]: mismatched types
+  --> $DIR/formal-and-expected-differ.rs:22:24
+   |
+LL |     let _: U<_, u32> = U(1, S(3u32));
+   |            ---------   ^^^^^^^^^^^^^ expected `u32`, found `f32`
+   |            |
+   |            expected due to this
+   |
+   = note: expected struct `U<_, u32>`
+              found struct `U<i32, f32>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
index 58344be93346d4ba0a2a1f8c5027a257c19e8851..e8ddccc854abe3b8f65a7ee77b3510682c22c97f 100644 (file)
@@ -36,7 +36,7 @@ error: attribute should be applied to a function definition
   --> $DIR/naked-invalid-attr.rs:5:1
    |
 LL | #![naked]
-   | ^^^^^^^^^
+   | ^^^^^^^^^ cannot be applied to crates
 
 error: aborting due to 5 previous errors
 
index 6e464f69510ec22be5f0f29b288a68f32551502c..f67410986e5590c6e3556c9765296f7977032f31 100644 (file)
@@ -132,12 +132,15 @@ fn FW3<T>()
 }
 
 fn FRPIT1() -> impl Iterator<Item: Copy, Item: Send> {
+    //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719]
     iter::empty()
 }
 fn FRPIT2() -> impl Iterator<Item: Copy, Item: Copy> {
+    //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719]
     iter::empty()
 }
 fn FRPIT3() -> impl Iterator<Item: 'static, Item: 'static> {
+    //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719]
     iter::empty()
 }
 fn FAPIT1(_: impl Iterator<Item: Copy, Item: Send>) {}
index e4f4836f71ab21827cd5d434f97b1e390dfee745..c3061327f566e2410ca53b4904d24bcc3fc4225a 100644 (file)
@@ -191,7 +191,31 @@ LL |     T: Iterator<Item: 'static, Item: 'static>,
    |                 `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:143:40
+  --> $DIR/duplicate.rs:134:42
+   |
+LL | fn FRPIT1() -> impl Iterator<Item: Copy, Item: Send> {
+   |                              ----------  ^^^^^^^^^^ re-bound here
+   |                              |
+   |                              `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
+  --> $DIR/duplicate.rs:138:42
+   |
+LL | fn FRPIT2() -> impl Iterator<Item: Copy, Item: Copy> {
+   |                              ----------  ^^^^^^^^^^ re-bound here
+   |                              |
+   |                              `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
+  --> $DIR/duplicate.rs:142:45
+   |
+LL | fn FRPIT3() -> impl Iterator<Item: 'static, Item: 'static> {
+   |                              -------------  ^^^^^^^^^^^^^ re-bound here
+   |                              |
+   |                              `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
+  --> $DIR/duplicate.rs:146:40
    |
 LL | fn FAPIT1(_: impl Iterator<Item: Copy, Item: Send>) {}
    |                            ----------  ^^^^^^^^^^ re-bound here
@@ -199,7 +223,7 @@ LL | fn FAPIT1(_: impl Iterator<Item: Copy, Item: Send>) {}
    |                            `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:145:40
+  --> $DIR/duplicate.rs:148:40
    |
 LL | fn FAPIT2(_: impl Iterator<Item: Copy, Item: Copy>) {}
    |                            ----------  ^^^^^^^^^^ re-bound here
@@ -207,7 +231,7 @@ LL | fn FAPIT2(_: impl Iterator<Item: Copy, Item: Copy>) {}
    |                            `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:147:43
+  --> $DIR/duplicate.rs:150:43
    |
 LL | fn FAPIT3(_: impl Iterator<Item: 'static, Item: 'static>) {}
    |                            -------------  ^^^^^^^^^^^^^ re-bound here
@@ -215,7 +239,7 @@ LL | fn FAPIT3(_: impl Iterator<Item: 'static, Item: 'static>) {}
    |                            `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:150:35
+  --> $DIR/duplicate.rs:153:35
    |
 LL | type TAI1<T: Iterator<Item: Copy, Item: Send>> = T;
    |                       ----------  ^^^^^^^^^^ re-bound here
@@ -223,7 +247,7 @@ LL | type TAI1<T: Iterator<Item: Copy, Item: Send>> = T;
    |                       `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:152:35
+  --> $DIR/duplicate.rs:155:35
    |
 LL | type TAI2<T: Iterator<Item: Copy, Item: Copy>> = T;
    |                       ----------  ^^^^^^^^^^ re-bound here
@@ -231,7 +255,7 @@ LL | type TAI2<T: Iterator<Item: Copy, Item: Copy>> = T;
    |                       `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:154:38
+  --> $DIR/duplicate.rs:157:38
    |
 LL | type TAI3<T: Iterator<Item: 'static, Item: 'static>> = T;
    |                       -------------  ^^^^^^^^^^^^^ re-bound here
@@ -239,7 +263,7 @@ LL | type TAI3<T: Iterator<Item: 'static, Item: 'static>> = T;
    |                       `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:158:29
+  --> $DIR/duplicate.rs:161:29
    |
 LL |     T: Iterator<Item: Copy, Item: Send>,
    |                 ----------  ^^^^^^^^^^ re-bound here
@@ -247,7 +271,7 @@ LL |     T: Iterator<Item: Copy, Item: Send>,
    |                 `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:163:29
+  --> $DIR/duplicate.rs:166:29
    |
 LL |     T: Iterator<Item: Copy, Item: Copy>,
    |                 ----------  ^^^^^^^^^^ re-bound here
@@ -255,7 +279,7 @@ LL |     T: Iterator<Item: Copy, Item: Copy>,
    |                 `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:168:32
+  --> $DIR/duplicate.rs:171:32
    |
 LL |     T: Iterator<Item: 'static, Item: 'static>,
    |                 -------------  ^^^^^^^^^^^^^ re-bound here
@@ -263,7 +287,7 @@ LL |     T: Iterator<Item: 'static, Item: 'static>,
    |                 `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:172:36
+  --> $DIR/duplicate.rs:175:36
    |
 LL | type ETAI1<T: Iterator<Item: Copy, Item: Send>> = impl Copy;
    |                        ----------  ^^^^^^^^^^ re-bound here
@@ -271,7 +295,7 @@ LL | type ETAI1<T: Iterator<Item: Copy, Item: Send>> = impl Copy;
    |                        `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:174:36
+  --> $DIR/duplicate.rs:177:36
    |
 LL | type ETAI2<T: Iterator<Item: Copy, Item: Copy>> = impl Copy;
    |                        ----------  ^^^^^^^^^^ re-bound here
@@ -279,7 +303,7 @@ LL | type ETAI2<T: Iterator<Item: Copy, Item: Copy>> = impl Copy;
    |                        `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:176:39
+  --> $DIR/duplicate.rs:179:39
    |
 LL | type ETAI3<T: Iterator<Item: 'static, Item: 'static>> = impl Copy;
    |                        -------------  ^^^^^^^^^^^^^ re-bound here
@@ -287,7 +311,7 @@ LL | type ETAI3<T: Iterator<Item: 'static, Item: 'static>> = impl Copy;
    |                        `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:178:40
+  --> $DIR/duplicate.rs:181:40
    |
 LL | type ETAI4 = impl Iterator<Item: Copy, Item: Send>;
    |                            ----------  ^^^^^^^^^^ re-bound here
@@ -295,7 +319,7 @@ LL | type ETAI4 = impl Iterator<Item: Copy, Item: Send>;
    |                            `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:180:40
+  --> $DIR/duplicate.rs:183:40
    |
 LL | type ETAI5 = impl Iterator<Item: Copy, Item: Copy>;
    |                            ----------  ^^^^^^^^^^ re-bound here
@@ -303,7 +327,7 @@ LL | type ETAI5 = impl Iterator<Item: Copy, Item: Copy>;
    |                            `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:182:43
+  --> $DIR/duplicate.rs:185:43
    |
 LL | type ETAI6 = impl Iterator<Item: 'static, Item: 'static>;
    |                            -------------  ^^^^^^^^^^^^^ re-bound here
@@ -311,7 +335,7 @@ LL | type ETAI6 = impl Iterator<Item: 'static, Item: 'static>;
    |                            `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:185:36
+  --> $DIR/duplicate.rs:188:36
    |
 LL | trait TRI1<T: Iterator<Item: Copy, Item: Send>> {}
    |                        ----------  ^^^^^^^^^^ re-bound here
@@ -319,7 +343,7 @@ LL | trait TRI1<T: Iterator<Item: Copy, Item: Send>> {}
    |                        `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:187:36
+  --> $DIR/duplicate.rs:190:36
    |
 LL | trait TRI2<T: Iterator<Item: Copy, Item: Copy>> {}
    |                        ----------  ^^^^^^^^^^ re-bound here
@@ -327,7 +351,7 @@ LL | trait TRI2<T: Iterator<Item: Copy, Item: Copy>> {}
    |                        `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:189:39
+  --> $DIR/duplicate.rs:192:39
    |
 LL | trait TRI3<T: Iterator<Item: 'static, Item: 'static>> {}
    |                        -------------  ^^^^^^^^^^^^^ re-bound here
@@ -335,7 +359,7 @@ LL | trait TRI3<T: Iterator<Item: 'static, Item: 'static>> {}
    |                        `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:191:34
+  --> $DIR/duplicate.rs:194:34
    |
 LL | trait TRS1: Iterator<Item: Copy, Item: Send> {}
    |                      ----------  ^^^^^^^^^^ re-bound here
@@ -343,7 +367,7 @@ LL | trait TRS1: Iterator<Item: Copy, Item: Send> {}
    |                      `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:193:34
+  --> $DIR/duplicate.rs:196:34
    |
 LL | trait TRS2: Iterator<Item: Copy, Item: Copy> {}
    |                      ----------  ^^^^^^^^^^ re-bound here
@@ -351,7 +375,7 @@ LL | trait TRS2: Iterator<Item: Copy, Item: Copy> {}
    |                      `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:195:37
+  --> $DIR/duplicate.rs:198:37
    |
 LL | trait TRS3: Iterator<Item: 'static, Item: 'static> {}
    |                      -------------  ^^^^^^^^^^^^^ re-bound here
@@ -359,7 +383,7 @@ LL | trait TRS3: Iterator<Item: 'static, Item: 'static> {}
    |                      `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:199:29
+  --> $DIR/duplicate.rs:202:29
    |
 LL |     T: Iterator<Item: Copy, Item: Send>,
    |                 ----------  ^^^^^^^^^^ re-bound here
@@ -367,7 +391,7 @@ LL |     T: Iterator<Item: Copy, Item: Send>,
    |                 `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:205:29
+  --> $DIR/duplicate.rs:208:29
    |
 LL |     T: Iterator<Item: Copy, Item: Copy>,
    |                 ----------  ^^^^^^^^^^ re-bound here
@@ -375,7 +399,7 @@ LL |     T: Iterator<Item: Copy, Item: Copy>,
    |                 `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:211:32
+  --> $DIR/duplicate.rs:214:32
    |
 LL |     T: Iterator<Item: 'static, Item: 'static>,
    |                 -------------  ^^^^^^^^^^^^^ re-bound here
@@ -383,7 +407,7 @@ LL |     T: Iterator<Item: 'static, Item: 'static>,
    |                 `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:217:32
+  --> $DIR/duplicate.rs:220:32
    |
 LL |     Self: Iterator<Item: Copy, Item: Send>,
    |                    ----------  ^^^^^^^^^^ re-bound here
@@ -391,7 +415,7 @@ LL |     Self: Iterator<Item: Copy, Item: Send>,
    |                    `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:217:32
+  --> $DIR/duplicate.rs:220:32
    |
 LL |     Self: Iterator<Item: Copy, Item: Send>,
    |                    ----------  ^^^^^^^^^^ re-bound here
@@ -399,7 +423,7 @@ LL |     Self: Iterator<Item: Copy, Item: Send>,
    |                    `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:224:32
+  --> $DIR/duplicate.rs:227:32
    |
 LL |     Self: Iterator<Item: Copy, Item: Copy>,
    |                    ----------  ^^^^^^^^^^ re-bound here
@@ -407,7 +431,7 @@ LL |     Self: Iterator<Item: Copy, Item: Copy>,
    |                    `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:224:32
+  --> $DIR/duplicate.rs:227:32
    |
 LL |     Self: Iterator<Item: Copy, Item: Copy>,
    |                    ----------  ^^^^^^^^^^ re-bound here
@@ -415,7 +439,7 @@ LL |     Self: Iterator<Item: Copy, Item: Copy>,
    |                    `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:231:35
+  --> $DIR/duplicate.rs:234:35
    |
 LL |     Self: Iterator<Item: 'static, Item: 'static>,
    |                    -------------  ^^^^^^^^^^^^^ re-bound here
@@ -423,7 +447,7 @@ LL |     Self: Iterator<Item: 'static, Item: 'static>,
    |                    `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:231:35
+  --> $DIR/duplicate.rs:234:35
    |
 LL |     Self: Iterator<Item: 'static, Item: 'static>,
    |                    -------------  ^^^^^^^^^^^^^ re-bound here
@@ -431,7 +455,7 @@ LL |     Self: Iterator<Item: 'static, Item: 'static>,
    |                    `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:249:40
+  --> $DIR/duplicate.rs:252:40
    |
 LL | type TADyn1 = dyn Iterator<Item: Copy, Item: Send>;
    |                            ----------  ^^^^^^^^^^ re-bound here
@@ -439,7 +463,7 @@ LL | type TADyn1 = dyn Iterator<Item: Copy, Item: Send>;
    |                            `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:251:44
+  --> $DIR/duplicate.rs:254:44
    |
 LL | type TADyn2 = Box<dyn Iterator<Item: Copy, Item: Copy>>;
    |                                ----------  ^^^^^^^^^^ re-bound here
@@ -447,7 +471,7 @@ LL | type TADyn2 = Box<dyn Iterator<Item: Copy, Item: Copy>>;
    |                                `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:253:43
+  --> $DIR/duplicate.rs:256:43
    |
 LL | type TADyn3 = dyn Iterator<Item: 'static, Item: 'static>;
    |                            -------------  ^^^^^^^^^^^^^ re-bound here
@@ -455,7 +479,7 @@ LL | type TADyn3 = dyn Iterator<Item: 'static, Item: 'static>;
    |                            `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:237:34
+  --> $DIR/duplicate.rs:240:34
    |
 LL |     type A: Iterator<Item: Copy, Item: Send>;
    |                      ----------  ^^^^^^^^^^ re-bound here
@@ -463,7 +487,7 @@ LL |     type A: Iterator<Item: Copy, Item: Send>;
    |                      `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:241:34
+  --> $DIR/duplicate.rs:244:34
    |
 LL |     type A: Iterator<Item: Copy, Item: Copy>;
    |                      ----------  ^^^^^^^^^^ re-bound here
@@ -471,13 +495,13 @@ LL |     type A: Iterator<Item: Copy, Item: Copy>;
    |                      `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:245:37
+  --> $DIR/duplicate.rs:248:37
    |
 LL |     type A: Iterator<Item: 'static, Item: 'static>;
    |                      -------------  ^^^^^^^^^^^^^ re-bound here
    |                      |
    |                      `Item` bound here first
 
-error: aborting due to 60 previous errors
+error: aborting due to 63 previous errors
 
 For more information about this error, try `rustc --explain E0719`.
index 1dbf5db6c32ed9bdae77c7c18787f270c9d003db..df2ca025705d3955fae6c9b1a0d7333e29f39684 100644 (file)
@@ -6,7 +6,6 @@ async fn copy() -> Result<()>
 //~^ ERROR this enum takes 2 generic arguments
 {
     Ok(())
-    //~^ ERROR type annotations needed
 }
 
 fn main() { }
index 9918f569cbc893528d5cbc7f4f0b69bd2753d43e..45f5ec40cd758b08f914aabdce72e0d85bd7996f 100644 (file)
@@ -16,18 +16,6 @@ help: add missing generic argument
 LL | async fn copy() -> Result<(), E>
    |                             +++
 
-error[E0282]: type annotations needed
-  --> $DIR/issue-65159.rs:8:5
-   |
-LL |     Ok(())
-   |     ^^ cannot infer type of the type parameter `E` declared on the enum `Result`
-   |
-help: consider specifying the generic arguments
-   |
-LL |     Ok::<(), E>(())
-   |       +++++++++
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0107, E0282.
-For more information about an error, try `rustc --explain E0107`.
+For more information about this error, try `rustc --explain E0107`.
index 12942eabdf7b533cfec963112204273d9097f665..e14e2fc05ad39235c7589b830caa423d901621e8 100644 (file)
@@ -1,4 +1,4 @@
 #![feature(rustc_attrs)]
 
-#[rustc_dummy = b"ffi.rs"] //~ ERROR non-ASCII character in byte constant
+#[rustc_dummy = b"ffi.rs"] //~ ERROR non-ASCII character in byte string literal
 fn main() {}
index 422107867f7f995e0f47c80f0c954568405219aa..23d482de6a868e36c6587c130514b8340a989ef7 100644 (file)
@@ -1,8 +1,8 @@
-error: non-ASCII character in byte constant
+error: non-ASCII character in byte string literal
   --> $DIR/key-value-non-ascii.rs:3:19
    |
 LL | #[rustc_dummy = b"ffi.rs"]
-   |                   ^ byte constant must be ASCII
+   |                   ^ must be ASCII
    |
 help: if you meant to use the UTF-8 encoding of 'ffi', use \xHH escapes
    |
diff --git a/src/test/ui/borrowck/async-reference-generality.rs b/src/test/ui/borrowck/async-reference-generality.rs
new file mode 100644 (file)
index 0000000..487d1ac
--- /dev/null
@@ -0,0 +1,35 @@
+// check-fail
+// known-bug: #99492
+// edition: 2021
+
+use std::marker::PhantomData;
+
+pub struct Struct<I, T>(PhantomData<fn() -> <Self as It>::Item>)
+where
+    Self: It;
+
+impl<I> It for Struct<I, I::Item>
+where
+    I: It,
+{
+    type Item = ();
+}
+
+pub trait It {
+    type Item;
+}
+
+fn f() -> impl Send {
+    async {
+        let _x = Struct::<Empty<&'static ()>, _>(PhantomData);
+        async {}.await;
+    }
+}
+
+pub struct Empty<T>(PhantomData<fn() -> T>);
+
+impl<T> It for Empty<T> {
+    type Item = T;
+}
+
+fn main() {}
diff --git a/src/test/ui/borrowck/async-reference-generality.stderr b/src/test/ui/borrowck/async-reference-generality.stderr
new file mode 100644 (file)
index 0000000..af720ad
--- /dev/null
@@ -0,0 +1,27 @@
+error[E0308]: mismatched types
+  --> $DIR/async-reference-generality.rs:23:5
+   |
+LL | /     async {
+LL | |         let _x = Struct::<Empty<&'static ()>, _>(PhantomData);
+LL | |         async {}.await;
+LL | |     }
+   | |_____^ one type is more general than the other
+   |
+   = note: expected reference `&()`
+              found reference `&()`
+
+error[E0308]: mismatched types
+  --> $DIR/async-reference-generality.rs:23:5
+   |
+LL | /     async {
+LL | |         let _x = Struct::<Empty<&'static ()>, _>(PhantomData);
+LL | |         async {}.await;
+LL | |     }
+   | |_____^ one type is more general than the other
+   |
+   = note: expected reference `&()`
+              found reference `&()`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
index a6af129bf39f1191315b1ec0e6206fbda31fa7ac..4eeec09b910401ddd05ad34e618c59a3661fd60b 100644 (file)
@@ -4,7 +4,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     let x = defer(&vec!["Goodbye", "world!"]);
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
    |                    |
-   |                    creates a temporary which is freed while still in use
+   |                    creates a temporary value which is freed while still in use
 LL |     x.x[0];
    |     ------ borrow later used here
    |
index dea8ac90bec2ebe5033acfa2657020c6b574aadd..c62d5f903c8d81d4e32c8cc377f036ab50740294 100644 (file)
@@ -4,7 +4,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     buggy_map.insert(42, &*Box::new(1));
    |                            ^^^^^^^^^^^ - temporary value is freed at the end of this statement
    |                            |
-   |                            creates a temporary which is freed while still in use
+   |                            creates a temporary value which is freed while still in use
 ...
 LL |     buggy_map.insert(43, &*tmp);
    |     --------------------------- borrow later used here
index a5d1f2816f1ca707dbf04b1130d8cf07b82e5c7b..2720b09b0fc5f384d7ff612ffa801149dac8da2c 100644 (file)
@@ -4,7 +4,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     let y = x.as_ref().unwrap_or(&id(5));
    |                                   ^^^^^ - temporary value is freed at the end of this statement
    |                                   |
-   |                                   creates a temporary which is freed while still in use
+   |                                   creates a temporary value which is freed while still in use
 LL |     let _ = &y;
    |             -- borrow later used here
    |
index 79a1e09bd7cc61ad5f8f82a286cd974095f7d75c..3ae7e64d202b69496ea961c93a6f0c409c5f0c33 100644 (file)
@@ -5,7 +5,7 @@ LL |   pub fn foo<'a, F: Fn(&'a ())>(bar: F) {
    |              -- lifetime `'a` defined here
 LL | /     bar.call((
 LL | |         &id(()),
-   | |          ^^^^^^ creates a temporary which is freed while still in use
+   | |          ^^^^^^ creates a temporary value which is freed while still in use
 LL | |     ));
    | |      -- temporary value is freed at the end of this statement
    | |______|
index 8640ca7a509648142c49cde2430c5bc010398588..8fc963a85664e8a88a6407c57974a016cc939cc6 100644 (file)
@@ -10,7 +10,7 @@ fn main() {
     let val: &_ = binding.0;
     //~^ ERROR temporary value dropped while borrowed [E0716]
     //~| NOTE temporary value is freed at the end of this statement
-    //~| NOTE creates a temporary which is freed while still in use
+    //~| NOTE creates a temporary value which is freed while still in use
     //~| HELP consider using a `let` binding to create a longer lived value
     println!("{}", val);
     //~^ borrow later used here
index 877d372fb8484985fb880bc6b5bbe165122ad974..20f66b4d45de4af3cc1bd50b146e76b15c891642 100644 (file)
@@ -9,7 +9,7 @@ fn main() {
     let val: &_ = x.borrow().0;
     //~^ ERROR temporary value dropped while borrowed [E0716]
     //~| NOTE temporary value is freed at the end of this statement
-    //~| NOTE creates a temporary which is freed while still in use
+    //~| NOTE creates a temporary value which is freed while still in use
     //~| HELP consider using a `let` binding to create a longer lived value
     println!("{}", val);
     //~^ borrow later used here
index 4bd586db1cdcea283e86407ae370811641a27f99..a6357f8182fc2aa7a15f6281a76df591089e7c8c 100644 (file)
@@ -4,7 +4,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     let val: &_ = x.borrow().0;
    |                   ^^^^^^^^^^  - temporary value is freed at the end of this statement
    |                   |
-   |                   creates a temporary which is freed while still in use
+   |                   creates a temporary value which is freed while still in use
 ...
 LL |     println!("{}", val);
    |                    --- borrow later used here
index 2c8a700bc2ea37cc53343d5edc97d9d7eaa116df..dd0320bc53ba7d79d1151e7b34ea1ba3e85d845a 100644 (file)
@@ -17,7 +17,6 @@ async fn buy_lock(generator: &Mutex<MarketMultiplier>) -> LockedMarket<'_> {
     //~^ ERROR this struct takes 0 lifetime arguments but 1 lifetime argument was supplied
     //~^^ ERROR this struct takes 1 generic argument but 0 generic arguments were supplied
     LockedMarket(generator.lock().unwrap().buy())
-    //~^ ERROR cannot return value referencing temporary
 }
 
 struct LockedMarket<T>(T);
index 4bd0667304397e0a7b8eb91280cc183c52bcf03b..d2b927fb664c66b1958dbdfd914b771b95b1d2d1 100644 (file)
@@ -7,7 +7,7 @@ LL | async fn buy_lock(generator: &Mutex<MarketMultiplier>) -> LockedMarket<'_>
    |                                                           expected 0 lifetime arguments
    |
 note: struct defined here, with 0 lifetime parameters
-  --> $DIR/issue-82126-mismatched-subst-and-hir.rs:23:8
+  --> $DIR/issue-82126-mismatched-subst-and-hir.rs:22:8
    |
 LL | struct LockedMarket<T>(T);
    |        ^^^^^^^^^^^^
@@ -19,7 +19,7 @@ LL | async fn buy_lock(generator: &Mutex<MarketMultiplier>) -> LockedMarket<'_>
    |                                                           ^^^^^^^^^^^^ expected 1 generic argument
    |
 note: struct defined here, with 1 generic parameter: `T`
-  --> $DIR/issue-82126-mismatched-subst-and-hir.rs:23:8
+  --> $DIR/issue-82126-mismatched-subst-and-hir.rs:22:8
    |
 LL | struct LockedMarket<T>(T);
    |        ^^^^^^^^^^^^ -
@@ -28,16 +28,6 @@ help: add missing generic argument
 LL | async fn buy_lock(generator: &Mutex<MarketMultiplier>) -> LockedMarket<'_, T> {
    |                                                                          +++
 
-error[E0515]: cannot return value referencing temporary value
-  --> $DIR/issue-82126-mismatched-subst-and-hir.rs:19:5
-   |
-LL |     LockedMarket(generator.lock().unwrap().buy())
-   |     ^^^^^^^^^^^^^-------------------------^^^^^^^
-   |     |            |
-   |     |            temporary value created here
-   |     returns a value referencing data owned by the current function
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0107, E0515.
-For more information about an error, try `rustc --explain E0107`.
+For more information about this error, try `rustc --explain E0107`.
index 098bd2d3226e5e7abedc043b11f98d9b536b81fe..422d39742eb552c3be5bb82da23b193fc778a877 100644 (file)
@@ -22,6 +22,10 @@ LL |     f(2);
    |     ^^^^ expected an `Fn<(i32,)>` closure, found `dyn Fn(i32) -> i32`
    |
    = help: the trait `Fn<(i32,)>` is not implemented for `dyn Fn(i32) -> i32`
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+   |
+LL | fn main() where dyn Fn(i32) -> i32: Fn<(i32,)> {
+   |           ++++++++++++++++++++++++++++++++++++
 
 error: aborting due to 3 previous errors
 
index 4ec74494fe09b446315f26a93b67f8b1d01e5a35..6c0dc05ba2330c2a03d1e18fbed4b9eff9847dde 100644 (file)
@@ -6,7 +6,7 @@ LL | #[cfg(target_os = "linuz")]
    |                   |
    |                   help: did you mean: `"linux"`
    |
-   = note: expected values for `target_os` are: android, cuda, dragonfly, emscripten, espidf, freebsd, fuchsia, haiku, hermit, horizon, illumos, ios, l4re, linux, macos, netbsd, none, openbsd, psp, redox, solaris, solid_asp3, tvos, uefi, unknown, vxworks, wasi, watchos, windows, xous
+   = note: expected values for `target_os` are: android, cuda, dragonfly, emscripten, espidf, freebsd, fuchsia, haiku, hermit, horizon, illumos, ios, l4re, linux, macos, netbsd, none, nto, openbsd, psp, redox, solaris, solid_asp3, tvos, uefi, unknown, vxworks, wasi, watchos, windows, xous
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: unexpected `cfg` condition value
index 40f14c389842e6e93331b2d162c5490dfe6e2a47..425cd75141cec4a06241359376d919bfbf7df6db 100644 (file)
@@ -4,7 +4,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     let x1 = arg(&AddFlags(1));
    |                   ^^^^^^^^^^^ - temporary value is freed at the end of this statement
    |                   |
-   |                   creates a temporary which is freed while still in use
+   |                   creates a temporary value which is freed while still in use
 ...
 LL |     (x1, x2, x3, x4, x5, x6, x7);
    |      -- borrow later used here
@@ -21,7 +21,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     let x2 = AddFlags(1).get();
    |              ^^^^^^^^^^^      - temporary value is freed at the end of this statement
    |              |
-   |              creates a temporary which is freed while still in use
+   |              creates a temporary value which is freed while still in use
 ...
 LL |     (x1, x2, x3, x4, x5, x6, x7);
    |          -- borrow later used here
@@ -38,7 +38,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     let x3 = &*arg(&AddFlags(1));
    |                     ^^^^^^^^^^^ - temporary value is freed at the end of this statement
    |                     |
-   |                     creates a temporary which is freed while still in use
+   |                     creates a temporary value which is freed while still in use
 ...
 LL |     (x1, x2, x3, x4, x5, x6, x7);
    |              -- borrow later used here
@@ -55,7 +55,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     let ref x4 = *arg(&AddFlags(1));
    |                        ^^^^^^^^^^^ - temporary value is freed at the end of this statement
    |                        |
-   |                        creates a temporary which is freed while still in use
+   |                        creates a temporary value which is freed while still in use
 ...
 LL |     (x1, x2, x3, x4, x5, x6, x7);
    |                  -- borrow later used here
@@ -72,7 +72,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     let &ref x5 = arg(&AddFlags(1));
    |                        ^^^^^^^^^^^ - temporary value is freed at the end of this statement
    |                        |
-   |                        creates a temporary which is freed while still in use
+   |                        creates a temporary value which is freed while still in use
 ...
 LL |     (x1, x2, x3, x4, x5, x6, x7);
    |                      -- borrow later used here
@@ -89,7 +89,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     let x6 = AddFlags(1).get();
    |              ^^^^^^^^^^^      - temporary value is freed at the end of this statement
    |              |
-   |              creates a temporary which is freed while still in use
+   |              creates a temporary value which is freed while still in use
 ...
 LL |     (x1, x2, x3, x4, x5, x6, x7);
    |                          -- borrow later used here
@@ -106,7 +106,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     let StackBox { f: x7 } = StackBox { f: AddFlags(1).get() };
    |                                            ^^^^^^^^^^^        - temporary value is freed at the end of this statement
    |                                            |
-   |                                            creates a temporary which is freed while still in use
+   |                                            creates a temporary value which is freed while still in use
 LL |
 LL |     (x1, x2, x3, x4, x5, x6, x7);
    |                              -- borrow later used here
index 38401085971316efcf649a298b3e21f5bc4099a7..39ec71ba22a185214dfc679c2de5ff1c82e1aede 100644 (file)
@@ -16,7 +16,7 @@ LL | /     || match out_ref {
 LL | |         Variant::A => (),
 LL | |         Variant::B => (),
 LL | |     };
-   | |______^
+   | |_____^
    |
    = note: closures are lazy and do nothing unless called
    = note: `#[warn(unused_must_use)]` on by default
@@ -28,7 +28,7 @@ LL | /     || match here.field {
 LL | |         Variant::A => (),
 LL | |         Variant::B => (),
 LL | |     };
-   | |______^
+   | |_____^
    |
    = note: closures are lazy and do nothing unless called
 
diff --git a/src/test/ui/closures/supertrait-hint-references-assoc-ty.rs b/src/test/ui/closures/supertrait-hint-references-assoc-ty.rs
new file mode 100644 (file)
index 0000000..270bf14
--- /dev/null
@@ -0,0 +1,17 @@
+// check-pass
+
+pub trait Fn0: Fn(i32) -> Self::Out {
+    type Out;
+}
+
+impl<F: Fn(i32) -> ()> Fn0 for F {
+    type Out = ();
+}
+
+pub fn closure_typer(_: impl Fn0) {}
+
+fn main() {
+    closure_typer(move |x| {
+        let _: i64 = x.into();
+    });
+}
index f24874c992eafc0e39c7e45f7a4a3e7ff87d69d6..b223aff4e94923f151020f3ec51eeeeca3991d08 100644 (file)
@@ -1,6 +1,5 @@
 // build-pass
 #![feature(trait_upcasting)]
-#![allow(incomplete_features)]
 
 pub trait A {}
 pub trait B {}
index 5f278f94b93bd9a41752c48f7ea0f419e595060e..fbfcd45652f19a091b178673f0ab5359ae58a3d4 100644 (file)
@@ -28,7 +28,7 @@ warning: unused `MustUseDeprecated` that must be used
   --> $DIR/cfg-attr-multi-true.rs:19:5
    |
 LL |     MustUseDeprecated::new();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
   --> $DIR/cfg-attr-multi-true.rs:7:9
index d68acd2451fba05bf88b2ff480371af504a196e7..99a7949db173c862b45287a1794b5ff42a5be85b 100644 (file)
@@ -46,7 +46,7 @@ enum Enum {
 trait Trait {}
 impl dyn Trait { fn existing() {} }
 
-// FIXME: Should be a error for edition > 2015
+// FIXME: Should be an error for edition > 2015
 #[cfg_accessible(Trait::existing)] //~ ERROR not sure
 const A: bool = true;
 #[cfg_accessible(Trait::unresolved)] //~ ERROR not sure
index f83518fc9d4763afd152e38e632577abead52f44..7fb69032e6fc48b2e4cd6fc8a3accde632b753ef 100644 (file)
@@ -14,7 +14,6 @@ impl<const N: usize> Marker<N> for Example<N> {}
 fn make_marker() -> impl Marker<gimme_a_const!(marker)> {
   //~^ ERROR: type provided when a constant was expected
   Example::<gimme_a_const!(marker)>
-  //~^ ERROR: type provided when a constant was expected
 }
 
 fn from_marker(_: impl Marker<{
@@ -34,9 +33,7 @@ macro_rules! gimme_a_const {
   }>;
 
   let _fail = Example::<external_macro!()>;
-  //~^ ERROR: type provided when a constant was expected
 
   let _fail = Example::<gimme_a_const!()>;
-  //~^ ERROR: type provided when a constant was expected
-  //~| ERROR unexpected end of macro invocation
+  //~^ ERROR unexpected end of macro invocation
 }
index d5dd70d9b489cf98bebf5d9a67f4ca2637e3cb6a..2b75c19774842c410714d6ee14752aa0cf2023de 100644 (file)
@@ -1,5 +1,5 @@
 error: expected type, found `{`
-  --> $DIR/macro-fail.rs:29:27
+  --> $DIR/macro-fail.rs:28:27
    |
 LL | fn make_marker() -> impl Marker<gimme_a_const!(marker)> {
    |                                 ----------------------
@@ -13,7 +13,7 @@ LL |       ($rusty: ident) => {{ let $rusty = 3; *&$rusty }}
    = note: this error originates in the macro `gimme_a_const` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: expected type, found `{`
-  --> $DIR/macro-fail.rs:29:27
+  --> $DIR/macro-fail.rs:28:27
    |
 LL |   Example::<gimme_a_const!(marker)>
    |             ----------------------
@@ -46,7 +46,7 @@ LL |     let _fail = Example::<external_macro!()>;
    = note: this error originates in the macro `external_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: unexpected end of macro invocation
-  --> $DIR/macro-fail.rs:39:25
+  --> $DIR/macro-fail.rs:37:25
    |
 LL |     macro_rules! gimme_a_const {
    |     -------------------------- when calling this macro
@@ -60,24 +60,6 @@ error[E0747]: type provided when a constant was expected
 LL | fn make_marker() -> impl Marker<gimme_a_const!(marker)> {
    |                                 ^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0747]: type provided when a constant was expected
-  --> $DIR/macro-fail.rs:16:13
-   |
-LL |   Example::<gimme_a_const!(marker)>
-   |             ^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0747]: type provided when a constant was expected
-  --> $DIR/macro-fail.rs:36:25
-   |
-LL |   let _fail = Example::<external_macro!()>;
-   |                         ^^^^^^^^^^^^^^^^^
-
-error[E0747]: type provided when a constant was expected
-  --> $DIR/macro-fail.rs:39:25
-   |
-LL |   let _fail = Example::<gimme_a_const!()>;
-   |                         ^^^^^^^^^^^^^^^^
-
-error: aborting due to 8 previous errors
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0747`.
index 78143042ece7bfc30aa3d714e4677d37571c448f..ed6a6ee6e0fd9298f810658e6146d86f4c2a0617 100644 (file)
@@ -4,7 +4,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     let x: &'static usize =
    |            -------------- type annotation requires that borrow lasts for `'static`
 LL |         &std::intrinsics::size_of::<i32>();
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
 LL | }
    | - temporary value is freed at the end of this statement
 
index 69e3ca716a90939e655dc61d6a7f4c2df2dafb5f..2e697b219c5a4b7e53ad465a7c68478eaf160b1e 100644 (file)
@@ -10,7 +10,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/dont_promote_unstable_const_fn.rs:17:28
    |
 LL |     let _: &'static u32 = &foo();
-   |            ------------    ^^^^^ creates a temporary which is freed while still in use
+   |            ------------    ^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 LL | }
@@ -20,7 +20,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/dont_promote_unstable_const_fn.rs:21:28
    |
 LL |     let _: &'static u32 = &meh();
-   |            ------------    ^^^^^ creates a temporary which is freed while still in use
+   |            ------------    ^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -31,7 +31,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/dont_promote_unstable_const_fn.rs:22:26
    |
 LL |     let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis();
-   |            ----------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            ----------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 LL |
index 129f06151074f7b4b7da7cc587f012215008ec7c..aa742d784e0350bcf612ed844eeb8dff0930df5c 100644 (file)
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/dont_promote_unstable_const_fn_cross_crate.rs:8:28
    |
 LL |     let _: &'static u32 = &foo();
-   |            ------------    ^^^^^ creates a temporary which is freed while still in use
+   |            ------------    ^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 LL |     let _x: &'static u32 = &foo();
@@ -13,7 +13,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/dont_promote_unstable_const_fn_cross_crate.rs:9:29
    |
 LL |     let _x: &'static u32 = &foo();
-   |             ------------    ^^^^^ creates a temporary which is freed while still in use
+   |             ------------    ^^^^^ creates a temporary value which is freed while still in use
    |             |
    |             type annotation requires that borrow lasts for `'static`
 LL | }
index 596fa090d976fe7adf83ca1949f4564f88a632c5..2d4e7c83d3e4e8a34c44929c1f56a7786ce948d1 100644 (file)
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promoted_const_fn_fail.rs:17:27
    |
 LL |     let x: &'static u8 = &(bar() + 1);
-   |            -----------    ^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            -----------    ^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
index 63dc43a41a8fc096c94c605ad5694bf6e475a4c9..9ebae3a18a32f15e3d81f92725a0bb94ee3a1f6f 100644 (file)
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promoted_const_fn_fail_deny_const_err.rs:18:27
    |
 LL |     let x: &'static u8 = &(bar() + 1);
-   |            -----------    ^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            -----------    ^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
index 8ac60da38634b8f3b0c1d81f840ea6610316458b..01fcf2ec213424c8eaf38d1ea376e3b09e442d25 100644 (file)
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promoted_raw_ptr_ops.rs:2:29
    |
 LL |     let x: &'static bool = &(42 as *const i32 == 43 as *const i32);
-   |            -------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            -------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -13,7 +13,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promoted_raw_ptr_ops.rs:4:30
    |
 LL |     let y: &'static usize = &(&1 as *const i32 as usize + 1);
-   |            --------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            --------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -24,7 +24,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promoted_raw_ptr_ops.rs:6:28
    |
 LL |     let z: &'static i32 = &(unsafe { *(42 as *const i32) });
-   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -35,7 +35,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promoted_raw_ptr_ops.rs:8:29
    |
 LL |     let a: &'static bool = &(main as fn() == main as fn());
-   |            -------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            -------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 LL |
index 15b9b56ea66066c540491774ce3366bf7286df0c..434a957f64840780855d05b058692836b41f3e70 100644 (file)
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/transmute-const-promotion.rs:4:37
    |
 LL |     let x: &'static u32 = unsafe { &mem::transmute(3.0f32) };
-   |            ------------             ^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            ------------             ^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 LL |
index 70808c520d3f9748ed7e4683eedd308816ebc41c..42f17de200344598613ef63e0c8c2226d822a94d 100644 (file)
@@ -7,7 +7,7 @@ LL |       let x: &'static bool = &unsafe {
    | |            type annotation requires that borrow lasts for `'static`
 LL | |         Foo { a: &1 }.b == Foo { a: &2 }.b
 LL | |     };
-   | |_____^ creates a temporary which is freed while still in use
+   | |_____^ creates a temporary value which is freed while still in use
 LL |   }
    |   - temporary value is freed at the end of this statement
 
index 61162a792262bd98aaca4cfd0de4088a80e9d8f2..5dd757e3f5ee1fb049958d7cb5ffa8d97212bb2d 100644 (file)
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-int-conversion.rs:2:28
    |
 LL |     let x: &'static i32 = &(5_i32.reverse_bits());
-   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -13,7 +13,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-int-conversion.rs:4:28
    |
 LL |     let y: &'static i32 = &(i32::from_be_bytes([0x12, 0x34, 0x56, 0x78]));
-   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -24,7 +24,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-int-conversion.rs:6:28
    |
 LL |     let z: &'static i32 = &(i32::from_le_bytes([0x12, 0x34, 0x56, 0x78]));
-   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -35,7 +35,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-int-conversion.rs:8:28
    |
 LL |     let a: &'static i32 = &(i32::from_be(i32::from_ne_bytes([0x80, 0, 0, 0])));
-   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -46,7 +46,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-int-conversion.rs:10:29
    |
 LL |     let b: &'static [u8] = &(0x12_34_56_78_i32.to_be_bytes());
-   |            -------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            -------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -57,7 +57,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-int-conversion.rs:12:29
    |
 LL |     let c: &'static [u8] = &(0x12_34_56_78_i32.to_le_bytes());
-   |            -------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            -------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -68,7 +68,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-int-conversion.rs:14:29
    |
 LL |     let d: &'static [u8] = &(i32::MIN.to_be().to_ne_bytes());
-   |            -------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            -------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 LL |
index 56c7f7f092d665d1a419bd7381f563df01d8bd18..7d3689e6ec7d7ac188b3fcd47a882ca40519316e 100644 (file)
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-int-overflowing.rs:2:36
    |
 LL |     let x: &'static (i32, bool) = &(5_i32.overflowing_add(3));
-   |            --------------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            --------------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -13,7 +13,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-int-overflowing.rs:4:36
    |
 LL |     let y: &'static (i32, bool) = &(5_i32.overflowing_sub(3));
-   |            --------------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            --------------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -24,7 +24,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-int-overflowing.rs:6:36
    |
 LL |     let z: &'static (i32, bool) = &(5_i32.overflowing_mul(3));
-   |            --------------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            --------------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 LL |
index ed265804bbc6c62d40ab9ea84ed98a1edc38596e..039da1c31c57571ad97b3734499e3d63d45ac870 100644 (file)
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-int-rotate.rs:2:28
    |
 LL |     let x: &'static i32 = &(5_i32.rotate_left(3));
-   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -13,7 +13,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-int-rotate.rs:4:28
    |
 LL |     let y: &'static i32 = &(5_i32.rotate_right(3));
-   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 LL |
index 5f8fd4141804c21aa17fe033d3c1203872d562af..fc23d9d2b2942f6bc4eb7b136314ee61bca53b43 100644 (file)
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-int-sign.rs:2:29
    |
 LL |     let x: &'static bool = &(5_i32.is_negative());
-   |            -------------    ^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            -------------    ^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -13,7 +13,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-int-sign.rs:4:29
    |
 LL |     let y: &'static bool = &(5_i32.is_positive());
-   |            -------------    ^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            -------------    ^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 LL |
index 5174b72659cd775f6feef0f0af1479789cde7f21..1342fadc4055b2bcc24d109aaf8a473c8e34ea1c 100644 (file)
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-int-wrapping.rs:2:28
    |
 LL |     let x: &'static i32 = &(5_i32.wrapping_add(3));
-   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -13,7 +13,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-int-wrapping.rs:4:28
    |
 LL |     let y: &'static i32 = &(5_i32.wrapping_sub(3));
-   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -24,7 +24,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-int-wrapping.rs:6:28
    |
 LL |     let z: &'static i32 = &(5_i32.wrapping_mul(3));
-   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -35,7 +35,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-int-wrapping.rs:8:28
    |
 LL |     let a: &'static i32 = &(5_i32.wrapping_shl(3));
-   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -46,7 +46,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-int-wrapping.rs:10:28
    |
 LL |     let b: &'static i32 = &(5_i32.wrapping_shr(3));
-   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            ------------    ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 LL |
index 3a9ce79f10ef295b562ba60a0653f6c9cab2cfc4..78c58b5ab092b98df4f0b0be9b901473084fdba7 100644 (file)
@@ -11,7 +11,7 @@ LL | const B3: Option<&mut i32> = Some(&mut 42);
    |                              ----------^^-
    |                              |         | |
    |                              |         | temporary value is freed at the end of this statement
-   |                              |         creates a temporary which is freed while still in use
+   |                              |         creates a temporary value which is freed while still in use
    |                              using this value as a constant requires that borrow lasts for `'static`
 
 error[E0716]: temporary value dropped while borrowed
@@ -21,7 +21,7 @@ LL | const B4: Option<&mut i32> = helper(&mut 42);
    |                              ------------^^-
    |                              |           | |
    |                              |           | temporary value is freed at the end of this statement
-   |                              |           creates a temporary which is freed while still in use
+   |                              |           creates a temporary value which is freed while still in use
    |                              using this value as a constant requires that borrow lasts for `'static`
 
 error[E0716]: temporary value dropped while borrowed
@@ -31,7 +31,7 @@ LL | const FOO: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42));
    |                                  -------------------------------^^--
    |                                  |                              |  |
    |                                  |                              |  temporary value is freed at the end of this statement
-   |                                  |                              creates a temporary which is freed while still in use
+   |                                  |                              creates a temporary value which is freed while still in use
    |                                  using this value as a constant requires that borrow lasts for `'static`
 
 error[E0716]: temporary value dropped while borrowed
@@ -41,7 +41,7 @@ LL | static FOO2: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42));
    |                                    -------------------------------^^--
    |                                    |                              |  |
    |                                    |                              |  temporary value is freed at the end of this statement
-   |                                    |                              creates a temporary which is freed while still in use
+   |                                    |                              creates a temporary value which is freed while still in use
    |                                    using this value as a static requires that borrow lasts for `'static`
 
 error[E0716]: temporary value dropped while borrowed
@@ -51,7 +51,7 @@ LL | static mut FOO3: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42));
    |                                        -------------------------------^^--
    |                                        |                              |  |
    |                                        |                              |  temporary value is freed at the end of this statement
-   |                                        |                              creates a temporary which is freed while still in use
+   |                                        |                              creates a temporary value which is freed while still in use
    |                                        using this value as a static requires that borrow lasts for `'static`
 
 error: aborting due to 6 previous errors
index 26946fb99024c43008e2f4326fa4ad65ad0ac983..dbcb0c86052ee3fdeb4536d1f2432258a8076ff5 100644 (file)
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-ptr-nonnull.rs:4:37
    |
 LL |     let x: &'static NonNull<u32> = &(NonNull::dangling());
-   |            ---------------------    ^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            ---------------------    ^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -13,7 +13,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-ptr-nonnull.rs:9:37
    |
 LL |     let x: &'static NonNull<u32> = &(non_null.cast());
-   |            ---------------------    ^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            ---------------------    ^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 LL |
index 3644cf4cec7d3b7fb47100feeb4f146b877dd8ba..83448c3e8d8766e3ab7884055cfffcd7c17452b4 100644 (file)
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/const-ptr-unique.rs:8:33
    |
 LL |     let x: &'static *mut u32 = &(unique.as_ptr());
-   |            -----------------    ^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |            -----------------    ^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 LL |
index 4f9c7d34c35f4fc5db581d76698446d4bdc99a28..db2ffb91b988b0d65c37e96d81b401ec400fc467 100644 (file)
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/interior-mutability.rs:40:26
    |
 LL |     let x: &'static _ = &X;
-   |            ----------    ^ creates a temporary which is freed while still in use
+   |            ----------    ^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -13,7 +13,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/interior-mutability.rs:41:26
    |
 LL |     let y: &'static _ = &Y;
-   |            ----------    ^ creates a temporary which is freed while still in use
+   |            ----------    ^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 LL |     let z: &'static _ = &Z;
@@ -24,7 +24,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/interior-mutability.rs:42:26
    |
 LL |     let z: &'static _ = &Z;
-   |            ----------    ^ creates a temporary which is freed while still in use
+   |            ----------    ^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 LL | }
diff --git a/src/test/ui/consts/fn_trait_refs.rs b/src/test/ui/consts/fn_trait_refs.rs
new file mode 100644 (file)
index 0000000..b507492
--- /dev/null
@@ -0,0 +1,77 @@
+// check-pass
+
+#![feature(const_fn_trait_ref_impls)]
+#![feature(fn_traits)]
+#![feature(unboxed_closures)]
+#![feature(const_trait_impl)]
+#![feature(const_mut_refs)]
+#![feature(const_cmp)]
+#![feature(const_refs_to_cell)]
+
+use std::marker::Destruct;
+
+const fn tester_fn<T>(f: T) -> T::Output
+where
+    T: ~const Fn<()> + ~const Destruct,
+{
+    f()
+}
+
+const fn tester_fn_mut<T>(mut f: T) -> T::Output
+where
+    T: ~const FnMut<()> + ~const Destruct,
+{
+    f()
+}
+
+const fn tester_fn_once<T>(f: T) -> T::Output
+where
+    T: ~const FnOnce<()>,
+{
+    f()
+}
+
+const fn test_fn<T>(mut f: T) -> (T::Output, T::Output, T::Output)
+where
+    T: ~const Fn<()> + ~const Destruct,
+{
+    (
+        // impl<A: Tuple, F: ~const Fn + ?Sized> const Fn<A> for &F
+        tester_fn(&f),
+        // impl<A: Tuple, F: ~const Fn + ?Sized> const FnMut<A> for &F
+        tester_fn_mut(&f),
+        // impl<A: Tuple, F: ~const Fn + ?Sized> const FnOnce<A> for &F
+        tester_fn_once(&f),
+    )
+}
+
+const fn test_fn_mut<T>(mut f: T) -> (T::Output, T::Output)
+where
+    T: ~const FnMut<()> + ~const Destruct,
+{
+    (
+        // impl<A: Tuple, F: ~const FnMut + ?Sized> const FnMut<A> for &mut F
+        tester_fn_mut(&mut f),
+        // impl<A: Tuple, F: ~const FnMut + ?Sized> const FnOnce<A> for &mut F
+        tester_fn_once(&mut f),
+    )
+}
+const fn test(i: i32) -> i32 {
+    i + 1
+}
+
+fn main() {
+    const fn one() -> i32 {
+        1
+    };
+    const fn two() -> i32 {
+        2
+    };
+    const _: () = {
+        let test_one = test_fn(one);
+        assert!(test_one == (1, 1, 1));
+
+        let test_two = test_fn_mut(two);
+        assert!(test_two == (2, 2));
+    };
+}
diff --git a/src/test/ui/consts/invalid-const-in-body.rs b/src/test/ui/consts/invalid-const-in-body.rs
new file mode 100644 (file)
index 0000000..f0fa3bb
--- /dev/null
@@ -0,0 +1,6 @@
+fn f() -> impl Sized {
+    2.0E
+    //~^ ERROR expected at least one digit in exponent
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/invalid-const-in-body.stderr b/src/test/ui/consts/invalid-const-in-body.stderr
new file mode 100644 (file)
index 0000000..3be6583
--- /dev/null
@@ -0,0 +1,8 @@
+error: expected at least one digit in exponent
+  --> $DIR/invalid-const-in-body.rs:2:5
+   |
+LL |     2.0E
+   |     ^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/consts/issue-104155.rs b/src/test/ui/consts/issue-104155.rs
new file mode 100644 (file)
index 0000000..1cc8f81
--- /dev/null
@@ -0,0 +1,5 @@
+// check-pass
+const _: () = core::mem::forget(Box::<u32>::default);
+const _: () = core::mem::forget(|| Box::<u32>::default());
+
+fn main() {}
index 8dcb4daca3b707a564a8fc7f50bb13e6a2996299..55fe55759df54005fce3412078898677a5104a70 100644 (file)
@@ -5,7 +5,7 @@ LL | const FOO: Option<&[[u8; 3]]> = Some(&[*b"foo"]);
    |                                 ------^^^^^^^^^-
    |                                 |     |        |
    |                                 |     |        temporary value is freed at the end of this statement
-   |                                 |     creates a temporary which is freed while still in use
+   |                                 |     creates a temporary value which is freed while still in use
    |                                 using this value as a constant requires that borrow lasts for `'static`
 
 error[E0716]: temporary value dropped while borrowed
@@ -15,7 +15,7 @@ LL | pub const Z: Cow<'static, [ [u8; 3] ]> = Cow::Borrowed(&[*b"ABC"]);
    |                                          ---------------^^^^^^^^^-
    |                                          |              |        |
    |                                          |              |        temporary value is freed at the end of this statement
-   |                                          |              creates a temporary which is freed while still in use
+   |                                          |              creates a temporary value which is freed while still in use
    |                                          using this value as a constant requires that borrow lasts for `'static`
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/consts/issue-54954.rs b/src/test/ui/consts/issue-54954.rs
new file mode 100644 (file)
index 0000000..d4e1df2
--- /dev/null
@@ -0,0 +1,19 @@
+const ARR_LEN: usize = Tt::const_val::<[i8; 123]>();
+//~^ ERROR E0790
+
+trait Tt {
+    const fn const_val<T: Sized>() -> usize {
+        //~^ ERROR functions in traits cannot be declared const
+        core::mem::size_of::<T>()
+    }
+}
+
+fn f(z: [f32; ARR_LEN]) -> [f32; ARR_LEN] {
+  //~^ ERROR evaluation of constant value failed
+  //~| ERROR evaluation of constant value failed
+    z
+}
+
+fn main() {
+    let _ = f([1f32; ARR_LEN]);
+}
diff --git a/src/test/ui/consts/issue-54954.stderr b/src/test/ui/consts/issue-54954.stderr
new file mode 100644 (file)
index 0000000..668985c
--- /dev/null
@@ -0,0 +1,34 @@
+error[E0379]: functions in traits cannot be declared const
+  --> $DIR/issue-54954.rs:5:5
+   |
+LL |     const fn const_val<T: Sized>() -> usize {
+   |     ^^^^^ functions in traits cannot be const
+
+error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type
+  --> $DIR/issue-54954.rs:1:24
+   |
+LL |   const ARR_LEN: usize = Tt::const_val::<[i8; 123]>();
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot call associated function of trait
+...
+LL | /     const fn const_val<T: Sized>() -> usize {
+LL | |
+LL | |         core::mem::size_of::<T>()
+LL | |     }
+   | |_____- `Tt::const_val` defined here
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/issue-54954.rs:11:15
+   |
+LL | fn f(z: [f32; ARR_LEN]) -> [f32; ARR_LEN] {
+   |               ^^^^^^^ referenced constant has errors
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/issue-54954.rs:11:34
+   |
+LL | fn f(z: [f32; ARR_LEN]) -> [f32; ARR_LEN] {
+   |                                  ^^^^^^^ referenced constant has errors
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0080, E0379, E0790.
+For more information about an error, try `rustc --explain E0080`.
index 550423c2d933c2d533937596cbead032585328d0..0b8dc0ce0e903c75322bc3c0926883887392b14d 100644 (file)
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promotion.rs:11:27
    |
 LL |     let x: &'static () = &foo1();
-   |            -----------    ^^^^^^ creates a temporary which is freed while still in use
+   |            -----------    ^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -13,7 +13,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promotion.rs:12:28
    |
 LL |     let y: &'static i32 = &foo2(42);
-   |            ------------    ^^^^^^^^ creates a temporary which is freed while still in use
+   |            ------------    ^^^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -24,7 +24,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promotion.rs:13:28
    |
 LL |     let z: &'static i32 = &foo3();
-   |            ------------    ^^^^^^ creates a temporary which is freed while still in use
+   |            ------------    ^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -35,7 +35,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promotion.rs:14:34
    |
 LL |     let a: &'static Cell<i32> = &foo4();
-   |            ------------------    ^^^^^^ creates a temporary which is freed while still in use
+   |            ------------------    ^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -46,7 +46,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promotion.rs:15:42
    |
 LL |     let a: &'static Option<Cell<i32>> = &foo5();
-   |            --------------------------    ^^^^^^ creates a temporary which is freed while still in use
+   |            --------------------------    ^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 LL |     let a: &'static Option<Cell<i32>> = &foo6();
@@ -57,7 +57,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promotion.rs:16:42
    |
 LL |     let a: &'static Option<Cell<i32>> = &foo6();
-   |            --------------------------    ^^^^^^ creates a temporary which is freed while still in use
+   |            --------------------------    ^^^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 LL | }
index 0d0b0f9c689b5b6593d007015efb60d00f71fba3..b93358e8dcceaa1ef17b1ae58a4d492e1118f3e6 100644 (file)
@@ -5,14 +5,14 @@ LL | static mut TEST1: Option<&mut [i32]> = Some(&mut [1, 2, 3]);
    |                                        ----------^^^^^^^^^-
    |                                        |         |        |
    |                                        |         |        temporary value is freed at the end of this statement
-   |                                        |         creates a temporary which is freed while still in use
+   |                                        |         creates a temporary value which is freed while still in use
    |                                        using this value as a static requires that borrow lasts for `'static`
 
 error[E0716]: temporary value dropped while borrowed
   --> $DIR/promote-not.rs:11:18
    |
 LL |     let x = &mut [1,2,3];
-   |                  ^^^^^^^ creates a temporary which is freed while still in use
+   |                  ^^^^^^^ creates a temporary value which is freed while still in use
 LL |     x
    |     - using this value as a static requires that borrow lasts for `'static`
 LL | };
@@ -22,7 +22,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promote-not.rs:20:32
    |
 LL |         let _x: &'static () = &foo();
-   |                 -----------    ^^^^^ creates a temporary which is freed while still in use
+   |                 -----------    ^^^^^ creates a temporary value which is freed while still in use
    |                 |
    |                 type annotation requires that borrow lasts for `'static`
 LL |     }
@@ -32,7 +32,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promote-not.rs:28:29
    |
 LL |     let _x: &'static i32 = &unsafe { U { x: 0 }.x };
-   |             ------------    ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |             ------------    ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |             |
    |             type annotation requires that borrow lasts for `'static`
 LL | }
@@ -42,7 +42,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promote-not.rs:33:29
    |
 LL |     let _x: &'static i32 = &unsafe { U { x: 0 }.x };
-   |             ------------    ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |             ------------    ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |             |
    |             type annotation requires that borrow lasts for `'static`
 LL | };
@@ -52,7 +52,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promote-not.rs:39:29
    |
 LL |     let _val: &'static _ = &(Cell::new(1), 2).1;
-   |               ----------    ^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |               ----------    ^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |               |
    |               type annotation requires that borrow lasts for `'static`
 LL | };
@@ -62,7 +62,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promote-not.rs:46:29
    |
 LL |     let _val: &'static _ = &(Cell::new(1), 2).0;
-   |               ----------    ^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |               ----------    ^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |               |
    |               type annotation requires that borrow lasts for `'static`
 ...
@@ -73,7 +73,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promote-not.rs:47:29
    |
 LL |     let _val: &'static _ = &(Cell::new(1), 2).1;
-   |               ----------    ^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |               ----------    ^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |               |
    |               type annotation requires that borrow lasts for `'static`
 ...
@@ -84,7 +84,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promote-not.rs:50:29
    |
 LL |     let _val: &'static _ = &(1/0);
-   |               ----------    ^^^^^ creates a temporary which is freed while still in use
+   |               ----------    ^^^^^ creates a temporary value which is freed while still in use
    |               |
    |               type annotation requires that borrow lasts for `'static`
 ...
@@ -95,7 +95,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promote-not.rs:51:29
    |
 LL |     let _val: &'static _ = &(1/(1-1));
-   |               ----------    ^^^^^^^^^ creates a temporary which is freed while still in use
+   |               ----------    ^^^^^^^^^ creates a temporary value which is freed while still in use
    |               |
    |               type annotation requires that borrow lasts for `'static`
 ...
@@ -106,7 +106,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promote-not.rs:52:29
    |
 LL |     let _val: &'static _ = &(1%0);
-   |               ----------    ^^^^^ creates a temporary which is freed while still in use
+   |               ----------    ^^^^^ creates a temporary value which is freed while still in use
    |               |
    |               type annotation requires that borrow lasts for `'static`
 ...
@@ -117,7 +117,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promote-not.rs:53:29
    |
 LL |     let _val: &'static _ = &(1%(1-1));
-   |               ----------    ^^^^^^^^^ creates a temporary which is freed while still in use
+   |               ----------    ^^^^^^^^^ creates a temporary value which is freed while still in use
    |               |
    |               type annotation requires that borrow lasts for `'static`
 ...
@@ -128,7 +128,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promote-not.rs:54:29
    |
 LL |     let _val: &'static _ = &([1,2,3][4]+1);
-   |               ----------    ^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |               ----------    ^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |               |
    |               type annotation requires that borrow lasts for `'static`
 ...
@@ -139,7 +139,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promote-not.rs:57:29
    |
 LL |     let _val: &'static _ = &TEST_DROP;
-   |               ----------    ^^^^^^^^^ creates a temporary which is freed while still in use
+   |               ----------    ^^^^^^^^^ creates a temporary value which is freed while still in use
    |               |
    |               type annotation requires that borrow lasts for `'static`
 ...
@@ -150,7 +150,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promote-not.rs:59:29
    |
 LL |     let _val: &'static _ = &&TEST_DROP;
-   |               ----------    ^^^^^^^^^^ creates a temporary which is freed while still in use
+   |               ----------    ^^^^^^^^^^ creates a temporary value which is freed while still in use
    |               |
    |               type annotation requires that borrow lasts for `'static`
 ...
@@ -161,7 +161,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promote-not.rs:59:30
    |
 LL |     let _val: &'static _ = &&TEST_DROP;
-   |               ----------     ^^^^^^^^^ creates a temporary which is freed while still in use
+   |               ----------     ^^^^^^^^^ creates a temporary value which is freed while still in use
    |               |
    |               type annotation requires that borrow lasts for `'static`
 ...
@@ -172,7 +172,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promote-not.rs:62:29
    |
 LL |     let _val: &'static _ = &(&TEST_DROP,);
-   |               ----------    ^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |               ----------    ^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |               |
    |               type annotation requires that borrow lasts for `'static`
 ...
@@ -183,7 +183,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promote-not.rs:62:31
    |
 LL |     let _val: &'static _ = &(&TEST_DROP,);
-   |               ----------      ^^^^^^^^^ creates a temporary which is freed while still in use
+   |               ----------      ^^^^^^^^^ creates a temporary value which is freed while still in use
    |               |
    |               type annotation requires that borrow lasts for `'static`
 ...
@@ -194,7 +194,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promote-not.rs:65:29
    |
 LL |     let _val: &'static _ = &[&TEST_DROP; 1];
-   |               ----------    ^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |               ----------    ^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
    |               |
    |               type annotation requires that borrow lasts for `'static`
 ...
@@ -207,7 +207,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     let _val: &'static _ = &[&TEST_DROP; 1];
    |               ----------      ^^^^^^^^^    - temporary value is freed at the end of this statement
    |               |               |
-   |               |               creates a temporary which is freed while still in use
+   |               |               creates a temporary value which is freed while still in use
    |               type annotation requires that borrow lasts for `'static`
 
 error: aborting due to 20 previous errors
index c47d297c9040938b05f1264154de9836fc3f0d93..975a235a6495b6f3a587bd2306e3086c5f7fb901 100644 (file)
@@ -19,7 +19,7 @@ LL |       let x: &'static u32 = &{
 LL | |         let y = 42;
 LL | |         y
 LL | |     };
-   | |_____^ creates a temporary which is freed while still in use
+   | |_____^ creates a temporary value which is freed while still in use
 LL |   }
    |   - temporary value is freed at the end of this statement
 
index 184ba0ea3b3777788a433315a7b8bbdc4fba297a..4802834173fc54ee4482d877257875dede3dabc6 100644 (file)
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promoted-const-drop.rs:13:26
    |
 LL |     let _: &'static A = &A();
-   |            ----------    ^^^ creates a temporary which is freed while still in use
+   |            ----------    ^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 LL |     let _: &'static [A] = &[C];
@@ -13,7 +13,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/promoted-const-drop.rs:14:28
    |
 LL |     let _: &'static [A] = &[C];
-   |            ------------    ^^^ creates a temporary which is freed while still in use
+   |            ------------    ^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 LL | }
index 8ec68ada048a5377a7b0a28dde0ec2bc6bdea147..d847cf88f505fe393ed228aa99b748134a859814 100644 (file)
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/qualif-union.rs:28:26
    |
 LL |     let _: &'static _ = &C1;
-   |            ----------    ^^ creates a temporary which is freed while still in use
+   |            ----------    ^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -13,7 +13,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/qualif-union.rs:29:26
    |
 LL |     let _: &'static _ = &C2;
-   |            ----------    ^^ creates a temporary which is freed while still in use
+   |            ----------    ^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -24,7 +24,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/qualif-union.rs:30:26
    |
 LL |     let _: &'static _ = &C3;
-   |            ----------    ^^ creates a temporary which is freed while still in use
+   |            ----------    ^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 ...
@@ -35,7 +35,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/qualif-union.rs:31:26
    |
 LL |     let _: &'static _ = &C4;
-   |            ----------    ^^ creates a temporary which is freed while still in use
+   |            ----------    ^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 LL |     let _: &'static _ = &C5;
@@ -46,7 +46,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/qualif-union.rs:32:26
    |
 LL |     let _: &'static _ = &C5;
-   |            ----------    ^^ creates a temporary which is freed while still in use
+   |            ----------    ^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
 LL | }
index a28914051b980c78d4852d27d7e8bf0577773a33..8641017470ba045da83ddd97226a45bc5fe53a14 100644 (file)
@@ -14,6 +14,11 @@ error[E0308]: mismatched types
    |
 LL |     if Err(err) = File::open("hello.txt") {
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `()`
+   |
+help: consider adding `let`
+   |
+LL |     if let Err(err) = File::open("hello.txt") {
+   |        +++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/dropck/issue-54943-1.rs b/src/test/ui/dropck/issue-54943-1.rs
new file mode 100644 (file)
index 0000000..ec682d9
--- /dev/null
@@ -0,0 +1,13 @@
+// This test is a minimal version of an ICE in the dropck-eyepatch tests
+// found in the fix for #54943.
+
+// check-pass
+
+fn foo<T>(_t: T) {
+}
+
+fn main() {
+    struct A<'a, B: 'a>(&'a B);
+    let (a1, a2): (String, A<_>) = (String::from("auto"), A(&"this"));
+    foo((a1, a2));
+}
diff --git a/src/test/ui/dropck/issue-54943-2.rs b/src/test/ui/dropck/issue-54943-2.rs
new file mode 100644 (file)
index 0000000..d400ae5
--- /dev/null
@@ -0,0 +1,16 @@
+// This test is a minimal version of an ICE in the dropck-eyepatch tests
+// found in the fix for #54943. In particular, this test is in unreachable
+// code as the initial fix for this ICE only worked if the code was reachable.
+
+// check-pass
+
+fn foo<T>(_t: T) {
+}
+
+fn main() {
+    return;
+
+    struct A<'a, B: 'a>(&'a B);
+    let (a1, a2): (String, A<_>) = (String::from("auto"), A(&"this"));
+    foo((a1, a2));
+}
diff --git a/src/test/ui/dyn-star/issue-102430.rs b/src/test/ui/dyn-star/issue-102430.rs
new file mode 100644 (file)
index 0000000..244ecda
--- /dev/null
@@ -0,0 +1,32 @@
+// check-pass
+
+#![feature(dyn_star)]
+#![allow(incomplete_features)]
+
+trait AddOne {
+    fn add1(&mut self) -> usize;
+}
+
+impl AddOne for usize {
+    fn add1(&mut self) -> usize {
+        *self += 1;
+        *self
+    }
+}
+
+impl AddOne for &mut usize {
+    fn add1(&mut self) -> usize {
+        (*self).add1()
+    }
+}
+
+fn add_one(mut i: dyn* AddOne + '_) -> usize {
+    i.add1()
+}
+
+fn main() {
+    let mut x = 42usize;
+    let y = &mut x as (dyn* AddOne + '_);
+
+    println!("{}", add_one(y));
+}
diff --git a/src/test/ui/enum-discriminant/get_discr.rs b/src/test/ui/enum-discriminant/get_discr.rs
new file mode 100644 (file)
index 0000000..71eea4e
--- /dev/null
@@ -0,0 +1,114 @@
+// run-pass
+
+// Now that there are several variations on the code generated in
+// `codegen_get_discr`, let's make sure the various cases yield the correct
+// result.
+
+// To get the discriminant of an E<X1> value, there are no shortcuts - we must
+// do the full algorithm.
+#[repr(u8)]
+pub enum X1 {
+    _1 = 1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16,
+    _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32,
+    _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48,
+    _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64,
+    _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80,
+    _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96,
+    _97, _98, _99, _100, _101, _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112,
+    _113, _114, _115, _116, _117, _118, _119, _120, _121, _122, _123, _124, _125, _126, _127, _128,
+    _129, _130, _131, _132, _133, _134, _135, _136, _137, _138, _139, _140, _141, _142, _143, _144,
+    _145, _146, _147, _148, _149, _150, _151, _152, _153, _154, _155, _156, _157, _158, _159, _160,
+    _161, _162, _163, _164, _165, _166, _167, _168, _169, _170, _171, _172, _173, _174, _175, _176,
+    _177, _178, _179, _180, _181, _182, _183, _184, _185, _186, _187, _188, _189, _190, _191, _192,
+    _193, _194, _195, _196, _197, _198, _199, _200, _201, _202, _203, _204, _205, _206, _207, _208,
+    _209, _210, _211, _212, _213, _214, _215, _216, _217, _218, _219, _220, _221, _222, _223, _224,
+    _225, _226, _227, _228, _229, _230, _231, _232, _233, _234, _235, _236, _237, _238, _239, _240,
+    _241, _242, _243, _244, _245, _246, _247, _248, _249, _250, _251, _252, _253, _254,
+}
+
+#[repr(i8)]
+pub enum X2 {
+    _1 = -1, _2 = 0, _3 = 1,
+}
+
+#[repr(i8)]
+pub enum X3 {
+    _1 = -128, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16,
+    _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32,
+    _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48,
+    _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64,
+    _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80,
+    _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96,
+    _97, _98, _99, _100, _101, _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112,
+    _113, _114, _115, _116, _117, _118, _119, _120, _121, _122, _123, _124, _125, _126, _127, _128,
+    _129, _130, _131, _132, _133, _134, _135, _136, _137, _138, _139, _140, _141, _142, _143, _144,
+    _145, _146, _147, _148, _149, _150, _151, _152, _153, _154, _155, _156, _157, _158, _159, _160,
+    _161, _162, _163, _164, _165, _166, _167, _168, _169, _170, _171, _172, _173, _174, _175, _176,
+    _177, _178, _179, _180, _181, _182, _183, _184, _185, _186, _187, _188, _189, _190, _191, _192,
+    _193, _194, _195, _196, _197, _198, _199, _200, _201, _202, _203, _204, _205, _206, _207, _208,
+    _209, _210, _211, _212, _213, _214, _215, _216, _217, _218, _219, _220, _221, _222, _223, _224,
+    _225, _226, _227, _228, _229, _230, _231, _232, _233, _234, _235, _236, _237, _238, _239, _240,
+    _241, _242, _243, _244, _245, _246, _247, _248, _249, _250, _251, _252, _253, _254,
+}
+
+#[repr(i8)]
+pub enum X4 {
+    _1 = -126, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16,
+    _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32,
+    _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48,
+    _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64,
+    _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80,
+    _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96,
+    _97, _98, _99, _100, _101, _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112,
+    _113, _114, _115, _116, _117, _118, _119, _120, _121, _122, _123, _124, _125, _126, _127, _128,
+    _129, _130, _131, _132, _133, _134, _135, _136, _137, _138, _139, _140, _141, _142, _143, _144,
+    _145, _146, _147, _148, _149, _150, _151, _152, _153, _154, _155, _156, _157, _158, _159, _160,
+    _161, _162, _163, _164, _165, _166, _167, _168, _169, _170, _171, _172, _173, _174, _175, _176,
+    _177, _178, _179, _180, _181, _182, _183, _184, _185, _186, _187, _188, _189, _190, _191, _192,
+    _193, _194, _195, _196, _197, _198, _199, _200, _201, _202, _203, _204, _205, _206, _207, _208,
+    _209, _210, _211, _212, _213, _214, _215, _216, _217, _218, _219, _220, _221, _222, _223, _224,
+    _225, _226, _227, _228, _229, _230, _231, _232, _233, _234, _235, _236, _237, _238, _239, _240,
+    _241, _242, _243, _244, _245, _246, _247, _248, _249, _250, _251, _252, _253, _254,
+}
+
+pub enum E<X> {
+    A(X),
+    B,
+    C,
+}
+
+pub fn match_e<X>(e: E<X>) -> u8 {
+    use E::*;
+    match e {
+        A(_) => 0,
+        B => 1,
+        C => 2,
+    }
+}
+
+fn main() {
+    assert_eq!(match_e(E::A(X1::_1)), 0);
+    assert_eq!(match_e(E::A(X1::_2)), 0);
+    assert_eq!(match_e(E::A(X1::_254)), 0);
+    assert_eq!(match_e(E::<X1>::B), 1);
+    assert_eq!(match_e(E::<X1>::C), 2);
+    assert_eq!(match_e(E::A(X2::_1)), 0);
+    assert_eq!(match_e(E::A(X2::_2)), 0);
+    assert_eq!(match_e(E::A(X2::_3)), 0);
+    assert_eq!(match_e(E::<X2>::B), 1);
+    assert_eq!(match_e(E::<X2>::C), 2);
+    assert_eq!(match_e(E::A(X3::_1)), 0);
+    assert_eq!(match_e(E::A(X3::_2)), 0);
+    assert_eq!(match_e(E::A(X3::_254)), 0);
+    assert_eq!(match_e(E::<X3>::B), 1);
+    assert_eq!(match_e(E::<X3>::C), 2);
+    assert_eq!(match_e(E::A(X4::_1)), 0);
+    assert_eq!(match_e(E::A(X4::_2)), 0);
+    assert_eq!(match_e(E::A(X4::_254)), 0);
+    assert_eq!(match_e(E::<X4>::B), 1);
+    assert_eq!(match_e(E::<X4>::C), 2);
+    assert_eq!(match_e(E::A(false)), 0);
+    assert_eq!(match_e(E::A(true)), 0);
+    assert_eq!(match_e(E::<bool>::B), 1);
+    assert_eq!(match_e(E::<bool>::C), 2);
+}
diff --git a/src/test/ui/enum-discriminant/issue-46519.rs b/src/test/ui/enum-discriminant/issue-46519.rs
new file mode 100644 (file)
index 0000000..0567923
--- /dev/null
@@ -0,0 +1,30 @@
+// run-pass
+// compile-flags:--test -O
+
+// needs-unwind
+
+#[test]
+#[should_panic(expected = "creating inhabited type")]
+fn test() {
+    FontLanguageOverride::system_font(SystemFont::new());
+}
+
+pub enum FontLanguageOverride {
+    Normal,
+    Override(&'static str),
+    System(SystemFont)
+}
+
+pub enum SystemFont {}
+
+impl FontLanguageOverride {
+    fn system_font(f: SystemFont) -> Self {
+        FontLanguageOverride::System(f)
+    }
+}
+
+impl SystemFont {
+    fn new() -> Self {
+        panic!("creating inhabited type")
+    }
+}
index 9bd16abb7bb83ab17f4f334c99efcccb8a2a43cd..f1f93b3aed61508d603cad311ebb80ed1d05a80a 100644 (file)
@@ -1,3 +1,4 @@
 fn main() {
-    let x = "hello".chars().rev().collect(); //~ ERROR E0282
+    let x = "hello".chars().rev().collect();
+    //~^ ERROR E0282
 }
index c30e5f47188715df6f6d9d083e4f552ce5095205..8f8d6b87ef209e016d41479d6c6e5553c32aeb76 100644 (file)
@@ -8,7 +8,9 @@ fn baz<U,
            W: Fn()>
            (y: T) { //~ ERROR E0401
     }
-    bfnr(x); //~ ERROR type annotations needed
+    bfnr(x);
+    //~^ ERROR type annotations needed
+    //~| ERROR type annotations needed
 }
 
 
index b0e2ef5b6f7e3d65c101e62994552805c9775500..9687eca61fab0b5d16a1968fda5f18defde0bfd9 100644 (file)
@@ -21,7 +21,7 @@ LL |            (y: T) {
    |                ^ use of generic parameter from outer function
 
 error[E0401]: can't use generic parameters from outer function
-  --> $DIR/E0401.rs:22:25
+  --> $DIR/E0401.rs:24:25
    |
 LL | impl<T> Iterator for A<T> {
    | ---- `Self` type implicitly declared here, by this `impl`
@@ -43,7 +43,28 @@ help: consider specifying the generic arguments
 LL |     bfnr::<U, V, W>(x);
    |         +++++++++++
 
-error: aborting due to 4 previous errors
+error[E0283]: type annotations needed
+  --> $DIR/E0401.rs:11:5
+   |
+LL |     bfnr(x);
+   |     ^^^^ cannot infer type of the type parameter `W` declared on the function `bfnr`
+   |
+   = note: multiple `impl`s satisfying `_: Fn<()>` found in the following crates: `alloc`, `core`:
+           - impl<A, F> Fn<A> for &F
+             where A: Tuple, F: Fn<A>, F: ?Sized;
+           - impl<Args, F, A> Fn<Args> for Box<F, A>
+             where Args: Tuple, F: Fn<Args>, A: Allocator, F: ?Sized;
+note: required by a bound in `bfnr`
+  --> $DIR/E0401.rs:4:30
+   |
+LL |     fn bfnr<U, V: Baz<U>, W: Fn()>(y: T) {
+   |                              ^^^^ required by this bound in `bfnr`
+help: consider specifying the type arguments in the function call
+   |
+LL |     bfnr::<U, V, W>(x);
+   |         +++++++++++
+
+error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0282, E0401.
+Some errors have detailed explanations: E0282, E0283, E0401.
 For more information about an error, try `rustc --explain E0282`.
diff --git a/src/test/ui/feature-gates/feature-gate-abi-efiapi.rs b/src/test/ui/feature-gates/feature-gate-abi-efiapi.rs
new file mode 100644 (file)
index 0000000..0c0d736
--- /dev/null
@@ -0,0 +1,33 @@
+// needs-llvm-components: x86
+// compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=rlib
+#![no_core]
+#![feature(no_core, lang_items)]
+#[lang="sized"]
+trait Sized { }
+
+// Functions
+extern "efiapi" fn f1() {} //~ ERROR efiapi ABI is experimental
+
+// Methods in trait defintion
+trait Tr {
+    extern "efiapi" fn f2(); //~ ERROR efiapi ABI is experimental
+    extern "efiapi" fn f3() {} //~ ERROR efiapi ABI is experimental
+}
+
+struct S;
+
+// Methods in trait impl
+impl Tr for S {
+    extern "efiapi" fn f2() {} //~ ERROR efiapi ABI is experimental
+}
+
+// Methods in inherent impl
+impl S {
+    extern "efiapi" fn f4() {} //~ ERROR efiapi ABI is experimental
+}
+
+// Function pointer types
+type A = extern "efiapi" fn(); //~ ERROR efiapi ABI is experimental
+
+// Foreign modules
+extern "efiapi" {} //~ ERROR efiapi ABI is experimental
diff --git a/src/test/ui/feature-gates/feature-gate-abi-efiapi.stderr b/src/test/ui/feature-gates/feature-gate-abi-efiapi.stderr
new file mode 100644 (file)
index 0000000..5b01dcc
--- /dev/null
@@ -0,0 +1,66 @@
+error[E0658]: efiapi ABI is experimental and subject to change
+  --> $DIR/feature-gate-abi-efiapi.rs:9:8
+   |
+LL | extern "efiapi" fn f1() {}
+   |        ^^^^^^^^
+   |
+   = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
+   = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
+
+error[E0658]: efiapi ABI is experimental and subject to change
+  --> $DIR/feature-gate-abi-efiapi.rs:13:12
+   |
+LL |     extern "efiapi" fn f2();
+   |            ^^^^^^^^
+   |
+   = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
+   = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
+
+error[E0658]: efiapi ABI is experimental and subject to change
+  --> $DIR/feature-gate-abi-efiapi.rs:14:12
+   |
+LL |     extern "efiapi" fn f3() {}
+   |            ^^^^^^^^
+   |
+   = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
+   = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
+
+error[E0658]: efiapi ABI is experimental and subject to change
+  --> $DIR/feature-gate-abi-efiapi.rs:21:12
+   |
+LL |     extern "efiapi" fn f2() {}
+   |            ^^^^^^^^
+   |
+   = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
+   = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
+
+error[E0658]: efiapi ABI is experimental and subject to change
+  --> $DIR/feature-gate-abi-efiapi.rs:26:12
+   |
+LL |     extern "efiapi" fn f4() {}
+   |            ^^^^^^^^
+   |
+   = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
+   = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
+
+error[E0658]: efiapi ABI is experimental and subject to change
+  --> $DIR/feature-gate-abi-efiapi.rs:30:17
+   |
+LL | type A = extern "efiapi" fn();
+   |                 ^^^^^^^^
+   |
+   = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
+   = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
+
+error[E0658]: efiapi ABI is experimental and subject to change
+  --> $DIR/feature-gate-abi-efiapi.rs:33:8
+   |
+LL | extern "efiapi" {}
+   |        ^^^^^^^^
+   |
+   = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
+   = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
index 15b674c62e44de41f9c542be888de940be6fe75a..712655f9775d6f4a41e30d3082d16d3641063d42 100644 (file)
@@ -1,6 +1,5 @@
 // gate-test-intrinsics
 // gate-test-platform_intrinsics
-// gate-test-abi_efiapi
 // compile-flags: --crate-type=rlib
 
 #![feature(no_core, lang_items)]
@@ -18,7 +17,6 @@ extern "rust-intrinsic" fn f1() {} //~ ERROR intrinsics are subject to change
 extern "platform-intrinsic" fn f2() {} //~ ERROR platform intrinsics are experimental
                                        //~^ ERROR intrinsic must be in
 extern "rust-call" fn f4(_: ()) {} //~ ERROR rust-call ABI is subject to change
-extern "efiapi" fn f10() {} //~ ERROR efiapi ABI is experimental and subject to change
 
 // Methods in trait definition
 trait Tr {
@@ -27,10 +25,8 @@ trait Tr {
     extern "platform-intrinsic" fn m2(); //~ ERROR platform intrinsics are experimental
                                          //~^ ERROR intrinsic must be in
     extern "rust-call" fn m4(_: ()); //~ ERROR rust-call ABI is subject to change
-    extern "efiapi" fn m10(); //~ ERROR efiapi ABI is experimental and subject to change
 
     extern "rust-call" fn dm4(_: ()) {} //~ ERROR rust-call ABI is subject to change
-    extern "efiapi" fn dm10() {} //~ ERROR efiapi ABI is experimental and subject to change
 }
 
 struct S;
@@ -42,7 +38,6 @@ extern "rust-intrinsic" fn m1() {} //~ ERROR intrinsics are subject to change
     extern "platform-intrinsic" fn m2() {} //~ ERROR platform intrinsics are experimental
                                            //~^ ERROR intrinsic must be in
     extern "rust-call" fn m4(_: ()) {} //~ ERROR rust-call ABI is subject to change
-    extern "efiapi" fn m10() {} //~ ERROR efiapi ABI is experimental and subject to change
 }
 
 // Methods in inherent impl
@@ -52,17 +47,14 @@ extern "rust-intrinsic" fn im1() {} //~ ERROR intrinsics are subject to change
     extern "platform-intrinsic" fn im2() {} //~ ERROR platform intrinsics are experimental
                                             //~^ ERROR intrinsic must be in
     extern "rust-call" fn im4(_: ()) {} //~ ERROR rust-call ABI is subject to change
-    extern "efiapi" fn im10() {} //~ ERROR efiapi ABI is experimental and subject to change
 }
 
 // Function pointer types
 type A1 = extern "rust-intrinsic" fn(); //~ ERROR intrinsics are subject to change
 type A2 = extern "platform-intrinsic" fn(); //~ ERROR platform intrinsics are experimental
 type A4 = extern "rust-call" fn(_: ()); //~ ERROR rust-call ABI is subject to change
-type A10 = extern "efiapi" fn(); //~ ERROR efiapi ABI is experimental and subject to change
 
 // Foreign modules
 extern "rust-intrinsic" {} //~ ERROR intrinsics are subject to change
 extern "platform-intrinsic" {} //~ ERROR platform intrinsics are experimental
 extern "rust-call" {} //~ ERROR rust-call ABI is subject to change
-extern "efiapi" {} //~ ERROR efiapi ABI is experimental and subject to change
index 33ec250f09067353345c89ebf7b917bece05588b..e9791b9513f4d29e892164e55d2cfeed34e79981 100644 (file)
@@ -1,5 +1,5 @@
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:16:8
+  --> $DIR/feature-gate-abi.rs:15:8
    |
 LL | extern "rust-intrinsic" fn f1() {}
    |        ^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL | extern "rust-intrinsic" fn f1() {}
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:18:8
+  --> $DIR/feature-gate-abi.rs:17:8
    |
 LL | extern "platform-intrinsic" fn f2() {}
    |        ^^^^^^^^^^^^^^^^^^^^
@@ -16,7 +16,7 @@ LL | extern "platform-intrinsic" fn f2() {}
    = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:20:8
+  --> $DIR/feature-gate-abi.rs:19:8
    |
 LL | extern "rust-call" fn f4(_: ()) {}
    |        ^^^^^^^^^^^
@@ -24,17 +24,8 @@ LL | extern "rust-call" fn f4(_: ()) {}
    = note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
-error[E0658]: efiapi ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:21:8
-   |
-LL | extern "efiapi" fn f10() {}
-   |        ^^^^^^^^
-   |
-   = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
-   = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
-
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:25:12
+  --> $DIR/feature-gate-abi.rs:23:12
    |
 LL |     extern "rust-intrinsic" fn m1();
    |            ^^^^^^^^^^^^^^^^
@@ -42,7 +33,7 @@ LL |     extern "rust-intrinsic" fn m1();
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:27:12
+  --> $DIR/feature-gate-abi.rs:25:12
    |
 LL |     extern "platform-intrinsic" fn m2();
    |            ^^^^^^^^^^^^^^^^^^^^
@@ -51,7 +42,7 @@ LL |     extern "platform-intrinsic" fn m2();
    = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:29:12
+  --> $DIR/feature-gate-abi.rs:27:12
    |
 LL |     extern "rust-call" fn m4(_: ());
    |            ^^^^^^^^^^^
@@ -59,17 +50,8 @@ LL |     extern "rust-call" fn m4(_: ());
    = note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
-error[E0658]: efiapi ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:30:12
-   |
-LL |     extern "efiapi" fn m10();
-   |            ^^^^^^^^
-   |
-   = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
-   = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
-
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:32:12
+  --> $DIR/feature-gate-abi.rs:29:12
    |
 LL |     extern "rust-call" fn dm4(_: ()) {}
    |            ^^^^^^^^^^^
@@ -77,17 +59,8 @@ LL |     extern "rust-call" fn dm4(_: ()) {}
    = note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
-error[E0658]: efiapi ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:33:12
-   |
-LL |     extern "efiapi" fn dm10() {}
-   |            ^^^^^^^^
-   |
-   = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
-   = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
-
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:40:12
+  --> $DIR/feature-gate-abi.rs:36:12
    |
 LL |     extern "rust-intrinsic" fn m1() {}
    |            ^^^^^^^^^^^^^^^^
@@ -95,7 +68,7 @@ LL |     extern "rust-intrinsic" fn m1() {}
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:42:12
+  --> $DIR/feature-gate-abi.rs:38:12
    |
 LL |     extern "platform-intrinsic" fn m2() {}
    |            ^^^^^^^^^^^^^^^^^^^^
@@ -104,7 +77,7 @@ LL |     extern "platform-intrinsic" fn m2() {}
    = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:44:12
+  --> $DIR/feature-gate-abi.rs:40:12
    |
 LL |     extern "rust-call" fn m4(_: ()) {}
    |            ^^^^^^^^^^^
@@ -112,17 +85,8 @@ LL |     extern "rust-call" fn m4(_: ()) {}
    = note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
-error[E0658]: efiapi ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:45:12
-   |
-LL |     extern "efiapi" fn m10() {}
-   |            ^^^^^^^^
-   |
-   = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
-   = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
-
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:50:12
+  --> $DIR/feature-gate-abi.rs:45:12
    |
 LL |     extern "rust-intrinsic" fn im1() {}
    |            ^^^^^^^^^^^^^^^^
@@ -130,7 +94,7 @@ LL |     extern "rust-intrinsic" fn im1() {}
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:52:12
+  --> $DIR/feature-gate-abi.rs:47:12
    |
 LL |     extern "platform-intrinsic" fn im2() {}
    |            ^^^^^^^^^^^^^^^^^^^^
@@ -139,7 +103,7 @@ LL |     extern "platform-intrinsic" fn im2() {}
    = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:54:12
+  --> $DIR/feature-gate-abi.rs:49:12
    |
 LL |     extern "rust-call" fn im4(_: ()) {}
    |            ^^^^^^^^^^^
@@ -147,17 +111,8 @@ LL |     extern "rust-call" fn im4(_: ()) {}
    = note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
-error[E0658]: efiapi ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:55:12
-   |
-LL |     extern "efiapi" fn im10() {}
-   |            ^^^^^^^^
-   |
-   = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
-   = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
-
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:59:18
+  --> $DIR/feature-gate-abi.rs:53:18
    |
 LL | type A1 = extern "rust-intrinsic" fn();
    |                  ^^^^^^^^^^^^^^^^
@@ -165,7 +120,7 @@ LL | type A1 = extern "rust-intrinsic" fn();
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:60:18
+  --> $DIR/feature-gate-abi.rs:54:18
    |
 LL | type A2 = extern "platform-intrinsic" fn();
    |                  ^^^^^^^^^^^^^^^^^^^^
@@ -174,7 +129,7 @@ LL | type A2 = extern "platform-intrinsic" fn();
    = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:61:18
+  --> $DIR/feature-gate-abi.rs:55:18
    |
 LL | type A4 = extern "rust-call" fn(_: ());
    |                  ^^^^^^^^^^^
@@ -182,17 +137,8 @@ LL | type A4 = extern "rust-call" fn(_: ());
    = note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
-error[E0658]: efiapi ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:62:19
-   |
-LL | type A10 = extern "efiapi" fn();
-   |                   ^^^^^^^^
-   |
-   = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
-   = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
-
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:65:8
+  --> $DIR/feature-gate-abi.rs:58:8
    |
 LL | extern "rust-intrinsic" {}
    |        ^^^^^^^^^^^^^^^^
@@ -200,7 +146,7 @@ LL | extern "rust-intrinsic" {}
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:66:8
+  --> $DIR/feature-gate-abi.rs:59:8
    |
 LL | extern "platform-intrinsic" {}
    |        ^^^^^^^^^^^^^^^^^^^^
@@ -209,7 +155,7 @@ LL | extern "platform-intrinsic" {}
    = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:67:8
+  --> $DIR/feature-gate-abi.rs:60:8
    |
 LL | extern "rust-call" {}
    |        ^^^^^^^^^^^
@@ -217,63 +163,54 @@ LL | extern "rust-call" {}
    = note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
-error[E0658]: efiapi ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:68:8
-   |
-LL | extern "efiapi" {}
-   |        ^^^^^^^^
-   |
-   = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
-   = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
-
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:25:32
+  --> $DIR/feature-gate-abi.rs:23:32
    |
 LL |     extern "rust-intrinsic" fn m1();
    |                                ^^
 
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:27:36
+  --> $DIR/feature-gate-abi.rs:25:36
    |
 LL |     extern "platform-intrinsic" fn m2();
    |                                    ^^
 
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:16:33
+  --> $DIR/feature-gate-abi.rs:15:33
    |
 LL | extern "rust-intrinsic" fn f1() {}
    |                                 ^^
 
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:18:37
+  --> $DIR/feature-gate-abi.rs:17:37
    |
 LL | extern "platform-intrinsic" fn f2() {}
    |                                     ^^
 
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:40:37
+  --> $DIR/feature-gate-abi.rs:36:37
    |
 LL |     extern "rust-intrinsic" fn m1() {}
    |                                     ^^
 
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:42:41
+  --> $DIR/feature-gate-abi.rs:38:41
    |
 LL |     extern "platform-intrinsic" fn m2() {}
    |                                         ^^
 
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:50:38
+  --> $DIR/feature-gate-abi.rs:45:38
    |
 LL |     extern "rust-intrinsic" fn im1() {}
    |                                      ^^
 
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:52:42
+  --> $DIR/feature-gate-abi.rs:47:42
    |
 LL |     extern "platform-intrinsic" fn im2() {}
    |                                          ^^
 
-error: aborting due to 34 previous errors
+error: aborting due to 27 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-custom_mir.rs b/src/test/ui/feature-gates/feature-gate-custom_mir.rs
new file mode 100644 (file)
index 0000000..0126dde
--- /dev/null
@@ -0,0 +1,12 @@
+#![feature(core_intrinsics)]
+
+extern crate core;
+
+#[custom_mir(dialect = "built")] //~ ERROR the `#[custom_mir]` attribute is just used for the Rust test suite
+pub fn foo(_x: i32) -> i32 {
+    0
+}
+
+fn main() {
+    assert_eq!(2, foo(2));
+}
diff --git a/src/test/ui/feature-gates/feature-gate-custom_mir.stderr b/src/test/ui/feature-gates/feature-gate-custom_mir.stderr
new file mode 100644 (file)
index 0000000..3c149d3
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0658]: the `#[custom_mir]` attribute is just used for the Rust test suite
+  --> $DIR/feature-gate-custom_mir.rs:5:1
+   |
+LL | #[custom_mir(dialect = "built")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(custom_mir)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
index 5a645cf4ef98782af41dd7d123569fd61c07a117..7876704042188d065caab0e78b41f97c30366d29 100644 (file)
@@ -110,19 +110,19 @@ error: attribute should be applied to an `extern crate` item
   --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:25:1
    |
 LL | #![no_link]
-   | ^^^^^^^^^^^
+   | ^^^^^^^^^^^ not an `extern crate` item
 
 error: attribute should be applied to a free function, impl method or static
   --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:27:1
    |
 LL | #![export_name = "2200"]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^ not a free function, impl method or static
 
 error[E0518]: attribute should be applied to function or closure
   --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:29:1
    |
 LL | #![inline]
-   | ^^^^^^^^^^
+   | ^^^^^^^^^^ not a function or closure
 
 error: `macro_export` attribute cannot be used at crate level
   --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:12:1
index 8db12e55d25c27d88f7b17a149f8f77f5021da99..1fa315f3d215987d28050aad84ba0c94eb9497d4 100644 (file)
@@ -1,6 +1,6 @@
 //~ NOTE not a function
 //~| NOTE not a foreign function or static
-//~| NOTE not a function or static
+//~| NOTE cannot be applied to crates
 //~| NOTE not an `extern` block
 // This test enumerates as many compiler-builtin ungated attributes as
 // possible (that is, all the mutually compatible ones), and checks
index 310d1f720eb7cb6800ed21c32312e80700d1ba9d..30039267979fb6db14c533f4306f9ca40ec9787f 100644 (file)
@@ -403,7 +403,7 @@ warning: attribute should be applied to a function definition
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:62:1
    |
 LL | #![cold]
-   | ^^^^^^^^
+   | ^^^^^^^^ cannot be applied to crates
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
@@ -411,7 +411,7 @@ warning: attribute should be applied to an `extern` block with non-Rust ABI
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:64:1
    |
 LL | #![link()]
-   | ^^^^^^^^^^
+   | ^^^^^^^^^^ not an `extern` block
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
@@ -419,7 +419,7 @@ warning: attribute should be applied to a foreign function or static
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:66:1
    |
 LL | #![link_name = "1900"]
-   | ^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^ not a foreign function or static
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
@@ -427,7 +427,7 @@ warning: attribute should be applied to a function or static
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:69:1
    |
 LL | #![link_section = "1800"]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^ not a function or static
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
diff --git a/src/test/ui/fmt/unicode-escape-spans.rs b/src/test/ui/fmt/unicode-escape-spans.rs
new file mode 100644 (file)
index 0000000..753d91c
--- /dev/null
@@ -0,0 +1,19 @@
+fn main() {
+    // 1 byte in UTF-8
+    format!("\u{000041}{a}"); //~ ERROR cannot find value
+    format!("\u{0041}{a}"); //~ ERROR cannot find value
+    format!("\u{41}{a}"); //~ ERROR cannot find value
+    format!("\u{0}{a}"); //~ ERROR cannot find value
+
+    // 2 bytes
+    format!("\u{0df}{a}"); //~ ERROR cannot find value
+    format!("\u{df}{a}"); //~ ERROR cannot find value
+
+    // 3 bytes
+    format!("\u{00211d}{a}"); //~ ERROR cannot find value
+    format!("\u{211d}{a}"); //~ ERROR cannot find value
+
+    // 4 bytes
+    format!("\u{1f4a3}{a}"); //~ ERROR cannot find value
+    format!("\u{10ffff}{a}"); //~ ERROR cannot find value
+}
diff --git a/src/test/ui/fmt/unicode-escape-spans.stderr b/src/test/ui/fmt/unicode-escape-spans.stderr
new file mode 100644 (file)
index 0000000..1d8473f
--- /dev/null
@@ -0,0 +1,63 @@
+error[E0425]: cannot find value `a` in this scope
+  --> $DIR/unicode-escape-spans.rs:3:25
+   |
+LL |     format!("\u{000041}{a}");
+   |                         ^ not found in this scope
+
+error[E0425]: cannot find value `a` in this scope
+  --> $DIR/unicode-escape-spans.rs:4:23
+   |
+LL |     format!("\u{0041}{a}");
+   |                       ^ not found in this scope
+
+error[E0425]: cannot find value `a` in this scope
+  --> $DIR/unicode-escape-spans.rs:5:21
+   |
+LL |     format!("\u{41}{a}");
+   |                     ^ not found in this scope
+
+error[E0425]: cannot find value `a` in this scope
+  --> $DIR/unicode-escape-spans.rs:6:20
+   |
+LL |     format!("\u{0}{a}");
+   |                    ^ not found in this scope
+
+error[E0425]: cannot find value `a` in this scope
+  --> $DIR/unicode-escape-spans.rs:9:22
+   |
+LL |     format!("\u{0df}{a}");
+   |                      ^ not found in this scope
+
+error[E0425]: cannot find value `a` in this scope
+  --> $DIR/unicode-escape-spans.rs:10:21
+   |
+LL |     format!("\u{df}{a}");
+   |                     ^ not found in this scope
+
+error[E0425]: cannot find value `a` in this scope
+  --> $DIR/unicode-escape-spans.rs:13:25
+   |
+LL |     format!("\u{00211d}{a}");
+   |                         ^ not found in this scope
+
+error[E0425]: cannot find value `a` in this scope
+  --> $DIR/unicode-escape-spans.rs:14:23
+   |
+LL |     format!("\u{211d}{a}");
+   |                       ^ not found in this scope
+
+error[E0425]: cannot find value `a` in this scope
+  --> $DIR/unicode-escape-spans.rs:17:24
+   |
+LL |     format!("\u{1f4a3}{a}");
+   |                        ^ not found in this scope
+
+error[E0425]: cannot find value `a` in this scope
+  --> $DIR/unicode-escape-spans.rs:18:25
+   |
+LL |     format!("\u{10ffff}{a}");
+   |                         ^ not found in this scope
+
+error: aborting due to 10 previous errors
+
+For more information about this error, try `rustc --explain E0425`.
index 23324af6171a9e5810224ee6a20d97741eaa472f..0b1f34aeb96bd52172833446ece6a7cc0c11c3b3 100644 (file)
@@ -4,7 +4,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |         let a = A(&mut true, &mut true, No);
    |                        ^^^^                - temporary value is freed at the end of this statement
    |                        |
-   |                        creates a temporary which is freed while still in use
+   |                        creates a temporary value which is freed while still in use
 ...
 LL |         assert_foo(a);
    |                    - borrow later used here
@@ -17,7 +17,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |         let a = A(&mut true, &mut true, No);
    |                                   ^^^^     - temporary value is freed at the end of this statement
    |                                   |
-   |                                   creates a temporary which is freed while still in use
+   |                                   creates a temporary value which is freed while still in use
 ...
 LL |         assert_foo(a);
    |                    - borrow later used here
index 30a6732f75956d40042bbc34125fb9cbfb3060a3..539343275df6021c64923f51493b339a2ed05135 100644 (file)
@@ -4,7 +4,7 @@ warning: unused generator that must be used
 LL | /     move || {
 LL | |         A.test(yield);
 LL | |     };
-   | |______^
+   | |_____^
    |
    = note: generators are lazy and do nothing unless resumed
    = note: `#[warn(unused_must_use)]` on by default
@@ -16,7 +16,7 @@ LL | /     static move || {
 LL | |         yield *y.borrow();
 LL | |         return "Done";
 LL | |     };
-   | |______^
+   | |_____^
    |
    = note: generators are lazy and do nothing unless resumed
 
index 29aca94408a82174811f7edbbf976cc8ae58d9c0..8f1fc5e803194d15774a89812e6e1f0582b2dace 100644 (file)
@@ -7,7 +7,7 @@ LL | |         loop {
 LL | |             yield
 LL | |         }
 LL | |     };
-   | |______^
+   | |_____^
    |
    = note: generators are lazy and do nothing unless resumed
    = note: `#[warn(unused_must_use)]` on by default
index b911b6661909a1fcb042a5bf467562130a42a3d3..3dd2d595445aa39fd7a4a5854acda265af6b3f9d 100644 (file)
@@ -8,7 +8,7 @@ LL | |                 match Enum::A(String::new()) {
 ...  |
 LL | |         }
 LL | |     };
-   | |______^
+   | |_____^
    |
    = note: generators are lazy and do nothing unless resumed
    = note: `#[warn(unused_must_use)]` on by default
index e83dbf833bfa747de2eead4c79022333b5f07411..2e1fec35eaf52a29e798bda28b70c8697d2809cd 100644 (file)
@@ -8,7 +8,7 @@ LL | |             yield;
 ...  |
 LL | |         *bar = 2;
 LL | |     };
-   | |______^
+   | |_____^
    |
    = note: generators are lazy and do nothing unless resumed
    = note: `#[warn(unused_must_use)]` on by default
index 5cb43067fee6bf067092a349e4dcb2ab332b671f..e262f213f63d2314d8dcb79f313395614d98d940 100644 (file)
@@ -8,7 +8,7 @@ LL | |             // and it should also find out that `a` is not live.
 ...  |
 LL | |             let _ = &a;
 LL | |         };
-   | |__________^
+   | |_________^
    |
    = note: generators are lazy and do nothing unless resumed
    = note: `#[warn(unused_must_use)]` on by default
index c9e1ab722d47ff8d2931dc1dd25c4d1242492620..a87248f66210039f3b1d92257e5f672a5e1fa81b 100644 (file)
@@ -5,7 +5,7 @@ LL | /     || {
 LL | |         let b = true;
 LL | |         foo(yield, &b);
 LL | |     };
-   | |______^
+   | |_____^
    |
    = note: generators are lazy and do nothing unless resumed
    = note: `#[warn(unused_must_use)]` on by default
index 8587e1dc663bc9e4a7e85aa487fbfff02489367b..9d03ee00800c8f489b7b4ca96952df1d847a7577 100644 (file)
@@ -8,7 +8,7 @@ LL | |             let _t = box (&x, yield 0, &y);
 ...  |
 LL | |         }
 LL | |     };
-   | |______^
+   | |_____^
    |
    = note: generators are lazy and do nothing unless resumed
    = note: `#[warn(unused_must_use)]` on by default
index 07de24662cf2e4034f18b0b76da77698fe58610b..ed14a2e3273af7dde00d731f6148263a19cf9d15 100644 (file)
@@ -8,7 +8,7 @@ LL | |             // See https://github.com/rust-lang/rust/issues/52792
 ...  |
 LL | |         }
 LL | |     };
-   | |______^
+   | |_____^
    |
    = note: generators are lazy and do nothing unless resumed
    = note: `#[warn(unused_must_use)]` on by default
index fe10477bf7380b17a845a010990b29cadef6cd09..97862e91cd4a0409222621933663630df6b811bc 100644 (file)
@@ -5,7 +5,7 @@ LL | /     || {
 LL | |         yield a;
 LL | |         yield b;
 LL | |     };
-   | |______^
+   | |_____^
    |
    = note: generators are lazy and do nothing unless resumed
    = note: `#[warn(unused_must_use)]` on by default
index 414999881d4701cb5ab2a7e72b72e86ad1e7934a..1c9abc4e837c518aa888649f2b5b57b0265631fa 100644 (file)
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/hrtb-implied-1.rs:31:22
    |
 LL |     let slice = &mut ();
-   |                      ^^ creates a temporary which is freed while still in use
+   |                      ^^ creates a temporary value which is freed while still in use
 ...
 LL |     print_items::<WindowsMut<'_>>(windows);
    |     -------------------------------------- argument requires that borrow lasts for `'static`
diff --git a/src/test/ui/generic-associated-types/bugs/issue-100013.rs b/src/test/ui/generic-associated-types/bugs/issue-100013.rs
new file mode 100644 (file)
index 0000000..fc4e47a
--- /dev/null
@@ -0,0 +1,39 @@
+// check-fail
+// known-bug
+// edition: 2021
+
+// We really should accept this, but we need implied bounds between the regions
+// in a generator interior.
+
+pub trait FutureIterator {
+    type Future<'s, 'cx>: Send
+    where
+        's: 'cx;
+}
+
+fn call<I: FutureIterator>() -> impl Send {
+    async { // a generator checked for autotrait impl `Send`
+        //~^ lifetime bound not satisfied
+        let x = None::<I::Future<'_, '_>>; // a type referencing GAT
+        async {}.await; // a yield point
+    }
+}
+
+fn call2<'a, 'b, I: FutureIterator>() -> impl Send {
+    async { // a generator checked for autotrait impl `Send`
+        //~^ lifetime bound not satisfied
+        let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
+        //~^ lifetime may not live long enough
+        async {}.await; // a yield point
+    }
+}
+
+fn call3<'a: 'b, 'b, I: FutureIterator>() -> impl Send {
+    async { // a generator checked for autotrait impl `Send`
+        //~^ lifetime bound not satisfied
+        let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
+        async {}.await; // a yield point
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/bugs/issue-100013.stderr b/src/test/ui/generic-associated-types/bugs/issue-100013.stderr
new file mode 100644 (file)
index 0000000..72ae288
--- /dev/null
@@ -0,0 +1,82 @@
+error: lifetime bound not satisfied
+  --> $DIR/issue-100013.rs:15:5
+   |
+LL | /     async { // a generator checked for autotrait impl `Send`
+LL | |
+LL | |         let x = None::<I::Future<'_, '_>>; // a type referencing GAT
+LL | |         async {}.await; // a yield point
+LL | |     }
+   | |_____^
+   |
+note: the lifetime defined here...
+  --> $DIR/issue-100013.rs:17:38
+   |
+LL |         let x = None::<I::Future<'_, '_>>; // a type referencing GAT
+   |                                      ^^
+note: ...must outlive the lifetime defined here
+  --> $DIR/issue-100013.rs:17:34
+   |
+LL |         let x = None::<I::Future<'_, '_>>; // a type referencing GAT
+   |                                  ^^
+   = note: this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
+
+error: lifetime bound not satisfied
+  --> $DIR/issue-100013.rs:23:5
+   |
+LL | /     async { // a generator checked for autotrait impl `Send`
+LL | |
+LL | |         let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
+LL | |
+LL | |         async {}.await; // a yield point
+LL | |     }
+   | |_____^
+   |
+note: the lifetime defined here...
+  --> $DIR/issue-100013.rs:22:14
+   |
+LL | fn call2<'a, 'b, I: FutureIterator>() -> impl Send {
+   |              ^^
+note: ...must outlive the lifetime defined here
+  --> $DIR/issue-100013.rs:22:10
+   |
+LL | fn call2<'a, 'b, I: FutureIterator>() -> impl Send {
+   |          ^^
+   = note: this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
+
+error: lifetime may not live long enough
+  --> $DIR/issue-100013.rs:25:17
+   |
+LL | fn call2<'a, 'b, I: FutureIterator>() -> impl Send {
+   |          --  -- lifetime `'b` defined here
+   |          |
+   |          lifetime `'a` defined here
+...
+LL |         let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'b`
+   |
+   = help: consider adding the following bound: `'a: 'b`
+
+error: lifetime bound not satisfied
+  --> $DIR/issue-100013.rs:32:5
+   |
+LL | /     async { // a generator checked for autotrait impl `Send`
+LL | |
+LL | |         let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
+LL | |         async {}.await; // a yield point
+LL | |     }
+   | |_____^
+   |
+note: the lifetime defined here...
+  --> $DIR/issue-100013.rs:31:18
+   |
+LL | fn call3<'a: 'b, 'b, I: FutureIterator>() -> impl Send {
+   |                  ^^
+note: ...must outlive the lifetime defined here
+  --> $DIR/issue-100013.rs:31:10
+   |
+LL | fn call3<'a: 'b, 'b, I: FutureIterator>() -> impl Send {
+   |          ^^
+   = note: this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
+
+error: aborting due to 4 previous errors
+
index f6aa6b36e13dcfb7907f3320b04248b9fa393fda..d6e18010f3b271a42810d91a153c53695950cf7c 100644 (file)
@@ -1,7 +1,4 @@
-// check-fail
-// known-bug: #80626
-
-// This should pass, but it requires `Sized` to be coinductive.
+// check-pass
 
 trait Allocator {
     type Allocated<T>;
@@ -9,7 +6,7 @@ trait Allocator {
 
 enum LinkedList<A: Allocator> {
     Head,
-    Next(A::Allocated<Self>)
+    Next(A::Allocated<Self>),
 }
 
 fn main() {}
diff --git a/src/test/ui/generic-associated-types/bugs/issue-80626.stderr b/src/test/ui/generic-associated-types/bugs/issue-80626.stderr
deleted file mode 100644 (file)
index 9a0f332..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-error[E0275]: overflow evaluating the requirement `LinkedList<A>: Sized`
-  --> $DIR/issue-80626.rs:12:10
-   |
-LL |     Next(A::Allocated<Self>)
-   |          ^^^^^^^^^^^^^^^^^^
-   |
-note: required by a bound in `Allocator::Allocated`
-  --> $DIR/issue-80626.rs:7:20
-   |
-LL |     type Allocated<T>;
-   |                    ^ required by this bound in `Allocator::Allocated`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0275`.
index 0a11a0f3ae0e44cd06569651e9abf49f5443ecef..b35657989efb96ddda749a38767a8c04edd723ba 100644 (file)
@@ -1,3 +1,5 @@
+// check-pass
+
 trait PointerFamily {
     type Pointer<T>;
 }
@@ -10,11 +12,13 @@ impl PointerFamily for RcFamily {
 }
 
 #[allow(dead_code)]
-enum Node<T, P: PointerFamily> where P::Pointer<Node<T, P>>: Sized {
+enum Node<T, P: PointerFamily>
+where
+    P::Pointer<Node<T, P>>: Sized,
+{
     Cons(P::Pointer<Node<T, P>>),
 }
 
 fn main() {
     let _list: <RcFamily as PointerFamily>::Pointer<Node<i32, RcFamily>>;
-    //~^ ERROR overflow evaluating the requirement `Node<i32, RcFamily>: Sized`
 }
diff --git a/src/test/ui/generic-associated-types/issue-87750.stderr b/src/test/ui/generic-associated-types/issue-87750.stderr
deleted file mode 100644 (file)
index b358ca2..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0275]: overflow evaluating the requirement `Node<i32, RcFamily>: Sized`
-  --> $DIR/issue-87750.rs:18:16
-   |
-LL |     let _list: <RcFamily as PointerFamily>::Pointer<Node<i32, RcFamily>>;
-   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0275`.
index 58d57df63c1bda37e10cfa48fc2d774d50679409..ecf6f69c9fa7ebca2426cf28e384f1790afdcb08 100644 (file)
@@ -21,6 +21,7 @@ impl<T> Foo for Number<T> {
     // ```
     // which it is :)
     type Item = [T] where [T]: Sized;
+    //~^ ERROR overflow evaluating the requirement `<Number<T> as Foo>::Item == _`
 }
 
 struct OnlySized<T> where T: Sized { f: T }
@@ -40,7 +41,6 @@ impl<T> Bar for T where T: Foo {
     // can use the bound on `Foo::Item` for this, but that requires
     // `wf(<T as Foo>::Item)`, which is an invalid cycle.
     type Assoc = OnlySized<<T as Foo>::Item>;
-    //~^ ERROR overflow evaluating the requirement `<T as Foo>::Item: Sized`
 }
 
 fn foo<T: Print>() {
index 27c1a82994a53047ce20e885eed5ddb1ba2ec369..aae9a56bb612878da03b2e46c2bdc74c3ff1c175 100644 (file)
@@ -1,14 +1,8 @@
-error[E0275]: overflow evaluating the requirement `<T as Foo>::Item: Sized`
-  --> $DIR/projection-bound-cycle-generic.rs:42:18
+error[E0275]: overflow evaluating the requirement `<Number<T> as Foo>::Item == _`
+  --> $DIR/projection-bound-cycle-generic.rs:23:5
    |
-LL |     type Assoc = OnlySized<<T as Foo>::Item>;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: required by a bound in `OnlySized`
-  --> $DIR/projection-bound-cycle-generic.rs:26:18
-   |
-LL | struct OnlySized<T> where T: Sized { f: T }
-   |                  ^ required by this bound in `OnlySized`
+LL |     type Item = [T] where [T]: Sized;
+   |     ^^^^^^^^^
 
 error: aborting due to previous error
 
index 4cad1f61319ef0ecd0304dfddd7d3027c73efd85..b51ae7ef20186dcf07ad3725677657b81296ffaa 100644 (file)
@@ -24,6 +24,7 @@ impl Foo for Number {
     // ```
     // which it is :)
     type Item = str where str: Sized;
+    //~^ ERROR overflow evaluating the requirement `<Number as Foo>::Item == _`
 }
 
 struct OnlySized<T> where T: Sized { f: T }
@@ -43,7 +44,6 @@ impl<T> Bar for T where T: Foo {
     // can use the bound on `Foo::Item` for this, but that requires
     // `wf(<T as Foo>::Item)`, which is an invalid cycle.
     type Assoc = OnlySized<<T as Foo>::Item>;
-    //~^ ERROR overflow evaluating the requirement `<T as Foo>::Item: Sized`
 }
 
 fn foo<T: Print>() {
index a46518c80da76cf8e8ecf861ea288edbc882e707..b1b8afeecd02f51c65457461a4e7bd5f38e6abdb 100644 (file)
@@ -1,14 +1,8 @@
-error[E0275]: overflow evaluating the requirement `<T as Foo>::Item: Sized`
-  --> $DIR/projection-bound-cycle.rs:45:18
+error[E0275]: overflow evaluating the requirement `<Number as Foo>::Item == _`
+  --> $DIR/projection-bound-cycle.rs:26:5
    |
-LL |     type Assoc = OnlySized<<T as Foo>::Item>;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: required by a bound in `OnlySized`
-  --> $DIR/projection-bound-cycle.rs:29:18
-   |
-LL | struct OnlySized<T> where T: Sized { f: T }
-   |                  ^ required by this bound in `OnlySized`
+LL |     type Item = str where str: Sized;
+   |     ^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/higher-rank-trait-bounds/issue-36139-normalize-closure-sig.rs b/src/test/ui/higher-rank-trait-bounds/issue-36139-normalize-closure-sig.rs
new file mode 100644 (file)
index 0000000..2d49151
--- /dev/null
@@ -0,0 +1,19 @@
+// run-pass
+// Previously the closure's argument would be inferred to
+// <S as ITrait<'a>>::Item, causing an error in MIR type
+// checking
+
+trait ITrait<'a> {type Item;}
+
+struct S {}
+
+impl<'a> ITrait<'a> for S { type Item = &'a mut usize; }
+
+fn m<T, I, F>(_: F)
+    where I: for<'a> ITrait<'a>,
+          F: for<'a> FnMut(<I as ITrait<'a>>::Item) { }
+
+
+fn main() {
+    m::<usize,S,_>(|x| { *x += 1; });
+}
diff --git a/src/test/ui/higher-rank-trait-bounds/issue-43623.rs b/src/test/ui/higher-rank-trait-bounds/issue-43623.rs
new file mode 100644 (file)
index 0000000..cedcf7c
--- /dev/null
@@ -0,0 +1,21 @@
+// check-pass
+
+pub trait Trait<'a> {
+    type Assoc;
+}
+
+pub struct Type;
+
+impl<'a> Trait<'a> for Type {
+    type Assoc = ();
+}
+
+pub fn break_me<T, F>(f: F)
+where
+    T: for<'b> Trait<'b>,
+    F: for<'b> FnMut(<T as Trait<'b>>::Assoc),
+{
+    break_me::<Type, fn(_)>;
+}
+
+fn main() {}
diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90950.rs b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90950.rs
new file mode 100644 (file)
index 0000000..ab9d9a7
--- /dev/null
@@ -0,0 +1,53 @@
+// check-fail
+// known-bug: #90950
+
+trait Yokeable<'a>: 'static {
+    type Output: 'a;
+}
+
+
+trait IsCovariant<'a> {}
+
+struct Yoke<Y: for<'a> Yokeable<'a>> {
+    data: Y,
+}
+
+
+// impl<Y: for<'a> Yokeable<'a>> Yoke<Y> {
+//     fn project<Y2: for<'a> Yokeable<'a>>(
+//         &self,
+//         f: for<'a> fn(<Y as Yokeable<'a>>::Output, &'a (),
+//     ) -> <Y2 as Yokeable<'a>>::Output) -> Yoke<Y2> {
+//         unimplemented!()
+//     }
+// }
+
+fn upcast<Y>(x: Yoke<Y>) -> Yoke<Box<dyn IsCovariant<'static> + 'static>> where
+    Y: for<'a> Yokeable<'a>,
+    for<'a> <Y as Yokeable<'a>>::Output: IsCovariant<'a>
+    {
+    // x.project(|data, _| {
+    //     Box::new(data)
+    // })
+    unimplemented!()
+}
+
+
+impl<'a> Yokeable<'a> for Box<dyn IsCovariant<'static> + 'static> {
+    type Output = Box<dyn IsCovariant<'a> + 'a>;
+}
+
+// this impl is mostly an example and unnecessary for the pure repro
+use std::borrow::*;
+impl<'a, T: ToOwned + ?Sized> Yokeable<'a> for Cow<'static, T> {
+    type Output = Cow<'a, T>;
+}
+impl<'a, T: ToOwned + ?Sized> IsCovariant<'a> for Cow<'a, T> {}
+
+
+
+fn upcast_yoke(y: Yoke<Cow<'static, str>>) -> Yoke<Box<dyn IsCovariant<'static> + 'static>> {
+    upcast(y)
+}
+
+fn main() {}
diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90950.stderr b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90950.stderr
new file mode 100644 (file)
index 0000000..6206b16
--- /dev/null
@@ -0,0 +1,21 @@
+error[E0277]: the trait bound `for<'a> <_ as Yokeable<'a>>::Output: IsCovariant<'a>` is not satisfied
+  --> $DIR/issue-90950.rs:50:12
+   |
+LL |     upcast(y)
+   |     ------ ^ the trait `for<'a> IsCovariant<'a>` is not implemented for `<_ as Yokeable<'a>>::Output`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `IsCovariant<'a>` is implemented for `std::borrow::Cow<'a, T>`
+note: required by a bound in `upcast`
+  --> $DIR/issue-90950.rs:27:42
+   |
+LL | fn upcast<Y>(x: Yoke<Y>) -> Yoke<Box<dyn IsCovariant<'static> + 'static>> where
+   |    ------ required by a bound in this
+LL |     Y: for<'a> Yokeable<'a>,
+LL |     for<'a> <Y as Yokeable<'a>>::Output: IsCovariant<'a>
+   |                                          ^^^^^^^^^^^^^^^ required by this bound in `upcast`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/norm-before-method-resolution.rs b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/norm-before-method-resolution.rs
new file mode 100644 (file)
index 0000000..7693b11
--- /dev/null
@@ -0,0 +1,23 @@
+// check-fail
+// known-bug: #89196
+
+// Should pass, but we normalize and check bounds before we resolve the generics
+// of the function (which we know because of the return type).
+
+trait Trait<'a> {
+    type Out;
+}
+
+impl<'a, T> Trait<'a> for T {
+    type Out = T;
+}
+
+fn weird_bound<X>() -> X
+    where
+        for<'a> X: Trait<'a>,
+        for<'a> <X as Trait<'a>>::Out: Copy
+{ todo!() }
+
+fn main() {
+    let _: () = weird_bound();
+}
diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/norm-before-method-resolution.stderr b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/norm-before-method-resolution.stderr
new file mode 100644 (file)
index 0000000..51c9646
--- /dev/null
@@ -0,0 +1,18 @@
+error[E0277]: the trait bound `for<'a> <_ as Trait<'a>>::Out: Copy` is not satisfied
+  --> $DIR/norm-before-method-resolution.rs:22:17
+   |
+LL |     let _: () = weird_bound();
+   |                 ^^^^^^^^^^^ the trait `for<'a> Copy` is not implemented for `<_ as Trait<'a>>::Out`
+   |
+note: required by a bound in `weird_bound`
+  --> $DIR/norm-before-method-resolution.rs:18:40
+   |
+LL | fn weird_bound<X>() -> X
+   |    ----------- required by a bound in this
+...
+LL |         for<'a> <X as Trait<'a>>::Out: Copy
+   |                                        ^^^^ required by this bound in `weird_bound`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
index d881af9ed8fe13c655fed5ecff9544c72fbb4bf1..00aed2ad95a283c642fbc39e880e130dcba53212 100644 (file)
@@ -30,16 +30,19 @@ fn baa(b: bool) -> impl std::fmt::Debug {
 
 fn muh() -> Result<(), impl std::fmt::Debug> {
     Err("whoops")?;
-    Ok(()) //~ ERROR type annotations needed
+    Ok(())
+    //~^ ERROR type annotations needed
 }
 
 fn muh2() -> Result<(), impl std::fmt::Debug> {
-    return Err(From::from("foo")); //~ ERROR type annotations needed
+    return Err(From::from("foo"));
+    //~^ ERROR type annotations needed
     Ok(())
 }
 
 fn muh3() -> Result<(), impl std::fmt::Debug> {
-    Err(From::from("foo")) //~ ERROR type annotations needed
+    Err(From::from("foo"))
+    //~^ ERROR type annotations needed
 }
 
 fn main() {}
index 1ff777e65037c11b9872c7ded5cee41a4033637d..766614e9e50ffcc9cb2cc5eec08ba336b255375a 100644 (file)
@@ -10,7 +10,7 @@ LL |     Ok::<(), E>(())
    |       +++++++++
 
 error[E0282]: type annotations needed
-  --> $DIR/cross-return-site-inference.rs:37:12
+  --> $DIR/cross-return-site-inference.rs:38:12
    |
 LL |     return Err(From::from("foo"));
    |            ^^^ cannot infer type of the type parameter `E` declared on the enum `Result`
@@ -21,7 +21,7 @@ LL |     return Err::<(), E>(From::from("foo"));
    |               +++++++++
 
 error[E0282]: type annotations needed
-  --> $DIR/cross-return-site-inference.rs:42:5
+  --> $DIR/cross-return-site-inference.rs:44:5
    |
 LL |     Err(From::from("foo"))
    |     ^^^ cannot infer type of the type parameter `E` declared on the enum `Result`
index 88e2520bf4b247f2c5704d6bcff3b890e7986a67..30fbba168689be02fd3588d9646ce5772e6ddaa2 100644 (file)
@@ -9,13 +9,6 @@ help: add `dyn` keyword before this trait
 LL | fn ice() -> impl AsRef<dyn Fn(&())> {
    |                        +++
 
-error[E0277]: the trait bound `(): AsRef<(dyn for<'a> Fn(&'a ()) + 'static)>` is not satisfied
-  --> $DIR/generic-with-implicit-hrtb-without-dyn.rs:6:13
-   |
-LL | fn ice() -> impl AsRef<Fn(&())> {
-   |             ^^^^^^^^^^^^^^^^^^^ the trait `AsRef<(dyn for<'a> Fn(&'a ()) + 'static)>` is not implemented for `()`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0277, E0782.
-For more information about an error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0782`.
index 5a922697f6ff9884f46e16ade0f794af38e95e3d..bed81c4bca76e1cea701a48f00320655638d7772 100644 (file)
@@ -4,8 +4,8 @@
 #![allow(warnings)]
 
 fn ice() -> impl AsRef<Fn(&())> {
-    //~^ ERROR: the trait bound `(): AsRef<(dyn for<'a> Fn(&'a ()) + 'static)>` is not satisfied [E0277]
-    //[edition2021]~| ERROR: trait objects must include the `dyn` keyword [E0782]
+    //[edition2015]~^ ERROR: the trait bound `(): AsRef<(dyn for<'a> Fn(&'a ()) + 'static)>` is not satisfied [E0277]
+    //[edition2021]~^^ ERROR: trait objects must include the `dyn` keyword [E0782]
     todo!()
 }
 
index 3e760710797eb032902b40bec831e53772db518d..61303a5b2cb4a80379be44f06477414e50716e26 100644 (file)
@@ -3,7 +3,7 @@
 
 fn a() -> impl Fn(&u8) -> impl Debug + '_ {
     //~^ ERROR ambiguous `+` in a type
-    //~^^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet
+    //~| ERROR higher kinded lifetime bounds on nested opaque types are not supported yet
     |x| x
 }
 
diff --git a/src/test/ui/impl-trait/in-trait/generics-mismatch.rs b/src/test/ui/impl-trait/in-trait/generics-mismatch.rs
new file mode 100644 (file)
index 0000000..cc0fc72
--- /dev/null
@@ -0,0 +1,17 @@
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+struct U;
+
+trait Foo {
+    fn bar(&self) -> impl Sized;
+}
+
+impl Foo for U {
+    fn bar<T>(&self) {}
+    //~^ ERROR method `bar` has 1 type parameter but its trait declaration has 0 type parameters
+}
+
+fn main() {
+    U.bar();
+}
diff --git a/src/test/ui/impl-trait/in-trait/generics-mismatch.stderr b/src/test/ui/impl-trait/in-trait/generics-mismatch.stderr
new file mode 100644 (file)
index 0000000..cd42683
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0049]: method `bar` has 1 type parameter but its trait declaration has 0 type parameters
+  --> $DIR/generics-mismatch.rs:11:12
+   |
+LL |     fn bar(&self) -> impl Sized;
+   |           - expected 0 type parameters
+...
+LL |     fn bar<T>(&self) {}
+   |            ^ found 1 type parameter
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0049`.
diff --git a/src/test/ui/impl-trait/in-trait/method-signature-matches.rs b/src/test/ui/impl-trait/in-trait/method-signature-matches.rs
new file mode 100644 (file)
index 0000000..c848ee3
--- /dev/null
@@ -0,0 +1,51 @@
+// edition: 2021
+
+#![feature(return_position_impl_trait_in_trait, async_fn_in_trait)]
+#![allow(incomplete_features)]
+
+trait Uwu {
+    fn owo(x: ()) -> impl Sized;
+}
+
+impl Uwu for () {
+    fn owo(_: u8) {}
+    //~^ ERROR method `owo` has an incompatible type for trait
+}
+
+trait AsyncUwu {
+    async fn owo(x: ()) {}
+}
+
+impl AsyncUwu for () {
+    async fn owo(_: u8) {}
+    //~^ ERROR method `owo` has an incompatible type for trait
+}
+
+trait TooMuch {
+    fn calm_down_please() -> impl Sized;
+}
+
+impl TooMuch for () {
+    fn calm_down_please(_: (), _: (), _: ()) {}
+    //~^ ERROR method `calm_down_please` has 3 parameters but the declaration in trait `TooMuch::calm_down_please` has 0
+}
+
+trait TooLittle {
+    fn come_on_a_little_more_effort(_: (), _: (), _: ()) -> impl Sized;
+}
+
+impl TooLittle for () {
+    fn come_on_a_little_more_effort() {}
+    //~^ ERROR method `come_on_a_little_more_effort` has 0 parameters but the declaration in trait `TooLittle::come_on_a_little_more_effort` has 3
+}
+
+trait Lifetimes {
+    fn early<'early, T>(x: &'early T) -> impl Sized;
+}
+
+impl Lifetimes for () {
+    fn early<'late, T>(_: &'late ()) {}
+    //~^ ERROR method `early` has an incompatible type for trait
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/in-trait/method-signature-matches.stderr b/src/test/ui/impl-trait/in-trait/method-signature-matches.stderr
new file mode 100644 (file)
index 0000000..2b32c52
--- /dev/null
@@ -0,0 +1,84 @@
+error[E0053]: method `owo` has an incompatible type for trait
+  --> $DIR/method-signature-matches.rs:11:15
+   |
+LL |     fn owo(_: u8) {}
+   |               ^^
+   |               |
+   |               expected `()`, found `u8`
+   |               help: change the parameter type to match the trait: `()`
+   |
+note: type in trait
+  --> $DIR/method-signature-matches.rs:7:15
+   |
+LL |     fn owo(x: ()) -> impl Sized;
+   |               ^^
+   = note: expected fn pointer `fn(())`
+              found fn pointer `fn(u8)`
+
+error[E0053]: method `owo` has an incompatible type for trait
+  --> $DIR/method-signature-matches.rs:20:21
+   |
+LL |     async fn owo(_: u8) {}
+   |                     ^^
+   |                     |
+   |                     expected `()`, found `u8`
+   |                     help: change the parameter type to match the trait: `()`
+   |
+note: while checking the return type of the `async fn`
+  --> $DIR/method-signature-matches.rs:20:25
+   |
+LL |     async fn owo(_: u8) {}
+   |                         ^ checked the `Output` of this `async fn`, expected opaque type
+note: while checking the return type of the `async fn`
+  --> $DIR/method-signature-matches.rs:20:25
+   |
+LL |     async fn owo(_: u8) {}
+   |                         ^ checked the `Output` of this `async fn`, found opaque type
+note: type in trait
+  --> $DIR/method-signature-matches.rs:16:21
+   |
+LL |     async fn owo(x: ()) {}
+   |                     ^^
+   = note: expected fn pointer `fn(()) -> _`
+              found fn pointer `fn(u8) -> _`
+
+error[E0050]: method `calm_down_please` has 3 parameters but the declaration in trait `TooMuch::calm_down_please` has 0
+  --> $DIR/method-signature-matches.rs:29:28
+   |
+LL |     fn calm_down_please() -> impl Sized;
+   |     ------------------------------------ trait requires 0 parameters
+...
+LL |     fn calm_down_please(_: (), _: (), _: ()) {}
+   |                            ^^^^^^^^^^^^^^^^ expected 0 parameters, found 3
+
+error[E0050]: method `come_on_a_little_more_effort` has 0 parameters but the declaration in trait `TooLittle::come_on_a_little_more_effort` has 3
+  --> $DIR/method-signature-matches.rs:38:5
+   |
+LL |     fn come_on_a_little_more_effort(_: (), _: (), _: ()) -> impl Sized;
+   |                                        ---------------- trait requires 3 parameters
+...
+LL |     fn come_on_a_little_more_effort() {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 3 parameters, found 0
+
+error[E0053]: method `early` has an incompatible type for trait
+  --> $DIR/method-signature-matches.rs:47:27
+   |
+LL |     fn early<'late, T>(_: &'late ()) {}
+   |                     -     ^^^^^^^^^
+   |                     |     |
+   |                     |     expected type parameter `T`, found `()`
+   |                     |     help: change the parameter type to match the trait: `&'early T`
+   |                     this type parameter
+   |
+note: type in trait
+  --> $DIR/method-signature-matches.rs:43:28
+   |
+LL |     fn early<'early, T>(x: &'early T) -> impl Sized;
+   |                            ^^^^^^^^^
+   = note: expected fn pointer `fn(&'early T)`
+              found fn pointer `fn(&())`
+
+error: aborting due to 5 previous errors
+
+Some errors have detailed explanations: E0050, E0053.
+For more information about an error, try `rustc --explain E0050`.
diff --git a/src/test/ui/impl-trait/in-trait/specialization-broken.rs b/src/test/ui/impl-trait/in-trait/specialization-broken.rs
new file mode 100644 (file)
index 0000000..9d27d37
--- /dev/null
@@ -0,0 +1,26 @@
+// FIXME(compiler-errors): I'm not exactly sure if this is expected to pass or not.
+// But we fixed an ICE anyways.
+
+#![feature(specialization)]
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+trait Foo {
+    fn bar(&self) -> impl Sized;
+}
+
+default impl<U> Foo for U
+where
+    U: Copy,
+{
+    fn bar(&self) -> U {
+        //~^ ERROR method `bar` has an incompatible type for trait
+        *self
+    }
+}
+
+impl Foo for i32 {}
+
+fn main() {
+    1i32.bar();
+}
diff --git a/src/test/ui/impl-trait/in-trait/specialization-broken.stderr b/src/test/ui/impl-trait/in-trait/specialization-broken.stderr
new file mode 100644 (file)
index 0000000..a30e634
--- /dev/null
@@ -0,0 +1,23 @@
+error[E0053]: method `bar` has an incompatible type for trait
+  --> $DIR/specialization-broken.rs:16:22
+   |
+LL | default impl<U> Foo for U
+   |              - this type parameter
+...
+LL |     fn bar(&self) -> U {
+   |                      ^
+   |                      |
+   |                      expected associated type, found type parameter `U`
+   |                      help: change the output type to match the trait: `impl Sized`
+   |
+note: type in trait
+  --> $DIR/specialization-broken.rs:9:22
+   |
+LL |     fn bar(&self) -> impl Sized;
+   |                      ^^^^^^^^^^
+   = note: expected fn pointer `fn(&U) -> impl Sized`
+              found fn pointer `fn(&U) -> U`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0053`.
diff --git a/src/test/ui/impl-trait/in-trait/specialization-substs-remap.rs b/src/test/ui/impl-trait/in-trait/specialization-substs-remap.rs
new file mode 100644 (file)
index 0000000..c9ee877
--- /dev/null
@@ -0,0 +1,24 @@
+// check-pass
+
+#![feature(specialization)]
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+trait Foo {
+    fn bar(&self) -> impl Sized;
+}
+
+impl<U> Foo for U
+where
+    U: Copy,
+{
+    fn bar(&self) -> U {
+        *self
+    }
+}
+
+impl Foo for i32 {}
+
+fn main() {
+    let _: i32 = 1i32.bar();
+}
index 1518c116b318571573629d1979540cdc8c5fdec4..4a89238d07e605de576d761c77569cb5b6bbbc45 100644 (file)
@@ -4,11 +4,10 @@
 
 fn f<T>(data: &[T]) -> impl Iterator<Item = Vec> {
     //~^ ERROR: missing generics for struct `Vec` [E0107]
-    iter::empty() //~ ERROR: type annotations needed [E0282]
+    iter::empty()
 }
 
 fn g<T>(data: &[T], target: T) -> impl Iterator<Item = Vec<T>> {
-    //~^ ERROR: type annotations needed [E0282]
     f(data).filter(|x| x == target)
 }
 
index e8575b76b0930c3c8499054ad3335d51cf5c43b6..34d5c2d61dc41148c07043a0c698f8b8352b7550 100644 (file)
@@ -14,24 +14,6 @@ help: add missing generic argument
 LL | fn f<T>(data: &[T]) -> impl Iterator<Item = Vec<T>> {
    |                                             ~~~~~~
 
-error[E0282]: type annotations needed
-  --> $DIR/issue-92305.rs:7:5
-   |
-LL |     iter::empty()
-   |     ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty`
-   |
-help: consider specifying the generic argument
-   |
-LL |     iter::empty::<T>()
-   |                +++++
-
-error[E0282]: type annotations needed
-  --> $DIR/issue-92305.rs:10:35
-   |
-LL | fn g<T>(data: &[T], target: T) -> impl Iterator<Item = Vec<T>> {
-   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type
-
-error: aborting due to 3 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0107, E0282.
-For more information about an error, try `rustc --explain E0107`.
+For more information about this error, try `rustc --explain E0107`.
index abf6a7e956c693b68c3be0fcaf3ab62feffd4d34..a5db10d3a220c663cc2ed93423f238d9dfd39260 100644 (file)
@@ -35,26 +35,26 @@ fn one_hrtb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl Sized + 'a> {}
 fn one_hrtb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl Qux<'a>> {}
 //~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet
 
-// This should pass.
+// This should resolve.
 fn one_hrtb_mention_fn_trait_param<'b>() -> impl for<'a> Foo<'a, Assoc = impl Qux<'b>> {}
 
-// This should pass.
+// This should resolve.
 fn one_hrtb_mention_fn_outlives<'b>() -> impl for<'a> Foo<'a, Assoc = impl Sized + 'b> {}
 
-// This should pass.
+// This should resolve.
 fn one_hrtb_mention_fn_trait_param_uses<'b>() -> impl for<'a> Bar<'a, Assoc = impl Qux<'b>> {}
 
-// This should pass.
+// This should resolve.
 fn one_hrtb_mention_fn_outlives_uses<'b>() -> impl for<'a> Bar<'a, Assoc = impl Sized + 'b> {}
 
-// This should pass.
+// This should resolve.
 fn two_htrb_trait_param() -> impl for<'a> Foo<'a, Assoc = impl for<'b> Qux<'b>> {}
 
 // `'b` is not in scope for the outlives bound.
 fn two_htrb_outlives() -> impl for<'a> Foo<'a, Assoc = impl for<'b> Sized + 'b> {}
 //~^ ERROR use of undeclared lifetime name `'b` [E0261]
 
-// This should pass.
+// This should resolve.
 fn two_htrb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl for<'b> Qux<'b>> {}
 
 // `'b` is not in scope for the outlives bound.
index d9de73a38efff0bca0b7d3cd867d464d04462d90..79844dcbdacfd78aeca94de81b46ea5654dc58b6 100644 (file)
@@ -31,6 +31,16 @@ fn badboi<'in_, 'out, T>(x: Foo<'in_, 'out, T>, sadness: &'in_ T) -> &'out T {
     sadness.cast()
 }
 
+fn badboi2<'in_, 'out, T>(x: Foo<'in_, 'out, T>, sadness: &'in_ T) {
+    //~^ ERROR lifetime mismatch
+    let _: &'out T = sadness.cast();
+}
+
+fn badboi3<'in_, 'out, T>(a: Foo<'in_, 'out, (&'in_ T, &'out T)>, sadness: &'in_ T) {
+    //~^ ERROR lifetime mismatch
+    let _: &'out T = sadness.cast();
+}
+
 fn bad<'short, T>(value: &'short T) -> &'static T {
     let x: for<'in_, 'out> fn(Foo<'in_, 'out, T>, &'in_ T) -> &'out T = badboi;
     let x: for<'out> fn(Foo<'short, 'out, T>, &'short T) -> &'out T = x;
index b020ea64bf46ef6cdacd8eb82ea045de1fec4312..0c00bbc380e8a2fb8c6506391dc07b8400125f92 100644 (file)
@@ -7,6 +7,24 @@ LL | fn badboi<'in_, 'out, T>(x: Foo<'in_, 'out, T>, sadness: &'in_ T) -> &'out
    |                             this parameter and the return type are declared with different lifetimes...
    |                             ...but data from `x` is returned here
 
-error: aborting due to previous error
+error[E0623]: lifetime mismatch
+  --> $DIR/hrlt-implied-trait-bounds-guard.rs:34:30
+   |
+LL | fn badboi2<'in_, 'out, T>(x: Foo<'in_, 'out, T>, sadness: &'in_ T) {
+   |                              ^^^^^^^^^^^^^^^^^^
+   |                              |
+   |                              this type is declared with multiple lifetimes...
+   |                              ...but data with one lifetime flows into the other here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/hrlt-implied-trait-bounds-guard.rs:39:30
+   |
+LL | fn badboi3<'in_, 'out, T>(a: Foo<'in_, 'out, (&'in_ T, &'out T)>, sadness: &'in_ T) {
+   |                              ^^^^^^^^^^^^^^^^^-------^^-------^^
+   |                              |                |
+   |                              |                these two types are declared with different lifetimes...
+   |                              ...but data from `a` flows into `a` here
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0623`.
index e7fabd0ffbc8bd178b4457d0c82598b9c5fbccf7..b5152d04f6959fe511a9db9b2ab52f53a96427b7 100644 (file)
@@ -10,6 +10,7 @@ fn main() {
     let fut = async {
         make_unit()?;
 
-        Ok(()) //~ ERROR type annotations needed
+        Ok(())
+        //~^ ERROR type annotations needed
     };
 }
index 1c350b18f5a6fa0f9ccd457c483e2aa6d5e4fcef..bd5d10b417342ff42205cc35280047474256e2bb 100644 (file)
@@ -1,6 +1,7 @@
 fn main() {
     let x = |a: (), b: ()| {
         Err(a)?;
-        Ok(b) //~ ERROR type annotations needed
+        Ok(b)
+        //~^ ERROR type annotations needed
     };
 }
diff --git a/src/test/ui/inference/issue-103587.rs b/src/test/ui/inference/issue-103587.rs
new file mode 100644 (file)
index 0000000..11536f9
--- /dev/null
@@ -0,0 +1,12 @@
+fn main() {
+    let x = Some(123);
+
+    if let Some(_) == x {}
+    //~^ ERROR expected `=`, found `==`
+
+    if Some(_) = x {}
+    //~^ ERROR mismatched types
+
+    if None = x { }
+    //~^ ERROR mismatched types
+}
diff --git a/src/test/ui/inference/issue-103587.stderr b/src/test/ui/inference/issue-103587.stderr
new file mode 100644 (file)
index 0000000..b373fbf
--- /dev/null
@@ -0,0 +1,40 @@
+error: expected `=`, found `==`
+  --> $DIR/issue-103587.rs:4:20
+   |
+LL |     if let Some(_) == x {}
+   |                    ^^
+   |
+help: consider using `=` here
+   |
+LL |     if let Some(_) = x {}
+   |                    ~
+
+error[E0308]: mismatched types
+  --> $DIR/issue-103587.rs:7:8
+   |
+LL |     if Some(_) = x {}
+   |        ^^^^^^^^^^^ expected `bool`, found `()`
+   |
+help: consider adding `let`
+   |
+LL |     if let Some(_) = x {}
+   |        +++
+
+error[E0308]: mismatched types
+  --> $DIR/issue-103587.rs:10:8
+   |
+LL |     if None = x { }
+   |        ^^^^^^^^ expected `bool`, found `()`
+   |
+help: you might have meant to use pattern matching
+   |
+LL |     if let None = x { }
+   |        +++
+help: you might have meant to compare for equality
+   |
+LL |     if None == x { }
+   |              +
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
index 30063a0957c749e42f43372a96b57356ebc1b692..8a9d2b235f0e43c2b63787410cc100f78c405f44 100644 (file)
@@ -15,7 +15,8 @@
 
 fn foo(parameters: &HashMap<String, String>) -> bool {
     parameters
-        .get(&"key".into()) //~ ERROR: type annotations needed
+        .get(&"key".into())
+        //~^ ERROR type annotations needed
         .and_then(|found: &String| Some(false))
         .unwrap_or(false)
 }
index 5e5a3babfe02038a1bc9e784ab3327bc14baa1e0..69ade1a7515cb3e6bc521e36e015dfd86cc96e05 100644 (file)
@@ -1,3 +1,5 @@
+// ignore-wasm32 FIXME: ignoring wasm as it suggests slightly different impls
+
 // Regression test for #72616, it used to emit incorrect diagnostics, like:
 // error[E0283]: type annotations needed for `String`
 //  --> src/main.rs:8:30
@@ -18,7 +20,8 @@ pub fn main() {
     }
     {
         if String::from("a") == "a".try_into().unwrap() {}
-        //~^ ERROR: type annotations needed
+        //~^ ERROR type annotations needed
+        //~| ERROR type annotations needed
     }
     {
         let _: String = match "_".try_into() {
index a71ce9a8ef27af725cbd111f92027f71ee94288d..6ee0626cab85791e0cf973adba9d401e67a6f841 100644 (file)
@@ -1,5 +1,5 @@
 error[E0283]: type annotations needed
-  --> $DIR/issue-72616.rs:20:37
+  --> $DIR/issue-72616.rs:22:37
    |
 LL |         if String::from("a") == "a".try_into().unwrap() {}
    |                              --     ^^^^^^^^
@@ -16,6 +16,22 @@ help: try using a fully qualified path to specify the expected types
 LL |         if String::from("a") == <&str as TryInto<T>>::try_into("a").unwrap() {}
    |                                 +++++++++++++++++++++++++++++++   ~
 
-error: aborting due to previous error
+error[E0283]: type annotations needed
+  --> $DIR/issue-72616.rs:22:37
+   |
+LL |         if String::from("a") == "a".try_into().unwrap() {}
+   |                                     ^^^^^^^^
+   |
+   = note: multiple `impl`s satisfying `_: TryFrom<&str>` found in the following crates: `core`, `std`:
+           - impl<> TryFrom<&str> for std::sys_common::net::LookupHost;
+           - impl<T, U> TryFrom<U> for T
+             where U: Into<T>;
+   = note: required for `&str` to implement `TryInto<_>`
+help: try using a fully qualified path to specify the expected types
+   |
+LL |         if String::from("a") == <&str as TryInto<T>>::try_into("a").unwrap() {}
+   |                                 +++++++++++++++++++++++++++++++   ~
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0283`.
index 64333a29313b349d2187441020d27c7326be8c5b..10560f85ed480a67d4012043c9e2f7b6504c28ea 100644 (file)
@@ -7,7 +7,8 @@ fn f(x: &i32) -> Result<i32, ()> {
 
 fn g() -> Result<Vec<i32>, ()> {
     let l = [1, 2, 3, 4];
-    l.iter().map(f).collect()? //~ ERROR type annotations needed
+    l.iter().map(f).collect()?
+    //~^ ERROR type annotations needed
 }
 
 fn main() {
diff --git a/src/test/ui/issues/auxiliary/issue-75907.rs b/src/test/ui/issues/auxiliary/issue-75907.rs
deleted file mode 100644 (file)
index 389c9c3..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-pub struct Bar(pub u8, u8, u8);
-
-pub fn make_bar() -> Bar {
-    Bar(1, 12, 10)
-}
-
-mod inner {
-    pub struct Foo(u8, pub u8, u8);
-
-    impl Foo {
-        pub fn new() -> Foo {
-            Foo(1, 12, 10)
-        }
-    }
-}
-
-pub use inner::Foo;
diff --git a/src/test/ui/issues/issue-10969.rs b/src/test/ui/issues/issue-10969.rs
deleted file mode 100644 (file)
index 0b78fc1..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-fn func(i: i32) {
-    i(); //~ERROR expected function, found `i32`
-}
-fn main() {
-    let i = 0i32;
-    i(); //~ERROR expected function, found `i32`
-}
diff --git a/src/test/ui/issues/issue-10969.stderr b/src/test/ui/issues/issue-10969.stderr
deleted file mode 100644 (file)
index f64b61a..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-error[E0618]: expected function, found `i32`
-  --> $DIR/issue-10969.rs:2:5
-   |
-LL | fn func(i: i32) {
-   |         - `i` has type `i32`
-LL |     i();
-   |     ^--
-   |     |
-   |     call expression requires function
-
-error[E0618]: expected function, found `i32`
-  --> $DIR/issue-10969.rs:6:5
-   |
-LL |     let i = 0i32;
-   |         - `i` has type `i32`
-LL |     i();
-   |     ^--
-   |     |
-   |     call expression requires function
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0618`.
diff --git a/src/test/ui/issues/issue-11612.rs b/src/test/ui/issues/issue-11612.rs
deleted file mode 100644 (file)
index 9f7f1cc..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-// check-pass
-#![allow(dead_code)]
-// #11612
-// We weren't updating the auto adjustments with all the resolved
-// type information after type check.
-
-// pretty-expanded FIXME #23616
-
-trait A { fn dummy(&self) { } }
-
-struct B<'a, T:'a> {
-    f: &'a T
-}
-
-impl<'a, T> A for B<'a, T> {}
-
-fn foo(_: &dyn A) {}
-
-fn bar<G>(b: &B<G>) {
-    foo(b);       // Coercion should work
-    foo(b as &dyn A); // Explicit cast should work as well
-}
-
-fn main() {}
diff --git a/src/test/ui/issues/issue-12552.rs b/src/test/ui/issues/issue-12552.rs
deleted file mode 100644 (file)
index b7f71dd..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-// this code used to cause an ICE
-
-fn main() {
-  let t = Err(0);
-  match t {
-    Some(k) => match k { //~ ERROR mismatched types
-      a => println!("{}", a)
-    },
-    None => () //~ ERROR mismatched types
-  }
-}
diff --git a/src/test/ui/issues/issue-12552.stderr b/src/test/ui/issues/issue-12552.stderr
deleted file mode 100644 (file)
index 4b027eb..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/issue-12552.rs:6:5
-   |
-LL |   match t {
-   |         - this expression has type `Result<_, {integer}>`
-LL |     Some(k) => match k {
-   |     ^^^^^^^ expected enum `Result`, found enum `Option`
-   |
-   = note: expected enum `Result<_, {integer}>`
-              found enum `Option<_>`
-help: try wrapping the pattern in `Ok`
-   |
-LL |     Ok(Some(k)) => match k {
-   |     +++       +
-
-error[E0308]: mismatched types
-  --> $DIR/issue-12552.rs:9:5
-   |
-LL |   match t {
-   |         - this expression has type `Result<_, {integer}>`
-...
-LL |     None => ()
-   |     ^^^^ expected enum `Result`, found enum `Option`
-   |
-   = note: expected enum `Result<_, {integer}>`
-              found enum `Option<_>`
-help: try wrapping the pattern in `Ok`
-   |
-LL |     Ok(None) => ()
-   |     +++    +
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
index f0ff2cafd4466126336f2ad11d8ce8b3814e4817..eb7661fad56db57b7c2bd7cad4053a005f8d6e09 100644 (file)
@@ -2,7 +2,7 @@ warning: unused closure that must be used
   --> $DIR/issue-1460.rs:6:5
    |
 LL |     {|i: u32| if 1 == i { }};
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: closures are lazy and do nothing unless called
    = note: `#[warn(unused_must_use)]` on by default
index ca8e9a1bed3374d3d4db50e4ce176d12a61df5ce..d920530b57c6940efc1e22d617f0cbc902355ac9 100644 (file)
@@ -2,7 +2,7 @@ warning: unused closure that must be used
   --> $DIR/issue-16256.rs:6:5
    |
 LL |     |c: u8| buf.push(c);
-   |     ^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^
    |
    = note: closures are lazy and do nothing unless called
    = note: `#[warn(unused_must_use)]` on by default
index 2d9ce430a462dc8d7ab99ebc094d1b7678804fdb..5a758c7002b92b6a54deb76a08a8fed43667611a 100644 (file)
@@ -2,18 +2,28 @@ error: cannot find attribute `derive_Clone` in this scope
   --> $DIR/issue-32655.rs:3:11
    |
 LL |         #[derive_Clone]
-   |           ^^^^^^^^^^^^
+   |           ^^^^^^^^^^^^ help: an attribute macro with a similar name exists: `derive_const`
 ...
 LL | foo!();
    | ------ in this macro invocation
    |
+  ::: $SRC_DIR/core/src/macros/mod.rs:LL:COL
+   |
+LL |     pub macro derive_const($item:item) {
+   |     ---------------------- similarly named attribute macro `derive_const` defined here
+   |
    = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: cannot find attribute `derive_Clone` in this scope
   --> $DIR/issue-32655.rs:15:7
    |
 LL |     #[derive_Clone]
-   |       ^^^^^^^^^^^^
+   |       ^^^^^^^^^^^^ help: an attribute macro with a similar name exists: `derive_const`
+   |
+  ::: $SRC_DIR/core/src/macros/mod.rs:LL:COL
+   |
+LL |     pub macro derive_const($item:item) {
+   |     ---------------------- similarly named attribute macro `derive_const` defined here
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-35675.rs b/src/test/ui/issues/issue-35675.rs
deleted file mode 100644 (file)
index 6837616..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-// these two HELPs are actually in a new line between this line and the `enum Fruit` line
-enum Fruit {
-    Apple(i64),
-    Orange(i64),
-}
-
-fn should_return_fruit() -> Apple {
-    //~^ ERROR cannot find type `Apple` in this scope
-    Apple(5)
-    //~^ ERROR cannot find function, tuple struct or tuple variant `Apple` in this scope
-}
-
-fn should_return_fruit_too() -> Fruit::Apple {
-    //~^ ERROR expected type, found variant `Fruit::Apple`
-    Apple(5)
-    //~^ ERROR cannot find function, tuple struct or tuple variant `Apple` in this scope
-}
-
-fn foo() -> Ok {
-    //~^ ERROR expected type, found variant `Ok`
-    Ok(())
-}
-
-fn bar() -> Variant3 {
-    //~^ ERROR cannot find type `Variant3` in this scope
-}
-
-fn qux() -> Some {
-    //~^ ERROR expected type, found variant `Some`
-    Some(1)
-}
-
-fn main() {}
-
-mod x {
-    pub enum Enum {
-        Variant1,
-        Variant2(),
-        Variant3(usize),
-        Variant4 {},
-    }
-}
diff --git a/src/test/ui/issues/issue-35675.stderr b/src/test/ui/issues/issue-35675.stderr
deleted file mode 100644 (file)
index 4a06196..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-error[E0412]: cannot find type `Apple` in this scope
-  --> $DIR/issue-35675.rs:7:29
-   |
-LL | fn should_return_fruit() -> Apple {
-   |                             ^^^^^ not found in this scope
-   |
-help: there is an enum variant `Fruit::Apple`; try using the variant's enum
-   |
-LL | fn should_return_fruit() -> Fruit {
-   |                             ~~~~~
-
-error[E0425]: cannot find function, tuple struct or tuple variant `Apple` in this scope
-  --> $DIR/issue-35675.rs:9:5
-   |
-LL |     Apple(5)
-   |     ^^^^^ not found in this scope
-   |
-help: consider importing this tuple variant
-   |
-LL | use Fruit::Apple;
-   |
-
-error[E0573]: expected type, found variant `Fruit::Apple`
-  --> $DIR/issue-35675.rs:13:33
-   |
-LL | fn should_return_fruit_too() -> Fruit::Apple {
-   |                                 ^^^^^^^^^^^^
-   |                                 |
-   |                                 not a type
-   |                                 help: try using the variant's enum: `Fruit`
-
-error[E0425]: cannot find function, tuple struct or tuple variant `Apple` in this scope
-  --> $DIR/issue-35675.rs:15:5
-   |
-LL |     Apple(5)
-   |     ^^^^^ not found in this scope
-   |
-help: consider importing this tuple variant
-   |
-LL | use Fruit::Apple;
-   |
-
-error[E0573]: expected type, found variant `Ok`
-  --> $DIR/issue-35675.rs:19:13
-   |
-LL | fn foo() -> Ok {
-   |             ^^
-   |             |
-   |             not a type
-   |             help: try using the variant's enum: `std::result::Result`
-
-error[E0412]: cannot find type `Variant3` in this scope
-  --> $DIR/issue-35675.rs:24:13
-   |
-LL | fn bar() -> Variant3 {
-   |             ^^^^^^^^ not found in this scope
-   |
-help: there is an enum variant `x::Enum::Variant3`; try using the variant's enum
-   |
-LL | fn bar() -> x::Enum {
-   |             ~~~~~~~
-
-error[E0573]: expected type, found variant `Some`
-  --> $DIR/issue-35675.rs:28:13
-   |
-LL | fn qux() -> Some {
-   |             ^^^^
-   |             |
-   |             not a type
-   |             help: try using the variant's enum: `std::option::Option`
-
-error: aborting due to 7 previous errors
-
-Some errors have detailed explanations: E0412, E0425, E0573.
-For more information about an error, try `rustc --explain E0412`.
diff --git a/src/test/ui/issues/issue-36139-normalize-closure-sig.rs b/src/test/ui/issues/issue-36139-normalize-closure-sig.rs
deleted file mode 100644 (file)
index 2d49151..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-// run-pass
-// Previously the closure's argument would be inferred to
-// <S as ITrait<'a>>::Item, causing an error in MIR type
-// checking
-
-trait ITrait<'a> {type Item;}
-
-struct S {}
-
-impl<'a> ITrait<'a> for S { type Item = &'a mut usize; }
-
-fn m<T, I, F>(_: F)
-    where I: for<'a> ITrait<'a>,
-          F: for<'a> FnMut(<I as ITrait<'a>>::Item) { }
-
-
-fn main() {
-    m::<usize,S,_>(|x| { *x += 1; });
-}
index 6ca2deee377a3690e52c01f34cd0006172143543..07c8101cbc68b776aa15b2d6f5b3912af677ea60 100644 (file)
@@ -2,10 +2,10 @@ error[E0599]: no method named `boom` found for reference `&Obj` in the current s
   --> $DIR/issue-3707.rs:10:14
    |
 LL |         self.boom();
-   |         -----^^^^
+   |         -----^^^^--
    |         |    |
    |         |    this is an associated function, not a method
-   |         help: use associated function syntax instead: `Obj::boom`
+   |         help: use associated function syntax instead: `Obj::boom()`
    |
    = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
 note: the candidate is defined in an impl for the type `Obj`
diff --git a/src/test/ui/issues/issue-43623.rs b/src/test/ui/issues/issue-43623.rs
deleted file mode 100644 (file)
index cedcf7c..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-// check-pass
-
-pub trait Trait<'a> {
-    type Assoc;
-}
-
-pub struct Type;
-
-impl<'a> Trait<'a> for Type {
-    type Assoc = ();
-}
-
-pub fn break_me<T, F>(f: F)
-where
-    T: for<'b> Trait<'b>,
-    F: for<'b> FnMut(<T as Trait<'b>>::Assoc),
-{
-    break_me::<Type, fn(_)>;
-}
-
-fn main() {}
diff --git a/src/test/ui/issues/issue-46519.rs b/src/test/ui/issues/issue-46519.rs
deleted file mode 100644 (file)
index 0567923..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-// run-pass
-// compile-flags:--test -O
-
-// needs-unwind
-
-#[test]
-#[should_panic(expected = "creating inhabited type")]
-fn test() {
-    FontLanguageOverride::system_font(SystemFont::new());
-}
-
-pub enum FontLanguageOverride {
-    Normal,
-    Override(&'static str),
-    System(SystemFont)
-}
-
-pub enum SystemFont {}
-
-impl FontLanguageOverride {
-    fn system_font(f: SystemFont) -> Self {
-        FontLanguageOverride::System(f)
-    }
-}
-
-impl SystemFont {
-    fn new() -> Self {
-        panic!("creating inhabited type")
-    }
-}
index f97713b4ac438f4ca46858f42a63ffd3079ae69f..c2c7df7a333a4a3461ca29a6273be3e7bf8511ac 100644 (file)
@@ -4,7 +4,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     let _vec: Vec<&'static String> = vec![&String::new()];
    |               --------------------         ^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
    |               |                            |
-   |               |                            creates a temporary which is freed while still in use
+   |               |                            creates a temporary value which is freed while still in use
    |               type annotation requires that borrow lasts for `'static`
 
 error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-47511.rs b/src/test/ui/issues/issue-47511.rs
deleted file mode 100644 (file)
index eb4860e..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-// check-fail
-// known-bug: #47511
-
-// Regression test for #47511: anonymous lifetimes can appear
-// unconstrained in a return type, but only if they appear just once
-// in the input, as the input to a projection.
-
-fn f(_: X) -> X {
-    unimplemented!()
-}
-
-fn g<'a>(_: X<'a>) -> X<'a> {
-    unimplemented!()
-}
-
-type X<'a> = <&'a () as Trait>::Value;
-
-trait Trait {
-    type Value;
-}
-
-impl<'a> Trait for &'a () {
-    type Value = ();
-}
-
-fn main() {}
diff --git a/src/test/ui/issues/issue-47511.stderr b/src/test/ui/issues/issue-47511.stderr
deleted file mode 100644 (file)
index 9998ee0..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-error[E0581]: return type references an anonymous lifetime, which is not constrained by the fn input types
-  --> $DIR/issue-47511.rs:8:15
-   |
-LL | fn f(_: X) -> X {
-   |               ^
-   |
-   = note: lifetimes appearing in an associated or opaque type are not considered constrained
-   = note: consider introducing a named lifetime parameter
-
-error[E0581]: return type references lifetime `'a`, which is not constrained by the fn input types
-  --> $DIR/issue-47511.rs:12:23
-   |
-LL | fn g<'a>(_: X<'a>) -> X<'a> {
-   |                       ^^^^^
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0581`.
diff --git a/src/test/ui/issues/issue-50687-ice-on-borrow.rs b/src/test/ui/issues/issue-50687-ice-on-borrow.rs
deleted file mode 100644 (file)
index 7a8a12c..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-// This previously caused an ICE at:
-// librustc/traits/structural_impls.rs:180: impossible case reached
-
-#![no_main]
-
-use std::borrow::Borrow;
-use std::io;
-use std::io::Write;
-
-trait Constraint {}
-
-struct Container<T> {
-    t: T,
-}
-
-struct Borrowed;
-struct Owned;
-
-impl<'a, T> Write for &'a Container<T>
-where
-    T: Constraint,
-    &'a T: Write,
-{
-    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        Ok(buf.len())
-    }
-
-    fn flush(&mut self) -> io::Result<()> {
-        Ok(())
-    }
-}
-
-impl Borrow<Borrowed> for Owned {
-    fn borrow(&self) -> &Borrowed {
-        &Borrowed
-    }
-}
-
-fn func(owned: Owned) {
-    let _: () = Borrow::borrow(&owned); //~ ERROR mismatched types
-}
diff --git a/src/test/ui/issues/issue-50687-ice-on-borrow.stderr b/src/test/ui/issues/issue-50687-ice-on-borrow.stderr
deleted file mode 100644 (file)
index e6a0eda..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/issue-50687-ice-on-borrow.rs:40:17
-   |
-LL |     let _: () = Borrow::borrow(&owned);
-   |            --   ^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found reference
-   |            |
-   |            expected due to this
-   |
-   = note: expected unit type `()`
-              found reference `&_`
-help: consider dereferencing the borrow
-   |
-LL |     let _: () = *Borrow::borrow(&owned);
-   |                 +
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
index 55929d85da457983b7db5ac442efd7b497426539..b25dbd1cb8b124eea9068fdf80ab28be1d94e615 100644 (file)
@@ -4,7 +4,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     foo(&unpromotable(5u32));
    |     -----^^^^^^^^^^^^^^^^^^-
    |     |    |
-   |     |    creates a temporary which is freed while still in use
+   |     |    creates a temporary value which is freed while still in use
    |     argument requires that borrow lasts for `'static`
 LL | }
    | - temporary value is freed at the end of this statement
diff --git a/src/test/ui/issues/issue-5216.rs b/src/test/ui/issues/issue-5216.rs
deleted file mode 100644 (file)
index 4072a57..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-fn f() { }
-struct S(Box<dyn FnMut() + Sync>);
-pub static C: S = S(f); //~ ERROR mismatched types
-
-
-fn g() { }
-type T = Box<dyn FnMut() + Sync>;
-pub static D: T = g; //~ ERROR mismatched types
-
-fn main() {}
diff --git a/src/test/ui/issues/issue-5216.stderr b/src/test/ui/issues/issue-5216.stderr
deleted file mode 100644 (file)
index 1afff28..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/issue-5216.rs:3:21
-   |
-LL | pub static C: S = S(f);
-   |                   - ^ expected struct `Box`, found fn item
-   |                   |
-   |                   arguments to this struct are incorrect
-   |
-   = note: expected struct `Box<(dyn FnMut() + Sync + 'static)>`
-             found fn item `fn() {f}`
-note: tuple struct defined here
-  --> $DIR/issue-5216.rs:2:8
-   |
-LL | struct S(Box<dyn FnMut() + Sync>);
-   |        ^
-
-error[E0308]: mismatched types
-  --> $DIR/issue-5216.rs:8:19
-   |
-LL | pub static D: T = g;
-   |                   ^ expected struct `Box`, found fn item
-   |
-   = note: expected struct `Box<(dyn FnMut() + Sync + 'static)>`
-             found fn item `fn() {g}`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/issues/issue-52240.rs b/src/test/ui/issues/issue-52240.rs
deleted file mode 100644 (file)
index 5def557..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-// issue-52240: Can turn immutable into mut with `ref mut`
-
-enum Foo {
-    Bar(i32),
-}
-
-fn main() {
-    let arr = vec!(Foo::Bar(0));
-    if let (Some(Foo::Bar(ref mut val)), _) = (&arr.get(0), 0) {
-        //~^ ERROR cannot borrow data in a `&` reference as mutable
-        *val = 9001;
-    }
-    match arr[0] {
-        Foo::Bar(ref s) => println!("{}", s)
-    }
-}
diff --git a/src/test/ui/issues/issue-52240.stderr b/src/test/ui/issues/issue-52240.stderr
deleted file mode 100644 (file)
index 69b663b..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0596]: cannot borrow data in a `&` reference as mutable
-  --> $DIR/issue-52240.rs:9:27
-   |
-LL |     if let (Some(Foo::Bar(ref mut val)), _) = (&arr.get(0), 0) {
-   |                           ^^^^^^^^^^^ cannot borrow as mutable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0596`.
diff --git a/src/test/ui/issues/issue-54943-1.rs b/src/test/ui/issues/issue-54943-1.rs
deleted file mode 100644 (file)
index ec682d9..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-// This test is a minimal version of an ICE in the dropck-eyepatch tests
-// found in the fix for #54943.
-
-// check-pass
-
-fn foo<T>(_t: T) {
-}
-
-fn main() {
-    struct A<'a, B: 'a>(&'a B);
-    let (a1, a2): (String, A<_>) = (String::from("auto"), A(&"this"));
-    foo((a1, a2));
-}
diff --git a/src/test/ui/issues/issue-54943-2.rs b/src/test/ui/issues/issue-54943-2.rs
deleted file mode 100644 (file)
index d400ae5..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-// This test is a minimal version of an ICE in the dropck-eyepatch tests
-// found in the fix for #54943. In particular, this test is in unreachable
-// code as the initial fix for this ICE only worked if the code was reachable.
-
-// check-pass
-
-fn foo<T>(_t: T) {
-}
-
-fn main() {
-    return;
-
-    struct A<'a, B: 'a>(&'a B);
-    let (a1, a2): (String, A<_>) = (String::from("auto"), A(&"this"));
-    foo((a1, a2));
-}
diff --git a/src/test/ui/issues/issue-54943.rs b/src/test/ui/issues/issue-54943.rs
deleted file mode 100644 (file)
index 8572230..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-fn foo<T: 'static>() { }
-
-fn boo<'a>() {
-    return;
-
-    let x = foo::<&'a u32>();
-    //~^ ERROR
-}
-
-fn main() {}
diff --git a/src/test/ui/issues/issue-54943.stderr b/src/test/ui/issues/issue-54943.stderr
deleted file mode 100644 (file)
index 59be0f9..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-error: lifetime may not live long enough
-  --> $DIR/issue-54943.rs:6:13
-   |
-LL | fn boo<'a>() {
-   |        -- lifetime `'a` defined here
-...
-LL |     let x = foo::<&'a u32>();
-   |             ^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/issues/issue-54954.rs b/src/test/ui/issues/issue-54954.rs
deleted file mode 100644 (file)
index d4e1df2..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-const ARR_LEN: usize = Tt::const_val::<[i8; 123]>();
-//~^ ERROR E0790
-
-trait Tt {
-    const fn const_val<T: Sized>() -> usize {
-        //~^ ERROR functions in traits cannot be declared const
-        core::mem::size_of::<T>()
-    }
-}
-
-fn f(z: [f32; ARR_LEN]) -> [f32; ARR_LEN] {
-  //~^ ERROR evaluation of constant value failed
-  //~| ERROR evaluation of constant value failed
-    z
-}
-
-fn main() {
-    let _ = f([1f32; ARR_LEN]);
-}
diff --git a/src/test/ui/issues/issue-54954.stderr b/src/test/ui/issues/issue-54954.stderr
deleted file mode 100644 (file)
index 668985c..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-error[E0379]: functions in traits cannot be declared const
-  --> $DIR/issue-54954.rs:5:5
-   |
-LL |     const fn const_val<T: Sized>() -> usize {
-   |     ^^^^^ functions in traits cannot be const
-
-error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type
-  --> $DIR/issue-54954.rs:1:24
-   |
-LL |   const ARR_LEN: usize = Tt::const_val::<[i8; 123]>();
-   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot call associated function of trait
-...
-LL | /     const fn const_val<T: Sized>() -> usize {
-LL | |
-LL | |         core::mem::size_of::<T>()
-LL | |     }
-   | |_____- `Tt::const_val` defined here
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/issue-54954.rs:11:15
-   |
-LL | fn f(z: [f32; ARR_LEN]) -> [f32; ARR_LEN] {
-   |               ^^^^^^^ referenced constant has errors
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/issue-54954.rs:11:34
-   |
-LL | fn f(z: [f32; ARR_LEN]) -> [f32; ARR_LEN] {
-   |                                  ^^^^^^^ referenced constant has errors
-
-error: aborting due to 4 previous errors
-
-Some errors have detailed explanations: E0080, E0379, E0790.
-For more information about an error, try `rustc --explain E0080`.
diff --git a/src/test/ui/issues/issue-5927.rs b/src/test/ui/issues/issue-5927.rs
deleted file mode 100644 (file)
index 14f9582..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-fn main() {
-    let z = match 3 {
-        x(1) => x(1) //~ ERROR cannot find tuple struct or tuple variant `x` in this scope
-        //~^ ERROR cannot find function `x` in this scope
-    };
-    assert!(z == 3);
-}
diff --git a/src/test/ui/issues/issue-5927.stderr b/src/test/ui/issues/issue-5927.stderr
deleted file mode 100644 (file)
index d6cd685..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-error[E0531]: cannot find tuple struct or tuple variant `x` in this scope
-  --> $DIR/issue-5927.rs:3:9
-   |
-LL |         x(1) => x(1)
-   |         ^ not found in this scope
-
-error[E0425]: cannot find function `x` in this scope
-  --> $DIR/issue-5927.rs:3:17
-   |
-LL |         x(1) => x(1)
-   |                 ^ not found in this scope
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0425, E0531.
-For more information about an error, try `rustc --explain E0425`.
index f581429a281540cf6242a6c4708beac4ccacee3f..89aeafebac497da7cb98c81f6408934209e310b2 100644 (file)
@@ -2,10 +2,7 @@ error[E0428]: the name `A` is defined multiple times
   --> $DIR/issue-69396-const-no-type-in-macro.rs:4:13
    |
 LL |               const A = "A".$fn();
-   |               ^^^^^^^^^^^^^^^^^^^^
-   |               |
-   |               `A` redefined here
-   |               previous definition of the value `A` here
+   |               ^^^^^^^^^^^^^^^^^^^^ `A` redefined here
 ...
 LL | / suite! {
 LL | |     len;
diff --git a/src/test/ui/issues/issue-7013.rs b/src/test/ui/issues/issue-7013.rs
deleted file mode 100644 (file)
index 1fb0130..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-use std::cell::RefCell;
-use std::rc::Rc;
-
-trait Foo {
-    fn set(&mut self, v: Rc<RefCell<A>>);
-}
-
-struct B {
-    v: Option<Rc<RefCell<A>>>
-}
-
-impl Foo for B {
-    fn set(&mut self, v: Rc<RefCell<A>>)
-    {
-        self.v = Some(v);
-    }
-}
-
-struct A {
-    v: Box<dyn Foo + Send>,
-}
-
-fn main() {
-    let a = A {v: Box::new(B{v: None}) as Box<dyn Foo + Send>};
-    //~^ ERROR `Rc<RefCell<A>>` cannot be sent between threads safely
-}
diff --git a/src/test/ui/issues/issue-7013.stderr b/src/test/ui/issues/issue-7013.stderr
deleted file mode 100644 (file)
index 4575f4d..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-error[E0277]: `Rc<RefCell<A>>` cannot be sent between threads safely
-  --> $DIR/issue-7013.rs:24:19
-   |
-LL |     let a = A {v: Box::new(B{v: None}) as Box<dyn Foo + Send>};
-   |                   ^^^^^^^^^^^^^^^^^^^^ `Rc<RefCell<A>>` cannot be sent between threads safely
-   |
-   = help: within `B`, the trait `Send` is not implemented for `Rc<RefCell<A>>`
-   = note: required because it appears within the type `Option<Rc<RefCell<A>>>`
-note: required because it appears within the type `B`
-  --> $DIR/issue-7013.rs:8:8
-   |
-LL | struct B {
-   |        ^
-   = note: required for the cast from `B` to the object type `dyn Foo + Send`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0277`.
index c96cd598f0ce067dab8619991fc3ad9a72767a1c..7bf3ed60ec104e83e8e83d74d824dadee0d3d4ee 100644 (file)
@@ -1,5 +1,6 @@
 fn main() {
     let n: u32 = 1;
     let mut d: u64 = 2;
-    d = d % n.into(); //~ ERROR type annotations needed
+    d = d % n.into();
+    //~^ ERROR type annotations needed
 }
diff --git a/src/test/ui/issues/issue-75907.rs b/src/test/ui/issues/issue-75907.rs
deleted file mode 100644 (file)
index 6da99cf..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-// Test for diagnostic improvement issue #75907
-
-mod foo {
-    pub(crate) struct Foo(u8);
-    pub(crate) struct Bar(pub u8, u8, Foo);
-
-    pub(crate) fn make_bar() -> Bar {
-        Bar(1, 12, Foo(10))
-    }
-}
-
-use foo::{make_bar, Bar, Foo};
-
-fn main() {
-    let Bar(x, y, Foo(z)) = make_bar();
-    //~^ ERROR cannot match against a tuple struct which contains private fields
-    //~| ERROR cannot match against a tuple struct which contains private fields
-}
diff --git a/src/test/ui/issues/issue-75907.stderr b/src/test/ui/issues/issue-75907.stderr
deleted file mode 100644 (file)
index 2f89e31..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-error[E0532]: cannot match against a tuple struct which contains private fields
-  --> $DIR/issue-75907.rs:15:9
-   |
-LL |     let Bar(x, y, Foo(z)) = make_bar();
-   |         ^^^
-   |
-note: constructor is not visible here due to private fields
-  --> $DIR/issue-75907.rs:15:16
-   |
-LL |     let Bar(x, y, Foo(z)) = make_bar();
-   |                ^  ^^^^^^ private field
-   |                |
-   |                private field
-
-error[E0532]: cannot match against a tuple struct which contains private fields
-  --> $DIR/issue-75907.rs:15:19
-   |
-LL |     let Bar(x, y, Foo(z)) = make_bar();
-   |                   ^^^
-   |
-note: constructor is not visible here due to private fields
-  --> $DIR/issue-75907.rs:15:23
-   |
-LL |     let Bar(x, y, Foo(z)) = make_bar();
-   |                       ^ private field
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0532`.
diff --git a/src/test/ui/issues/issue-75907_b.rs b/src/test/ui/issues/issue-75907_b.rs
deleted file mode 100644 (file)
index fdfc590..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-// Test for diagnostic improvement issue #75907, extern crate
-// aux-build:issue-75907.rs
-
-extern crate issue_75907 as a;
-
-use a::{make_bar, Bar, Foo};
-
-fn main() {
-    let Bar(x, y, z) = make_bar();
-    //~^ ERROR cannot match against a tuple struct which contains private fields
-
-    let Foo(x, y, z) = Foo::new();
-    //~^ ERROR cannot match against a tuple struct which contains private fields
-}
diff --git a/src/test/ui/issues/issue-75907_b.stderr b/src/test/ui/issues/issue-75907_b.stderr
deleted file mode 100644 (file)
index b82d084..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-error[E0532]: cannot match against a tuple struct which contains private fields
-  --> $DIR/issue-75907_b.rs:9:9
-   |
-LL |     let Bar(x, y, z) = make_bar();
-   |         ^^^
-   |
-note: constructor is not visible here due to private fields
-  --> $DIR/issue-75907_b.rs:9:16
-   |
-LL |     let Bar(x, y, z) = make_bar();
-   |                ^  ^ private field
-   |                |
-   |                private field
-
-error[E0532]: cannot match against a tuple struct which contains private fields
-  --> $DIR/issue-75907_b.rs:12:9
-   |
-LL |     let Foo(x, y, z) = Foo::new();
-   |         ^^^
-   |
-note: constructor is not visible here due to private fields
-  --> $DIR/issue-75907_b.rs:12:13
-   |
-LL |     let Foo(x, y, z) = Foo::new();
-   |             ^     ^ private field
-   |             |
-   |             private field
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0532`.
index 7d35da825328e29577a5bb8e6ec3177ee8ff6c38..4c424999b754d5e867f0e402da5b3f318b1f33f0 100644 (file)
@@ -1,5 +1,4 @@
 fn main() {
-    //~^ NOTE required by a bound in this
     let whatever: [u32; 10] = (0..10).collect();
     //~^ ERROR an array of type `[u32; 10]` cannot be built directly from an iterator
     //~| NOTE try collecting into a `Vec<{integer}>`, then using `.try_into()`
index 7fe9707e6d232b4e4323f95320c591f18755f90c..a23a36a88abb336dd24a54ec7ce3f41c9654ee90 100644 (file)
@@ -1,5 +1,5 @@
 error[E0277]: an array of type `[u32; 10]` cannot be built directly from an iterator
-  --> $DIR/collect-into-array.rs:3:31
+  --> $DIR/collect-into-array.rs:2:31
    |
 LL |     let whatever: [u32; 10] = (0..10).collect();
    |                               ^^^^^^^ ------- required by a bound introduced by this call
index 5eade075613fe6ce94d16c94256a60bcec2ee670..09832c260d04e82e5e64d0ccc510bf49ae6a42a6 100644 (file)
@@ -1,6 +1,4 @@
 fn process_slice(data: &[i32]) {
-    //~^ NOTE required by a bound in this
-    //~| NOTE required by a bound in this
     todo!()
 }
 
index bce40118bdfa0ad5b50fb7442e131469a71ac60f..bc152467ce3a5c5d94d1c06ca790ec3793a38492 100644 (file)
@@ -1,5 +1,5 @@
 error[E0277]: the size for values of type `[i32]` cannot be known at compilation time
-  --> $DIR/collect-into-slice.rs:8:9
+  --> $DIR/collect-into-slice.rs:6:9
    |
 LL |     let some_generated_vec = (0..10).collect();
    |         ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
@@ -9,7 +9,7 @@ LL |     let some_generated_vec = (0..10).collect();
    = help: unsized locals are gated as an unstable feature
 
 error[E0277]: the size for values of type `[i32]` cannot be known at compilation time
-  --> $DIR/collect-into-slice.rs:8:38
+  --> $DIR/collect-into-slice.rs:6:38
    |
 LL |     let some_generated_vec = (0..10).collect();
    |                                      ^^^^^^^ doesn't have a size known at compile-time
@@ -22,7 +22,7 @@ LL |     fn collect<B: FromIterator<Self::Item>>(self) -> B
    |                ^ required by this bound in `collect`
 
 error[E0277]: a slice of type `[i32]` cannot be built since `[i32]` has no definite size
-  --> $DIR/collect-into-slice.rs:8:30
+  --> $DIR/collect-into-slice.rs:6:30
    |
 LL |     let some_generated_vec = (0..10).collect();
    |                              ^^^^^^^ ------- required by a bound introduced by this call
diff --git a/src/test/ui/late-bound-lifetimes/auxiliary/upstream_alias.rs b/src/test/ui/late-bound-lifetimes/auxiliary/upstream_alias.rs
new file mode 100644 (file)
index 0000000..5b9dc0e
--- /dev/null
@@ -0,0 +1,5 @@
+pub trait Trait<'a> {
+    type Assoc;
+}
+
+pub type Alias<'a, T> = <T as Trait<'a>>::Assoc;
diff --git a/src/test/ui/late-bound-lifetimes/cross_crate_alias.rs b/src/test/ui/late-bound-lifetimes/cross_crate_alias.rs
new file mode 100644 (file)
index 0000000..4154c27
--- /dev/null
@@ -0,0 +1,10 @@
+// aux-build:upstream_alias.rs
+// check-pass
+
+extern crate upstream_alias;
+
+fn foo<'a, T: for<'b> upstream_alias::Trait<'b>>(_: upstream_alias::Alias<'a, T>) -> &'a () {
+    todo!()
+}
+
+fn main() {}
diff --git a/src/test/ui/late-bound-lifetimes/downgraded_to_early_through_alias.rs b/src/test/ui/late-bound-lifetimes/downgraded_to_early_through_alias.rs
new file mode 100644 (file)
index 0000000..e56a342
--- /dev/null
@@ -0,0 +1,24 @@
+// check-pass
+
+trait Gats<'a> {
+    type Assoc;
+    type Assoc2;
+}
+
+trait Trait: for<'a> Gats<'a> {
+    fn foo<'a>(_: &mut <Self as Gats<'a>>::Assoc) -> <Self as Gats<'a>>::Assoc2;
+}
+
+impl<'a> Gats<'a> for () {
+    type Assoc = &'a u32;
+    type Assoc2 = ();
+}
+
+type GatsAssoc<'a, T> = <T as Gats<'a>>::Assoc;
+type GatsAssoc2<'a, T> = <T as Gats<'a>>::Assoc2;
+
+impl Trait for () {
+    fn foo<'a>(_: &mut GatsAssoc<'a, Self>) -> GatsAssoc2<'a, Self> {}
+}
+
+fn main() {}
diff --git a/src/test/ui/late-bound-lifetimes/issue-47511.rs b/src/test/ui/late-bound-lifetimes/issue-47511.rs
new file mode 100644 (file)
index 0000000..7894435
--- /dev/null
@@ -0,0 +1,21 @@
+// check-pass
+
+fn f(_: X) -> X {
+    unimplemented!()
+}
+
+fn g<'a>(_: X<'a>) -> X<'a> {
+    unimplemented!()
+}
+
+type X<'a> = <&'a () as Trait>::Value;
+
+trait Trait {
+    type Value;
+}
+
+impl<'a> Trait for &'a () {
+    type Value = ();
+}
+
+fn main() {}
diff --git a/src/test/ui/late-bound-lifetimes/late_bound_through_alias.rs b/src/test/ui/late-bound-lifetimes/late_bound_through_alias.rs
new file mode 100644 (file)
index 0000000..9183967
--- /dev/null
@@ -0,0 +1,16 @@
+// check-pass
+
+fn f(_: X) -> X {
+    unimplemented!()
+}
+
+fn g<'a>(_: X<'a>) -> X<'a> {
+    unimplemented!()
+}
+
+type X<'a> = &'a ();
+
+fn main() {
+    let _: for<'a> fn(X<'a>) -> X<'a> = g;
+    let _: for<'a> fn(X<'a>) -> X<'a> = f;
+}
diff --git a/src/test/ui/late-bound-lifetimes/mismatched_arg_count.rs b/src/test/ui/late-bound-lifetimes/mismatched_arg_count.rs
new file mode 100644 (file)
index 0000000..0b331e2
--- /dev/null
@@ -0,0 +1,12 @@
+// ensures that we don't ICE when there are too many args supplied to the alias.
+
+trait Trait<'a> {
+    type Assoc;
+}
+
+type Alias<'a, T> = <T as Trait<'a>>::Assoc;
+
+fn bar<'a, T: Trait<'a>>(_: Alias<'a, 'a, T>) {}
+//~^ error: this type alias takes 1 lifetime argument but 2 lifetime arguments were supplied
+
+fn main() {}
diff --git a/src/test/ui/late-bound-lifetimes/mismatched_arg_count.stderr b/src/test/ui/late-bound-lifetimes/mismatched_arg_count.stderr
new file mode 100644 (file)
index 0000000..3704d9b
--- /dev/null
@@ -0,0 +1,17 @@
+error[E0107]: this type alias takes 1 lifetime argument but 2 lifetime arguments were supplied
+  --> $DIR/mismatched_arg_count.rs:9:29
+   |
+LL | fn bar<'a, T: Trait<'a>>(_: Alias<'a, 'a, T>) {}
+   |                             ^^^^^     -- help: remove this lifetime argument
+   |                             |
+   |                             expected 1 lifetime argument
+   |
+note: type alias defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/mismatched_arg_count.rs:7:6
+   |
+LL | type Alias<'a, T> = <T as Trait<'a>>::Assoc;
+   |      ^^^^^ --
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0107`.
index bbf04c98436e8dd43c96080472079b4b26ce6ff1..987b051b11106e39441633aba255207af62543ce 100644 (file)
@@ -4,7 +4,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     let mut x = vec![1].iter();
    |                 ^^^^^^^       - temporary value is freed at the end of this statement
    |                 |
-   |                 creates a temporary which is freed while still in use
+   |                 creates a temporary value which is freed while still in use
 LL |
 LL |     x.use_mut();
    |     ----------- borrow later used here
index 2805720f035b8d78163352d7c32fcccf7fab2b11..657f23c60856fa04d3d4613da7bc2685b47ae671 100644 (file)
@@ -2,7 +2,7 @@ warning: unused return value of `need_to_use_this_value` that must be used
   --> $DIR/fn_must_use.rs:55:5
    |
 LL |     need_to_use_this_value();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: it's important
 note: the lint level is defined here
@@ -15,13 +15,13 @@ warning: unused return value of `MyStruct::need_to_use_this_method_value` that m
   --> $DIR/fn_must_use.rs:60:5
    |
 LL |     m.need_to_use_this_method_value();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused return value of `EvenNature::is_even` that must be used
   --> $DIR/fn_must_use.rs:61:5
    |
 LL |     m.is_even(); // trait method!
-   |     ^^^^^^^^^^^^
+   |     ^^^^^^^^^^^
    |
    = note: no side effects
 
@@ -29,19 +29,19 @@ warning: unused return value of `MyStruct::need_to_use_this_associated_function_
   --> $DIR/fn_must_use.rs:64:5
    |
 LL |     MyStruct::need_to_use_this_associated_function_value();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused return value of `std::cmp::PartialEq::eq` that must be used
   --> $DIR/fn_must_use.rs:70:5
    |
 LL |     2.eq(&3);
-   |     ^^^^^^^^^
+   |     ^^^^^^^^
 
 warning: unused return value of `std::cmp::PartialEq::eq` that must be used
   --> $DIR/fn_must_use.rs:71:5
    |
 LL |     m.eq(&n);
-   |     ^^^^^^^^^
+   |     ^^^^^^^^
 
 warning: unused comparison that must be used
   --> $DIR/fn_must_use.rs:74:5
diff --git a/src/test/ui/lint/issue-103435-extra-parentheses.fixed b/src/test/ui/lint/issue-103435-extra-parentheses.fixed
new file mode 100644 (file)
index 0000000..2b01b41
--- /dev/null
@@ -0,0 +1,18 @@
+// run-rustfix
+#![deny(unused_parens)]
+
+fn main() {
+    if let Some(_) = Some(1) {}
+    //~^ ERROR unnecessary parentheses around pattern
+
+    for _x in 1..10 {}
+    //~^ ERROR unnecessary parentheses around pattern
+
+    if 2 == 1 {}
+    //~^ ERROR unnecessary parentheses around `if` condition
+
+    // reported by parser
+    for _x in 1..10 {}
+    //~^ ERROR expected one of
+    //~| ERROR unexpected parentheses surrounding
+}
diff --git a/src/test/ui/lint/issue-103435-extra-parentheses.rs b/src/test/ui/lint/issue-103435-extra-parentheses.rs
new file mode 100644 (file)
index 0000000..8261610
--- /dev/null
@@ -0,0 +1,18 @@
+// run-rustfix
+#![deny(unused_parens)]
+
+fn main() {
+    if let(Some(_))= Some(1) {}
+    //~^ ERROR unnecessary parentheses around pattern
+
+    for(_x)in 1..10 {}
+    //~^ ERROR unnecessary parentheses around pattern
+
+    if(2 == 1){}
+    //~^ ERROR unnecessary parentheses around `if` condition
+
+    // reported by parser
+    for(_x in 1..10){}
+    //~^ ERROR expected one of
+    //~| ERROR unexpected parentheses surrounding
+}
diff --git a/src/test/ui/lint/issue-103435-extra-parentheses.stderr b/src/test/ui/lint/issue-103435-extra-parentheses.stderr
new file mode 100644 (file)
index 0000000..29c41c9
--- /dev/null
@@ -0,0 +1,61 @@
+error: expected one of `)`, `,`, `@`, or `|`, found keyword `in`
+  --> $DIR/issue-103435-extra-parentheses.rs:15:12
+   |
+LL |     for(_x in 1..10){}
+   |            ^^ expected one of `)`, `,`, `@`, or `|`
+
+error: unexpected parentheses surrounding `for` loop head
+  --> $DIR/issue-103435-extra-parentheses.rs:15:8
+   |
+LL |     for(_x in 1..10){}
+   |        ^           ^
+   |
+help: remove parentheses in `for` loop
+   |
+LL -     for(_x in 1..10){}
+LL +     for _x in 1..10 {}
+   |
+
+error: unnecessary parentheses around pattern
+  --> $DIR/issue-103435-extra-parentheses.rs:5:11
+   |
+LL |     if let(Some(_))= Some(1) {}
+   |           ^       ^
+   |
+note: the lint level is defined here
+  --> $DIR/issue-103435-extra-parentheses.rs:2:9
+   |
+LL | #![deny(unused_parens)]
+   |         ^^^^^^^^^^^^^
+help: remove these parentheses
+   |
+LL -     if let(Some(_))= Some(1) {}
+LL +     if let Some(_) = Some(1) {}
+   |
+
+error: unnecessary parentheses around pattern
+  --> $DIR/issue-103435-extra-parentheses.rs:8:8
+   |
+LL |     for(_x)in 1..10 {}
+   |        ^  ^
+   |
+help: remove these parentheses
+   |
+LL -     for(_x)in 1..10 {}
+LL +     for _x in 1..10 {}
+   |
+
+error: unnecessary parentheses around `if` condition
+  --> $DIR/issue-103435-extra-parentheses.rs:11:7
+   |
+LL |     if(2 == 1){}
+   |       ^      ^
+   |
+help: remove these parentheses
+   |
+LL -     if(2 == 1){}
+LL +     if 2 == 1 {}
+   |
+
+error: aborting due to 5 previous errors
+
index 011acc3bf5d6e98f85f78970b0fe1c5be36aec0a..72118275774d14b4d82747c4cb03297c3e89d54c 100644 (file)
@@ -2,7 +2,7 @@ warning: unused return value of `Box::<T>::from_raw` that must be used
   --> $DIR/must-use-box-from-raw.rs:8:5
    |
 LL |     Box::from_raw(ptr);
-   |     ^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^
    |
    = note: call `drop(from_raw(ptr))` if you intend to drop the `Box`
 note: the lint level is defined here
index 45a5317fccc6e7c508a901736ebc049da5e531fb..bba2b1ba078c694191d9734e10e2474e45de022c 100644 (file)
@@ -2,7 +2,7 @@ error: unused array of `S` that must be used
   --> $DIR/must_use-array.rs:39:5
    |
 LL |     singleton();
-   |     ^^^^^^^^^^^^
+   |     ^^^^^^^^^^^
    |
 note: the lint level is defined here
   --> $DIR/must_use-array.rs:1:9
@@ -14,7 +14,7 @@ error: unused array of `S` that must be used
   --> $DIR/must_use-array.rs:40:5
    |
 LL |     many();
-   |     ^^^^^^^
+   |     ^^^^^^
 
 error: unused array of `S` in tuple element 0 that must be used
   --> $DIR/must_use-array.rs:41:6
@@ -26,7 +26,7 @@ error: unused array of implementers of `T` that must be used
   --> $DIR/must_use-array.rs:42:5
    |
 LL |     array_of_impl_trait();
-   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^
 
 error: unused array of boxed `T` trait objects in tuple element 1 that must be used
   --> $DIR/must_use-array.rs:43:5
@@ -38,7 +38,7 @@ error: unused array of arrays of arrays of `S` that must be used
   --> $DIR/must_use-array.rs:45:5
    |
 LL |     array_of_arrays_of_arrays();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 6 previous errors
 
index f5199f43c74bd2e37784c5e8e00f723cec09d426..ef738708d5f4e56e1f54e85c57e979d6ff685e14 100644 (file)
@@ -2,7 +2,7 @@ error: unused implementer of `Iterator` that must be used
   --> $DIR/must_use-in-stdlib-traits.rs:42:4
    |
 LL |    iterator();
-   |    ^^^^^^^^^^^
+   |    ^^^^^^^^^^
    |
    = note: iterators are lazy and do nothing unless consumed
 note: the lint level is defined here
@@ -15,7 +15,7 @@ error: unused implementer of `Future` that must be used
   --> $DIR/must_use-in-stdlib-traits.rs:43:4
    |
 LL |    future();
-   |    ^^^^^^^^^
+   |    ^^^^^^^^
    |
    = note: futures do nothing unless you `.await` or poll them
 
@@ -23,7 +23,7 @@ error: unused implementer of `FnOnce` that must be used
   --> $DIR/must_use-in-stdlib-traits.rs:44:4
    |
 LL |    square_fn_once();
-   |    ^^^^^^^^^^^^^^^^^
+   |    ^^^^^^^^^^^^^^^^
    |
    = note: closures are lazy and do nothing unless called
 
@@ -31,7 +31,7 @@ error: unused implementer of `FnMut` that must be used
   --> $DIR/must_use-in-stdlib-traits.rs:45:4
    |
 LL |    square_fn_mut();
-   |    ^^^^^^^^^^^^^^^^
+   |    ^^^^^^^^^^^^^^^
    |
    = note: closures are lazy and do nothing unless called
 
@@ -39,7 +39,7 @@ error: unused implementer of `Fn` that must be used
   --> $DIR/must_use-in-stdlib-traits.rs:46:4
    |
 LL |    square_fn();
-   |    ^^^^^^^^^^^^
+   |    ^^^^^^^^^^^
    |
    = note: closures are lazy and do nothing unless called
 
index a42eb8841789dfb0f0071a4e1d2d65b833b877a1..2f54964848359a9d5e5327533fc0dee558420ed5 100644 (file)
@@ -2,7 +2,7 @@ error: unused implementer of `Critical` that must be used
   --> $DIR/must_use-trait.rs:33:5
    |
 LL |     get_critical();
-   |     ^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
   --> $DIR/must_use-trait.rs:1:9
@@ -14,13 +14,13 @@ error: unused boxed `Critical` trait object that must be used
   --> $DIR/must_use-trait.rs:34:5
    |
 LL |     get_boxed_critical();
-   |     ^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^
 
 error: unused boxed boxed `Critical` trait object that must be used
   --> $DIR/must_use-trait.rs:35:5
    |
 LL |     get_nested_boxed_critical();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: unused boxed `Critical` trait object in tuple element 1 that must be used
   --> $DIR/must_use-trait.rs:37:5
index 7f25a19350862db0ea1d156626e4f32599e03927..9fcbc5074ea800ae4d1209e430afb2fe772dc1f5 100644 (file)
@@ -2,7 +2,7 @@ error: unused return value of `foo` that must be used
   --> $DIR/must_use-unit.rs:13:5
    |
 LL |     foo();
-   |     ^^^^^^
+   |     ^^^^^
    |
 note: the lint level is defined here
   --> $DIR/must_use-unit.rs:2:9
@@ -14,7 +14,7 @@ error: unused return value of `bar` that must be used
   --> $DIR/must_use-unit.rs:15:5
    |
 LL |     bar();
-   |     ^^^^^^
+   |     ^^^^^
 
 error: aborting due to 2 previous errors
 
index 7d17af11573796bbf61e7c8cd5e61dbc05fbd0c3..4be93aa155ad9097f0e35326ae0b2dd013caae87 100644 (file)
@@ -1,24 +1,43 @@
 // edition:2018
-// run-pass
-#![allow(dead_code)]
+#![deny(unused_must_use)]
+
 
 #[must_use]
-//~^ WARNING `must_use`
-async fn test() -> i32 {
+async fn foo() -> i32 {
     1
 }
 
+#[must_use]
+fn bar() -> impl std::future::Future<Output=i32> {
+    async {
+        42
+    }
+}
+
+async fn baz() -> i32 {
+    0
+}
 
 struct Wowee {}
 
 impl Wowee {
     #[must_use]
-    //~^ WARNING `must_use`
     async fn test_method() -> i32 {
         1
     }
 }
 
+async fn test() {
+    foo(); //~ ERROR unused return value of `foo` that must be used
+    //~^ ERROR unused implementer of `Future` that must be used
+    foo().await; //~ ERROR unused output of future returned by `foo` that must be used
+    bar(); //~ ERROR unused return value of `bar` that must be used
+    //~^ ERROR unused implementer of `Future` that must be used
+    bar().await; //~ ERROR unused output of future returned by `bar` that must be used
+    baz(); //~ ERROR unused implementer of `Future` that must be used
+    baz().await; // ok
+}
+
 /* FIXME(guswynn) update this test when async-fn-in-traits works
 trait Doer {
     #[must_use]
index 6bbc9e2bf00885e0e29534184371d8d7dc4fd74c..4bcb26dc16586a38f3898fa8df4032af493b0271 100644 (file)
@@ -1,26 +1,55 @@
-warning: `must_use` attribute on `async` functions applies to the anonymous `Future` returned by the function, not the value within
-  --> $DIR/unused-async.rs:5:1
-   |
-LL |   #[must_use]
-   |   ^^^^^^^^^^^
-LL |
-LL | / async fn test() -> i32 {
-LL | |     1
-LL | | }
-   | |_- this attribute does nothing, the `Future`s returned by async functions are already `must_use`
-   |
-   = note: `#[warn(unused_attributes)]` on by default
-
-warning: `must_use` attribute on `async` functions applies to the anonymous `Future` returned by the function, not the value within
-  --> $DIR/unused-async.rs:15:5
-   |
-LL |       #[must_use]
-   |       ^^^^^^^^^^^
-LL |
-LL | /     async fn test_method() -> i32 {
-LL | |         1
-LL | |     }
-   | |_____- this attribute does nothing, the `Future`s returned by async functions are already `must_use`
-
-warning: 2 warnings emitted
+error: unused implementer of `Future` that must be used
+  --> $DIR/unused-async.rs:31:5
+   |
+LL |     foo();
+   |     ^^^^^
+   |
+   = note: futures do nothing unless you `.await` or poll them
+note: the lint level is defined here
+  --> $DIR/unused-async.rs:2:9
+   |
+LL | #![deny(unused_must_use)]
+   |         ^^^^^^^^^^^^^^^
+
+error: unused return value of `foo` that must be used
+  --> $DIR/unused-async.rs:31:5
+   |
+LL |     foo();
+   |     ^^^^^
+
+error: unused output of future returned by `foo` that must be used
+  --> $DIR/unused-async.rs:33:5
+   |
+LL |     foo().await;
+   |     ^^^^^^^^^^^
+
+error: unused implementer of `Future` that must be used
+  --> $DIR/unused-async.rs:34:5
+   |
+LL |     bar();
+   |     ^^^^^
+   |
+   = note: futures do nothing unless you `.await` or poll them
+
+error: unused return value of `bar` that must be used
+  --> $DIR/unused-async.rs:34:5
+   |
+LL |     bar();
+   |     ^^^^^
+
+error: unused output of future returned by `bar` that must be used
+  --> $DIR/unused-async.rs:36:5
+   |
+LL |     bar().await;
+   |     ^^^^^^^^^^^
+
+error: unused implementer of `Future` that must be used
+  --> $DIR/unused-async.rs:37:5
+   |
+LL |     baz();
+   |     ^^^^^
+   |
+   = note: futures do nothing unless you `.await` or poll them
+
+error: aborting due to 7 previous errors
 
index 4362abd2037fff69785d78f3e52180ef5c6271c7..c3a82402e0a2e516fcce7811186e438a16b58104 100644 (file)
@@ -4,7 +4,7 @@ error: unused closure that must be used
 LL | /     || {
 LL | |         println!("Hello!");
 LL | |     };
-   | |______^
+   | |_____^
    |
    = note: closures are lazy and do nothing unless called
 note: the lint level is defined here
@@ -17,7 +17,7 @@ error: unused implementer of `Future` that must be used
   --> $DIR/unused-closure.rs:13:5
    |
 LL |     async {};
-   |     ^^^^^^^^^
+   |     ^^^^^^^^
    |
    = note: futures do nothing unless you `.await` or poll them
 
@@ -25,7 +25,7 @@ error: unused closure that must be used
   --> $DIR/unused-closure.rs:14:5
    |
 LL |     || async {};
-   |     ^^^^^^^^^^^^
+   |     ^^^^^^^^^^^
    |
    = note: closures are lazy and do nothing unless called
 
@@ -33,7 +33,7 @@ error: unused closure that must be used
   --> $DIR/unused-closure.rs:15:5
    |
 LL |     async || {};
-   |     ^^^^^^^^^^^^
+   |     ^^^^^^^^^^^
    |
    = note: closures are lazy and do nothing unless called
 
@@ -41,7 +41,7 @@ error: unused array of boxed arrays of closures that must be used
   --> $DIR/unused-closure.rs:18:5
    |
 LL |     [Box::new([|| {}; 10]); 1];
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: closures are lazy and do nothing unless called
 
@@ -49,7 +49,7 @@ error: unused closure that must be used
   --> $DIR/unused-closure.rs:20:5
    |
 LL |     vec![|| "a"].pop().unwrap();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: closures are lazy and do nothing unless called
 
@@ -57,7 +57,7 @@ error: unused closure that must be used
   --> $DIR/unused-closure.rs:23:9
    |
 LL |         || true;
-   |         ^^^^^^^^
+   |         ^^^^^^^
    |
    = note: closures are lazy and do nothing unless called
 
index 087e06341cdde2dd4a906aef27db31a3bcba8767..4e1ba1fd9595fd5bdb37fe40edae1005ee2fb7ea 100644 (file)
@@ -2,7 +2,7 @@ error: unused `MustUse` that must be used
   --> $DIR/unused-result.rs:21:5
    |
 LL |     foo::<MustUse>();
-   |     ^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
   --> $DIR/unused-result.rs:2:25
@@ -14,7 +14,7 @@ error: unused `MustUseMsg` that must be used
   --> $DIR/unused-result.rs:22:5
    |
 LL |     foo::<MustUseMsg>();
-   |     ^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^
    |
    = note: some message
 
@@ -34,13 +34,13 @@ error: unused `MustUse` that must be used
   --> $DIR/unused-result.rs:35:5
    |
 LL |     foo::<MustUse>();
-   |     ^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^
 
 error: unused `MustUseMsg` that must be used
   --> $DIR/unused-result.rs:36:5
    |
 LL |     foo::<MustUseMsg>();
-   |     ^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^
    |
    = note: some message
 
index d2f8c0078481772043877e24c2d25be388e30c3f..cb45add9c2b1ba13886f43ecdbe3c790f8fc6df5 100644 (file)
@@ -2,7 +2,7 @@ error: unused implementer of `Iterator` that must be used
   --> $DIR/unused-supertrait.rs:9:5
    |
 LL |     it();
-   |     ^^^^^
+   |     ^^^^
    |
    = note: iterators are lazy and do nothing unless consumed
 note: the lint level is defined here
index ce959ddbc469703915181b4b6bf71d857a622445..0f699429e02437fd2c0dbf4cc2be76bb59bf2699 100644 (file)
@@ -139,7 +139,7 @@ error: unused `X` that must be used
   --> $DIR/unused_attributes-must_use.rs:103:5
    |
 LL |     X;
-   |     ^^
+   |     ^
    |
 note: the lint level is defined here
   --> $DIR/unused_attributes-must_use.rs:2:28
@@ -151,37 +151,37 @@ error: unused `Y` that must be used
   --> $DIR/unused_attributes-must_use.rs:104:5
    |
 LL |     Y::Z;
-   |     ^^^^^
+   |     ^^^^
 
 error: unused `U` that must be used
   --> $DIR/unused_attributes-must_use.rs:105:5
    |
 LL |     U { unit: () };
-   |     ^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^
 
 error: unused return value of `U::method` that must be used
   --> $DIR/unused_attributes-must_use.rs:106:5
    |
 LL |     U::method();
-   |     ^^^^^^^^^^^^
+   |     ^^^^^^^^^^^
 
 error: unused return value of `foo` that must be used
   --> $DIR/unused_attributes-must_use.rs:107:5
    |
 LL |     foo();
-   |     ^^^^^^
+   |     ^^^^^
 
 error: unused return value of `foreign_foo` that must be used
   --> $DIR/unused_attributes-must_use.rs:110:9
    |
 LL |         foreign_foo();
-   |         ^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^
 
 error: unused return value of `Use::get_four` that must be used
   --> $DIR/unused_attributes-must_use.rs:118:5
    |
 LL |     ().get_four();
-   |     ^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^
 
 error: aborting due to 28 previous errors
 
diff --git a/src/test/ui/match/issue-12552.rs b/src/test/ui/match/issue-12552.rs
new file mode 100644 (file)
index 0000000..b7f71dd
--- /dev/null
@@ -0,0 +1,11 @@
+// this code used to cause an ICE
+
+fn main() {
+  let t = Err(0);
+  match t {
+    Some(k) => match k { //~ ERROR mismatched types
+      a => println!("{}", a)
+    },
+    None => () //~ ERROR mismatched types
+  }
+}
diff --git a/src/test/ui/match/issue-12552.stderr b/src/test/ui/match/issue-12552.stderr
new file mode 100644 (file)
index 0000000..4b027eb
--- /dev/null
@@ -0,0 +1,34 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-12552.rs:6:5
+   |
+LL |   match t {
+   |         - this expression has type `Result<_, {integer}>`
+LL |     Some(k) => match k {
+   |     ^^^^^^^ expected enum `Result`, found enum `Option`
+   |
+   = note: expected enum `Result<_, {integer}>`
+              found enum `Option<_>`
+help: try wrapping the pattern in `Ok`
+   |
+LL |     Ok(Some(k)) => match k {
+   |     +++       +
+
+error[E0308]: mismatched types
+  --> $DIR/issue-12552.rs:9:5
+   |
+LL |   match t {
+   |         - this expression has type `Result<_, {integer}>`
+...
+LL |     None => ()
+   |     ^^^^ expected enum `Result`, found enum `Option`
+   |
+   = note: expected enum `Result<_, {integer}>`
+              found enum `Option<_>`
+help: try wrapping the pattern in `Ok`
+   |
+LL |     Ok(None) => ()
+   |     +++    +
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/never_type/exhaustive_patterns.rs b/src/test/ui/never_type/exhaustive_patterns.rs
new file mode 100644 (file)
index 0000000..2e23fa1
--- /dev/null
@@ -0,0 +1,21 @@
+// check-fail
+// known-bug: #104034
+
+#![feature(exhaustive_patterns, never_type)]
+
+mod inner {
+    pub struct Wrapper<T>(T);
+}
+
+enum Either<A, B> {
+    A(A),
+    B(inner::Wrapper<B>),
+}
+
+fn foo() -> Either<(), !> {
+    Either::A(())
+}
+
+fn main() {
+    let Either::A(()) = foo();
+}
diff --git a/src/test/ui/never_type/exhaustive_patterns.stderr b/src/test/ui/never_type/exhaustive_patterns.stderr
new file mode 100644 (file)
index 0000000..e41baf8
--- /dev/null
@@ -0,0 +1,25 @@
+error[E0005]: refutable pattern in local binding: `Either::B(_)` not covered
+  --> $DIR/exhaustive_patterns.rs:20:9
+   |
+LL |     let Either::A(()) = foo();
+   |         ^^^^^^^^^^^^^ pattern `Either::B(_)` not covered
+   |
+   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
+   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `Either<(), !>` defined here
+  --> $DIR/exhaustive_patterns.rs:12:5
+   |
+LL | enum Either<A, B> {
+   |      ------
+LL |     A(A),
+LL |     B(inner::Wrapper<B>),
+   |     ^ not covered
+   = note: the matched value is of type `Either<(), !>`
+help: you might want to use `if let` to ignore the variant that isn't matched
+   |
+LL |     if let Either::A(()) = foo() { todo!() }
+   |     ++                           ~~~~~~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0005`.
index 2c6bd92641f608c7e7947ef2d410de46deb4f6ce..89781d96fab2624fbceac3df99b8e614a7b31893 100644 (file)
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/borrowed-temporary-error.rs:8:10
    |
 LL |         &(v,)
-   |          ^^^^ creates a temporary which is freed while still in use
+   |          ^^^^ creates a temporary value which is freed while still in use
 LL |
 LL |     });
    |       - temporary value is freed at the end of this statement
index d2d26b23d646e74380c740c66bd393c62e0874bd..363ddfaffe06e021ca517c62ac7b8282be8e2c0b 100644 (file)
@@ -6,7 +6,7 @@ LL |         let mut closure = expect_sig(|p, y| *p = y);
    |
    = note: defining type: test::{closure#0} with closure substs [
                i16,
-               for<'a, 'b, 'c> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('a) }) mut &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) i32, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrNamed('c) }) i32)),
+               for<Region(BrAnon(0, None)), Region(BrAnon(1, None)), Region(BrAnon(2, None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) mut &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) i32, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(2, None) }) i32)),
                (),
            ]
 
index 6355d3295247f3cc6ac630d680c82bb820cdce59..f67c312b946883a486655688f21717605e098567 100644 (file)
@@ -6,7 +6,7 @@ LL |         let mut closure = expect_sig(|p, y| *p = y);
    |
    = note: defining type: test::{closure#0} with closure substs [
                i16,
-               for<'a, 'b> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('a) }) mut &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) i32, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) i32)),
+               for<Region(BrAnon(0, None)), Region(BrAnon(1, None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) mut &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) i32, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) i32)),
                (),
            ]
 
index 5f9724ce3db19c968fdfb24642c35d318a5e2e03..7da6ce58bf7fc6cbc10ffdbfa1509c73b33fc5f7 100644 (file)
@@ -6,7 +6,7 @@ LL |         |_outlives1, _outlives2, _outlives3, x, y| {
    |
    = note: defining type: supply::{closure#0} with closure substs [
                i16,
-               for<'a, 'b> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('a) }) u32>, std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('a) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) &'_#3r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('a) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) u32>)),
+               for<Region(BrAnon(0, None)), Region(BrAnon(1, None))> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) u32>, std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) &'_#3r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>)),
                (),
            ]
    = note: late-bound region is '_#4r
index ec728ebd5adf53d16c7a0d2145f7de72838aeaec..993687605c4afca610c7d6efb1a7d11d3cca872c 100644 (file)
@@ -6,7 +6,7 @@ LL |     establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y
    |
    = note: defining type: supply::{closure#0} with closure substs [
                i16,
-               for<'a, 'b, 'c, 'd, 'e, 'f> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('a) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrNamed('c) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrNamed('d) }) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrNamed('e) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 5, kind: BrNamed('f) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrNamed('d) }) u32>)),
+               for<Region(BrAnon(0, None)), Region(BrAnon(1, None)), Region(BrAnon(2, None)), Region(BrAnon(3, None)), Region(BrAnon(4, None)), Region(BrAnon(5, None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(2, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(3, None) }) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(4, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 5, kind: BrAnon(5, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(3, None) }) u32>)),
                (),
            ]
    = note: late-bound region is '_#3r
index 01293379700d28ca717a24e470761d8fff529851..7991abeb7a800d72a6e04c0e4ef402911420492c 100644 (file)
@@ -6,7 +6,7 @@ LL |     foo(cell, |cell_a, cell_x| {
    |
    = note: defining type: case1::{closure#0} with closure substs [
                i32,
-               for<'a> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('a) }) u32>)),
+               for<Region(BrAnon(0, None))> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) u32>)),
                (),
            ]
 
@@ -36,7 +36,7 @@ LL |     foo(cell, |cell_a, cell_x| {
    |
    = note: defining type: case2::{closure#0} with closure substs [
                i32,
-               for<'a> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('a) }) u32>)),
+               for<Region(BrAnon(0, None))> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) u32>)),
                (),
            ]
    = note: number of external vids: 2
index ce85b20b344e24bc4024c9473829590843f32d60..43dfc3bb9f83550a74633386a96f166ed33059cd 100644 (file)
@@ -6,7 +6,7 @@ LL |     establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
    |
    = note: defining type: supply::{closure#0} with closure substs [
                i16,
-               for<'a, 'b, 'c, 'd, 'e> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('a) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrNamed('c) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrNamed('d) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrNamed('e) }) u32>)),
+               for<Region(BrAnon(0, None)), Region(BrAnon(1, None)), Region(BrAnon(2, None)), Region(BrAnon(3, None)), Region(BrAnon(4, None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(2, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(3, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(4, None) }) u32>)),
                (),
            ]
    = note: late-bound region is '_#2r
index 20c7967b78bc95658f4eb61b682724bff9a63594..96c734226eff9857d3ba20dc4cdc1e2315574292 100644 (file)
@@ -6,7 +6,7 @@ LL |     establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y
    |
    = note: defining type: supply::{closure#0} with closure substs [
                i16,
-               for<'a, 'b, 'c, 'd, 'e, 'f> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('a) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrNamed('c) }) std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrNamed('d) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrNamed('e) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 5, kind: BrNamed('f) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrNamed('d) }) u32>)),
+               for<Region(BrAnon(0, None)), Region(BrAnon(1, None)), Region(BrAnon(2, None)), Region(BrAnon(3, None)), Region(BrAnon(4, None)), Region(BrAnon(5, None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(2, None) }) std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(3, None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(4, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 5, kind: BrAnon(5, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(3, None) }) u32>)),
                (),
            ]
    = note: late-bound region is '_#3r
index f7db5ab1f27a0ae53474b1f7b9687df184a23b36..03dbd686e4976274fafcce9c9d1d77363c05d7e6 100644 (file)
@@ -6,7 +6,7 @@ LL |     establish_relationships(cell_a, cell_b, |outlives1, outlives2, x, y| {
    |
    = note: defining type: test::{closure#0} with closure substs [
                i16,
-               for<'a, 'b> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('a) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('a) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) u32>)),
+               for<Region(BrAnon(0, None)), Region(BrAnon(1, None))> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>)),
                (),
            ]
    = note: late-bound region is '_#3r
index 3488edc75e10288b7980dd3cd09d650ac1b9e6f3..d716d3de2a115fc1b21d397ac7bbf8ae8122f089 100644 (file)
@@ -6,7 +6,7 @@ LL |         |_outlives1, _outlives2, x, y| {
    |
    = note: defining type: supply::{closure#0} with closure substs [
                i16,
-               for<'a, 'b> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('a) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('a) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) u32>)),
+               for<Region(BrAnon(0, None)), Region(BrAnon(1, None))> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>)),
                (),
            ]
    = note: late-bound region is '_#3r
index 0dc2d0de98fe7e62f370bd329c425d9de3006b69..b924873fca6f0d84a2e23ce0cf22462b021b026d 100644 (file)
@@ -6,7 +6,7 @@ LL |     establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
    |
    = note: defining type: supply::{closure#0} with closure substs [
                i16,
-               for<'a, 'b, 'c, 'd, 'e> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('a) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrNamed('c) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrNamed('d) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrNamed('e) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) u32>)),
+               for<Region(BrAnon(0, None)), Region(BrAnon(1, None)), Region(BrAnon(2, None)), Region(BrAnon(3, None)), Region(BrAnon(4, None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(2, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(3, None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(4, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>)),
                (),
            ]
    = note: late-bound region is '_#2r
index 4c9e026ea522ce8284998560eba72f5c0f59ef88..9b25efd0b66b1c28500ba59b28adcb246d7377e1 100644 (file)
@@ -6,7 +6,7 @@ LL |     establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y
    |
    = note: defining type: supply::{closure#0} with closure substs [
                i16,
-               for<'a, 'b, 'c, 'd, 'e, 'f> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('a) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrNamed('c) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrNamed('d) }) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrNamed('e) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 5, kind: BrNamed('f) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrNamed('d) }) u32>)),
+               for<Region(BrAnon(0, None)), Region(BrAnon(1, None)), Region(BrAnon(2, None)), Region(BrAnon(3, None)), Region(BrAnon(4, None)), Region(BrAnon(5, None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(2, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(3, None) }) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(4, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 5, kind: BrAnon(5, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(3, None) }) u32>)),
                (),
            ]
    = note: late-bound region is '_#3r
index 68429142edecd2dd6bc1dfedbaa3f8631f7f21f2..6db72b8863258fbf77b32a9ef4e72ba8275bfcdb 100644 (file)
@@ -6,7 +6,7 @@ LL |     expect_sig(|a, b| b); // ought to return `a`
    |
    = note: defining type: test::{closure#0} with closure substs [
                i16,
-               for<'a, 'b> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('a) }) i32, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) i32)) -> &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('a) }) i32,
+               for<Region(BrAnon(0, None)), Region(BrAnon(1, None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) i32, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) i32)) -> &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) i32,
                (),
            ]
 
index 1b35165db45dca1efc32e148bc3d5270e27c58f6..bfdfca2100406ccd6c76a4b30f8377f1f676bb5c 100644 (file)
@@ -2,7 +2,7 @@ warning: unused generator that must be used
   --> $DIR/issue-48623-generator.rs:15:5
    |
 LL |     move || { d; yield; &mut *r };
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: generators are lazy and do nothing unless resumed
    = note: `#[warn(unused_must_use)]` on by default
diff --git a/src/test/ui/nll/issue-54943.rs b/src/test/ui/nll/issue-54943.rs
new file mode 100644 (file)
index 0000000..8572230
--- /dev/null
@@ -0,0 +1,10 @@
+fn foo<T: 'static>() { }
+
+fn boo<'a>() {
+    return;
+
+    let x = foo::<&'a u32>();
+    //~^ ERROR
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/issue-54943.stderr b/src/test/ui/nll/issue-54943.stderr
new file mode 100644 (file)
index 0000000..59be0f9
--- /dev/null
@@ -0,0 +1,11 @@
+error: lifetime may not live long enough
+  --> $DIR/issue-54943.rs:6:13
+   |
+LL | fn boo<'a>() {
+   |        -- lifetime `'a` defined here
+...
+LL |     let x = foo::<&'a u32>();
+   |             ^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
index 20add62b91ddf19268958d33985f06cb506673c1..bb45575fa64c3ae6f1e50494d378029224b5b731 100644 (file)
@@ -4,7 +4,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     let (_, z) = foo(&"hello".to_string());
    |                  -----^^^^^^^^^^^^^^^^^^^-- temporary value is freed at the end of this statement
    |                  |    |
-   |                  |    creates a temporary which is freed while still in use
+   |                  |    creates a temporary value which is freed while still in use
    |                  argument requires that borrow lasts for `'static`
 
 error: aborting due to previous error
index f316a551cffa69543a0d779222a8b56f23cae16d..a442cf12d820e4fb87dddb29ece09ccb95102ace 100644 (file)
@@ -6,7 +6,7 @@ LL |     twice(cell, value, |a, b| invoke(a, b));
    |
    = note: defining type: generic::<T>::{closure#0} with closure substs [
                i16,
-               for<'a, 'b> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('a) }) ()>>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) T)),
+               for<Region(BrAnon(0, None)), Region(BrAnon(1, None))> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) ()>>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) T)),
                (),
            ]
    = note: number of external vids: 2
@@ -28,7 +28,7 @@ LL |     twice(cell, value, |a, b| invoke(a, b));
    |
    = note: defining type: generic_fail::<T>::{closure#0} with closure substs [
                i16,
-               for<'a, 'b> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('a) }) ()>>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) T)),
+               for<Region(BrAnon(0, None)), Region(BrAnon(1, None))> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) ()>>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) T)),
                (),
            ]
    = note: late-bound region is '_#2r
diff --git a/src/test/ui/nll/user-annotations/ascribed-type-wf.rs b/src/test/ui/nll/user-annotations/ascribed-type-wf.rs
new file mode 100644 (file)
index 0000000..14460de
--- /dev/null
@@ -0,0 +1,16 @@
+// check-pass
+// known-bug: #101350
+
+trait Trait {
+    type Ty;
+}
+
+impl Trait for &'static () {
+    type Ty = ();
+}
+
+fn extend<'a>() {
+    None::<<&'a () as Trait>::Ty>;
+}
+
+fn main() {}
index 60d6e6db36326daa6798b82ace8303b01e81531a..de6f8f80fe25248bcac3e425fcd37b9e639fa7fb 100644 (file)
@@ -76,7 +76,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     let _: Vec<&'static String> = vec![&String::new()];
    |            --------------------         ^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
    |            |                            |
-   |            |                            creates a temporary which is freed while still in use
+   |            |                            creates a temporary value which is freed while still in use
    |            type annotation requires that borrow lasts for `'static`
 
 error[E0716]: temporary value dropped while borrowed
@@ -85,7 +85,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     let (_, a): (Vec<&'static String>, _) = (vec![&String::new()], 44);
    |                 -------------------------          ^^^^^^^^^^^^^      - temporary value is freed at the end of this statement
    |                 |                                  |
-   |                 |                                  creates a temporary which is freed while still in use
+   |                 |                                  creates a temporary value which is freed while still in use
    |                 type annotation requires that borrow lasts for `'static`
 
 error[E0716]: temporary value dropped while borrowed
@@ -94,7 +94,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     let (_a, b): (Vec<&'static String>, _) = (vec![&String::new()], 44);
    |                  -------------------------          ^^^^^^^^^^^^^      - temporary value is freed at the end of this statement
    |                  |                                  |
-   |                  |                                  creates a temporary which is freed while still in use
+   |                  |                                  creates a temporary value which is freed while still in use
    |                  type annotation requires that borrow lasts for `'static`
 
 error[E0597]: `x` does not live long enough
index 05a510b24a7aba188168690f68c98723bd54071e..896dc1a1a5fba5821ef54705062b87d5a6214f03 100644 (file)
@@ -7,6 +7,6 @@ pub fn main() {
     b'\x0Z';  //~ ERROR invalid character in numeric character escape: `Z`
     b' ';  //~ ERROR byte constant must be escaped
     b''';  //~ ERROR byte constant must be escaped
-    b'é';  //~ ERROR non-ASCII character in byte constant
+    b'é';  //~ ERROR non-ASCII character in byte literal
     b'a  //~ ERROR unterminated byte constant [E0763]
 }
index c3d0006163005def230f0e33aa52c9735598da5e..efa55ae05bd37b6ac506af989d517eaf4837e57a 100644 (file)
@@ -32,11 +32,11 @@ error: byte constant must be escaped: `'`
 LL |     b''';
    |       ^ help: escape the character: `\'`
 
-error: non-ASCII character in byte constant
+error: non-ASCII character in byte literal
   --> $DIR/byte-literals.rs:10:7
    |
 LL |     b'é';
-   |       ^ byte constant must be ASCII
+   |       ^ must be ASCII
    |
 help: if you meant to use the unicode code point for 'é', use a \xHH escape
    |
index b1f11024a7bb6cdcd5bad76e2311a085b3a82b18..30a4f50c4e40b694cb5152627f0a1987c814dd5f 100644 (file)
@@ -3,7 +3,7 @@
 pub fn main() {
     b"\f";  //~ ERROR unknown byte escape
     b"\x0Z";  //~ ERROR invalid character in numeric character escape: `Z`
-    b"é";  //~ ERROR non-ASCII character in byte constant
-    br##"é"##;  //~ ERROR raw byte string must be ASCII
+    b"é";  //~ ERROR non-ASCII character in byte string literal
+    br##"é"##;  //~ ERROR non-ASCII character in raw byte string literal
     b"a  //~ ERROR unterminated double quote byte string
 }
index 3b8b3692e053f0fa9fa83133705875f43535a5fe..5b96cc3d18abc37332f5ce9648d3dd9f844513b8 100644 (file)
@@ -20,18 +20,18 @@ error: invalid character in numeric character escape: `Z`
 LL |     b"\x0Z";
    |          ^ invalid character in numeric character escape
 
-error: non-ASCII character in byte constant
+error: non-ASCII character in byte string literal
   --> $DIR/byte-string-literals.rs:6:7
    |
 LL |     b"é";
-   |       ^ byte constant must be ASCII
+   |       ^ must be ASCII
    |
 help: if you meant to use the unicode code point for 'é', use a \xHH escape
    |
 LL |     b"\xE9";
    |       ~~~~
 
-error: raw byte string must be ASCII
+error: non-ASCII character in raw byte string literal
   --> $DIR/byte-string-literals.rs:7:10
    |
 LL |     br##"é"##;
diff --git a/src/test/ui/parser/issue-103451.rs b/src/test/ui/parser/issue-103451.rs
new file mode 100644 (file)
index 0000000..1fdb001
--- /dev/null
@@ -0,0 +1,5 @@
+// error-pattern: this file contains an unclosed delimiter
+// error-pattern: expected value, found struct `R`
+struct R { }
+struct S {
+    x: [u8; R
diff --git a/src/test/ui/parser/issue-103451.stderr b/src/test/ui/parser/issue-103451.stderr
new file mode 100644 (file)
index 0000000..eb3c92f
--- /dev/null
@@ -0,0 +1,32 @@
+error: this file contains an unclosed delimiter
+  --> $DIR/issue-103451.rs:5:15
+   |
+LL | struct S {
+   |          - unclosed delimiter
+LL |     x: [u8; R
+   |        -      ^
+   |        |
+   |        unclosed delimiter
+
+error: this file contains an unclosed delimiter
+  --> $DIR/issue-103451.rs:5:15
+   |
+LL | struct S {
+   |          - unclosed delimiter
+LL |     x: [u8; R
+   |        -      ^
+   |        |
+   |        unclosed delimiter
+
+error[E0423]: expected value, found struct `R`
+  --> $DIR/issue-103451.rs:5:13
+   |
+LL | struct R { }
+   | ------------ `R` defined here
+LL | struct S {
+LL |     x: [u8; R
+   |             ^ help: use struct literal syntax instead: `R {}`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0423`.
diff --git a/src/test/ui/parser/issue-103748-ICE-wrong-braces.rs b/src/test/ui/parser/issue-103748-ICE-wrong-braces.rs
new file mode 100644 (file)
index 0000000..8012cb6
--- /dev/null
@@ -0,0 +1,8 @@
+#![crate_type = "lib"]
+
+struct Apple((Apple, Option(Banana ? Citron)));
+//~^ ERROR invalid `?` in type
+//~| ERROR expected one of `)` or `,`, found `Citron`
+//~| ERROR cannot find type `Citron` in this scope [E0412]
+//~| ERROR parenthesized type parameters may only be used with a `Fn` trait [E0214]
+//~| ERROR recursive type `Apple` has infinite size [E0072]
diff --git a/src/test/ui/parser/issue-103748-ICE-wrong-braces.stderr b/src/test/ui/parser/issue-103748-ICE-wrong-braces.stderr
new file mode 100644 (file)
index 0000000..b0d8b03
--- /dev/null
@@ -0,0 +1,51 @@
+error: invalid `?` in type
+  --> $DIR/issue-103748-ICE-wrong-braces.rs:3:36
+   |
+LL | struct Apple((Apple, Option(Banana ? Citron)));
+   |                                    ^ `?` is only allowed on expressions, not types
+   |
+help: if you meant to express that the type might not contain a value, use the `Option` wrapper type
+   |
+LL | struct Apple((Apple, Option(Option<Banana > Citron)));
+   |                             +++++++       ~
+
+error: expected one of `)` or `,`, found `Citron`
+  --> $DIR/issue-103748-ICE-wrong-braces.rs:3:38
+   |
+LL | struct Apple((Apple, Option(Banana ? Citron)));
+   |                                     -^^^^^^ expected one of `)` or `,`
+   |                                     |
+   |                                     help: missing `,`
+
+error[E0412]: cannot find type `Citron` in this scope
+  --> $DIR/issue-103748-ICE-wrong-braces.rs:3:38
+   |
+LL | struct Apple((Apple, Option(Banana ? Citron)));
+   |                                      ^^^^^^ not found in this scope
+
+error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
+  --> $DIR/issue-103748-ICE-wrong-braces.rs:3:22
+   |
+LL | struct Apple((Apple, Option(Banana ? Citron)));
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^ only `Fn` traits may use parentheses
+   |
+help: use angle brackets instead
+   |
+LL | struct Apple((Apple, Option<Banana ? Citron>));
+   |                            ~               ~
+
+error[E0072]: recursive type `Apple` has infinite size
+  --> $DIR/issue-103748-ICE-wrong-braces.rs:3:1
+   |
+LL | struct Apple((Apple, Option(Banana ? Citron)));
+   | ^^^^^^^^^^^^  ----- recursive without indirection
+   |
+help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
+   |
+LL | struct Apple((Box<Apple>, Option(Banana ? Citron)));
+   |               ++++     +
+
+error: aborting due to 5 previous errors
+
+Some errors have detailed explanations: E0072, E0214, E0412.
+For more information about an error, try `rustc --explain E0072`.
diff --git a/src/test/ui/parser/item-kw-case-mismatch.fixed b/src/test/ui/parser/item-kw-case-mismatch.fixed
new file mode 100644 (file)
index 0000000..1794268
--- /dev/null
@@ -0,0 +1,34 @@
+// run-rustfix
+// edition:2018
+#![allow(unused_imports)]
+
+fn main() {}
+
+use std::ptr::read;  //~ ERROR keyword `use` is written in a wrong case
+use std::ptr::write; //~ ERROR keyword `use` is written in a wrong case
+
+async fn _a() {}
+//~^ ERROR keyword `fn` is written in a wrong case
+
+fn _b() {}
+//~^ ERROR keyword `fn` is written in a wrong case
+
+async fn _c() {}
+//~^ ERROR keyword `async` is written in a wrong case
+//~| ERROR keyword `fn` is written in a wrong case
+
+async fn _d() {}
+//~^ ERROR keyword `async` is written in a wrong case
+
+const unsafe fn _e() {}
+//~^ ERROR keyword `const` is written in a wrong case
+//~| ERROR keyword `unsafe` is written in a wrong case
+//~| ERROR keyword `fn` is written in a wrong case
+
+unsafe extern fn _f() {}
+//~^ ERROR keyword `unsafe` is written in a wrong case
+//~| ERROR keyword `extern` is written in a wrong case
+
+extern "C" fn _g() {}
+//~^ ERROR keyword `extern` is written in a wrong case
+//~| ERROR keyword `fn` is written in a wrong case
diff --git a/src/test/ui/parser/item-kw-case-mismatch.rs b/src/test/ui/parser/item-kw-case-mismatch.rs
new file mode 100644 (file)
index 0000000..ac8390e
--- /dev/null
@@ -0,0 +1,34 @@
+// run-rustfix
+// edition:2018
+#![allow(unused_imports)]
+
+fn main() {}
+
+Use std::ptr::read;  //~ ERROR keyword `use` is written in a wrong case
+USE std::ptr::write; //~ ERROR keyword `use` is written in a wrong case
+
+async Fn _a() {}
+//~^ ERROR keyword `fn` is written in a wrong case
+
+Fn _b() {}
+//~^ ERROR keyword `fn` is written in a wrong case
+
+aSYNC fN _c() {}
+//~^ ERROR keyword `async` is written in a wrong case
+//~| ERROR keyword `fn` is written in a wrong case
+
+Async fn _d() {}
+//~^ ERROR keyword `async` is written in a wrong case
+
+CONST UNSAFE FN _e() {}
+//~^ ERROR keyword `const` is written in a wrong case
+//~| ERROR keyword `unsafe` is written in a wrong case
+//~| ERROR keyword `fn` is written in a wrong case
+
+unSAFE EXTern fn _f() {}
+//~^ ERROR keyword `unsafe` is written in a wrong case
+//~| ERROR keyword `extern` is written in a wrong case
+
+EXTERN "C" FN _g() {}
+//~^ ERROR keyword `extern` is written in a wrong case
+//~| ERROR keyword `fn` is written in a wrong case
diff --git a/src/test/ui/parser/item-kw-case-mismatch.stderr b/src/test/ui/parser/item-kw-case-mismatch.stderr
new file mode 100644 (file)
index 0000000..e66dae8
--- /dev/null
@@ -0,0 +1,86 @@
+error: keyword `use` is written in a wrong case
+  --> $DIR/item-kw-case-mismatch.rs:7:1
+   |
+LL | Use std::ptr::read;
+   | ^^^ help: write it in the correct case (notice the capitalization): `use`
+
+error: keyword `use` is written in a wrong case
+  --> $DIR/item-kw-case-mismatch.rs:8:1
+   |
+LL | USE std::ptr::write;
+   | ^^^ help: write it in the correct case: `use`
+
+error: keyword `fn` is written in a wrong case
+  --> $DIR/item-kw-case-mismatch.rs:10:7
+   |
+LL | async Fn _a() {}
+   |       ^^ help: write it in the correct case (notice the capitalization): `fn`
+
+error: keyword `fn` is written in a wrong case
+  --> $DIR/item-kw-case-mismatch.rs:13:1
+   |
+LL | Fn _b() {}
+   | ^^ help: write it in the correct case (notice the capitalization): `fn`
+
+error: keyword `async` is written in a wrong case
+  --> $DIR/item-kw-case-mismatch.rs:16:1
+   |
+LL | aSYNC fN _c() {}
+   | ^^^^^ help: write it in the correct case: `async`
+
+error: keyword `fn` is written in a wrong case
+  --> $DIR/item-kw-case-mismatch.rs:16:7
+   |
+LL | aSYNC fN _c() {}
+   |       ^^ help: write it in the correct case: `fn`
+
+error: keyword `async` is written in a wrong case
+  --> $DIR/item-kw-case-mismatch.rs:20:1
+   |
+LL | Async fn _d() {}
+   | ^^^^^ help: write it in the correct case: `async`
+
+error: keyword `const` is written in a wrong case
+  --> $DIR/item-kw-case-mismatch.rs:23:1
+   |
+LL | CONST UNSAFE FN _e() {}
+   | ^^^^^ help: write it in the correct case: `const`
+
+error: keyword `unsafe` is written in a wrong case
+  --> $DIR/item-kw-case-mismatch.rs:23:7
+   |
+LL | CONST UNSAFE FN _e() {}
+   |       ^^^^^^ help: write it in the correct case: `unsafe`
+
+error: keyword `fn` is written in a wrong case
+  --> $DIR/item-kw-case-mismatch.rs:23:14
+   |
+LL | CONST UNSAFE FN _e() {}
+   |              ^^ help: write it in the correct case: `fn`
+
+error: keyword `unsafe` is written in a wrong case
+  --> $DIR/item-kw-case-mismatch.rs:28:1
+   |
+LL | unSAFE EXTern fn _f() {}
+   | ^^^^^^ help: write it in the correct case: `unsafe`
+
+error: keyword `extern` is written in a wrong case
+  --> $DIR/item-kw-case-mismatch.rs:28:8
+   |
+LL | unSAFE EXTern fn _f() {}
+   |        ^^^^^^ help: write it in the correct case: `extern`
+
+error: keyword `extern` is written in a wrong case
+  --> $DIR/item-kw-case-mismatch.rs:32:1
+   |
+LL | EXTERN "C" FN _g() {}
+   | ^^^^^^ help: write it in the correct case: `extern`
+
+error: keyword `fn` is written in a wrong case
+  --> $DIR/item-kw-case-mismatch.rs:32:12
+   |
+LL | EXTERN "C" FN _g() {}
+   |            ^^ help: write it in the correct case: `fn`
+
+error: aborting due to 14 previous errors
+
diff --git a/src/test/ui/parser/label-after-block-like.rs b/src/test/ui/parser/label-after-block-like.rs
new file mode 100644 (file)
index 0000000..55f3f8f
--- /dev/null
@@ -0,0 +1,43 @@
+fn a() {
+    if let () = () 'a {}
+    //~^ ERROR labeled expression must be followed by `:`
+    //~| ERROR expected `{`, found `'a`
+}
+
+fn b() {
+    if true 'a {}
+    //~^ ERROR labeled expression must be followed by `:`
+    //~| ERROR expected `{`, found `'a`
+}
+
+fn c() {
+    loop 'a {}
+    //~^ ERROR labeled expression must be followed by `:`
+    //~| ERROR expected `{`, found `'a`
+}
+
+fn d() {
+    while true 'a {}
+    //~^ ERROR labeled expression must be followed by `:`
+    //~| ERROR expected `{`, found `'a`
+}
+
+fn e() {
+    while let () = () 'a {}
+    //~^ ERROR labeled expression must be followed by `:`
+    //~| ERROR expected `{`, found `'a`
+}
+
+fn f() {
+    for _ in 0..0 'a {}
+    //~^ ERROR labeled expression must be followed by `:`
+    //~| ERROR expected `{`, found `'a`
+}
+
+fn g() {
+    unsafe 'a {}
+    //~^ ERROR labeled expression must be followed by `:`
+    //~| ERROR expected `{`, found `'a`
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/label-after-block-like.stderr b/src/test/ui/parser/label-after-block-like.stderr
new file mode 100644 (file)
index 0000000..8ff50b1
--- /dev/null
@@ -0,0 +1,176 @@
+error: labeled expression must be followed by `:`
+  --> $DIR/label-after-block-like.rs:2:20
+   |
+LL |     if let () = () 'a {}
+   |                    ---^^
+   |                    | |
+   |                    | help: add `:` after the label
+   |                    the label
+   |
+   = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them
+
+error: expected `{`, found `'a`
+  --> $DIR/label-after-block-like.rs:2:20
+   |
+LL |     if let () = () 'a {}
+   |                    ^^ expected `{`
+   |
+note: the `if` expression is missing a block after this condition
+  --> $DIR/label-after-block-like.rs:2:8
+   |
+LL |     if let () = () 'a {}
+   |        ^^^^^^^^^^^
+help: try placing this code inside a block
+   |
+LL |     if let () = () { 'a {} }
+   |                    +       +
+
+error: labeled expression must be followed by `:`
+  --> $DIR/label-after-block-like.rs:8:13
+   |
+LL |     if true 'a {}
+   |             ---^^
+   |             | |
+   |             | help: add `:` after the label
+   |             the label
+   |
+   = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them
+
+error: expected `{`, found `'a`
+  --> $DIR/label-after-block-like.rs:8:13
+   |
+LL |     if true 'a {}
+   |             ^^ expected `{`
+   |
+note: the `if` expression is missing a block after this condition
+  --> $DIR/label-after-block-like.rs:8:8
+   |
+LL |     if true 'a {}
+   |        ^^^^
+help: try placing this code inside a block
+   |
+LL |     if true { 'a {} }
+   |             +       +
+
+error: labeled expression must be followed by `:`
+  --> $DIR/label-after-block-like.rs:14:10
+   |
+LL |     loop 'a {}
+   |          ---^^
+   |          | |
+   |          | help: add `:` after the label
+   |          the label
+   |
+   = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them
+
+error: expected `{`, found `'a`
+  --> $DIR/label-after-block-like.rs:14:10
+   |
+LL |     loop 'a {}
+   |     ---- ^^ expected `{`
+   |     |
+   |     while parsing this `loop` expression
+   |
+help: try placing this code inside a block
+   |
+LL |     loop { 'a {} }
+   |          +       +
+
+error: labeled expression must be followed by `:`
+  --> $DIR/label-after-block-like.rs:20:16
+   |
+LL |     while true 'a {}
+   |                ---^^
+   |                | |
+   |                | help: add `:` after the label
+   |                the label
+   |
+   = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them
+
+error: expected `{`, found `'a`
+  --> $DIR/label-after-block-like.rs:20:16
+   |
+LL |     while true 'a {}
+   |     ----- ---- ^^ expected `{`
+   |     |     |
+   |     |     this `while` condition successfully parsed
+   |     while parsing the body of this `while` expression
+   |
+help: try placing this code inside a block
+   |
+LL |     while true { 'a {} }
+   |                +       +
+
+error: labeled expression must be followed by `:`
+  --> $DIR/label-after-block-like.rs:26:23
+   |
+LL |     while let () = () 'a {}
+   |                       ---^^
+   |                       | |
+   |                       | help: add `:` after the label
+   |                       the label
+   |
+   = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them
+
+error: expected `{`, found `'a`
+  --> $DIR/label-after-block-like.rs:26:23
+   |
+LL |     while let () = () 'a {}
+   |     ----- ----------- ^^ expected `{`
+   |     |     |
+   |     |     this `while` condition successfully parsed
+   |     while parsing the body of this `while` expression
+   |
+help: try placing this code inside a block
+   |
+LL |     while let () = () { 'a {} }
+   |                       +       +
+
+error: labeled expression must be followed by `:`
+  --> $DIR/label-after-block-like.rs:32:19
+   |
+LL |     for _ in 0..0 'a {}
+   |                   ---^^
+   |                   | |
+   |                   | help: add `:` after the label
+   |                   the label
+   |
+   = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them
+
+error: expected `{`, found `'a`
+  --> $DIR/label-after-block-like.rs:32:19
+   |
+LL |     for _ in 0..0 'a {}
+   |                   ^^ expected `{`
+   |
+help: try placing this code inside a block
+   |
+LL |     for _ in 0..0 { 'a {} }
+   |                   +       +
+
+error: labeled expression must be followed by `:`
+  --> $DIR/label-after-block-like.rs:38:12
+   |
+LL |     unsafe 'a {}
+   |            ---^^
+   |            | |
+   |            | help: add `:` after the label
+   |            the label
+   |
+   = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them
+
+error: expected `{`, found `'a`
+  --> $DIR/label-after-block-like.rs:38:12
+   |
+LL |     unsafe 'a {}
+   |     ------ ^^ expected `{`
+   |     |
+   |     while parsing this `unsafe` expression
+   |
+help: try placing this code inside a block
+   |
+LL |     unsafe { 'a {} }
+   |            +       +
+
+error: aborting due to 14 previous errors
+
index 163c8ac66b022ae8eb4aac851d8adc71027e05bb..1b859fee596adf6934dbbdcec51644c2442daf0a 100644 (file)
@@ -2,6 +2,6 @@
 
 pub fn main() {
     br"a\r"; //~ ERROR bare CR not allowed in raw string
-    br"é";  //~ ERROR raw byte string must be ASCII
+    br"é";  //~ ERROR non-ASCII character in raw byte string literal
     br##~"a"~##;  //~ ERROR only `#` is allowed in raw string delimitation
 }
index cfc877104bd9f37b3857cec8a7cb5fbe0f2c1fd3..a2f27d1ed70aee56808edb7302ebad643bcf94f9 100644 (file)
@@ -4,7 +4,7 @@ error: bare CR not allowed in raw string
 LL |     br"a\r";
    |         ^
 
-error: raw byte string must be ASCII
+error: non-ASCII character in raw byte string literal
   --> $DIR/raw-byte-string-literals.rs:5:8
    |
 LL |     br"é";
index 5af0b585a12755c2b1c46daf6f0bc5b0ad5fed2d..df099bb62ad1ec5103a80ae2a08a64b4d114f544 100644 (file)
@@ -14,15 +14,15 @@ fn main() {
     println!("{:?}", r##"/*‮ } ⁦if isAdmin⁩ ⁦ begin admins only "##);
     //~^ ERROR unicode codepoint changing visible direction of text present in literal
     println!("{:?}", b"/*‮ } ⁦if isAdmin⁩ ⁦ begin admins only ");
-    //~^ ERROR non-ASCII character in byte constant
-    //~| ERROR non-ASCII character in byte constant
-    //~| ERROR non-ASCII character in byte constant
-    //~| ERROR non-ASCII character in byte constant
+    //~^ ERROR non-ASCII character in byte string literal
+    //~| ERROR non-ASCII character in byte string literal
+    //~| ERROR non-ASCII character in byte string literal
+    //~| ERROR non-ASCII character in byte string literal
     println!("{:?}", br##"/*‮ } ⁦if isAdmin⁩ ⁦ begin admins only "##);
-    //~^ ERROR raw byte string must be ASCII
-    //~| ERROR raw byte string must be ASCII
-    //~| ERROR raw byte string must be ASCII
-    //~| ERROR raw byte string must be ASCII
+    //~^ ERROR non-ASCII character in raw byte string literal
+    //~| ERROR non-ASCII character in raw byte string literal
+    //~| ERROR non-ASCII character in raw byte string literal
+    //~| ERROR non-ASCII character in raw byte string literal
     println!("{:?}", '‮');
     //~^ ERROR unicode codepoint changing visible direction of text present in literal
 }
index 44548c72ff5d0c34d8ab7a4c26daba0146edc35d..fc071a941914210c110a8c13ec43b053d5a60e1d 100644 (file)
@@ -14,69 +14,69 @@ LL |     println!("{:?}", b"us\u{202B}e\u{202A}r");
    |
    = help: unicode escape sequences cannot be used as a byte or in a byte string
 
-error: non-ASCII character in byte constant
+error: non-ASCII character in byte string literal
   --> $DIR/unicode-control-codepoints.rs:16:26
    |
 LL |     println!("{:?}", b"/* } if isAdmin  begin admins only ");
-   |                          ^ byte constant must be ASCII but is '\u{202e}'
+   |                          ^ must be ASCII but is '\u{202e}'
    |
 help: if you meant to use the UTF-8 encoding of '\u{202e}', use \xHH escapes
    |
 LL |     println!("{:?}", b"/*\xE2\x80\xAE } if isAdmin  begin admins only ");
    |                          ~~~~~~~~~~~~
 
-error: non-ASCII character in byte constant
+error: non-ASCII character in byte string literal
   --> $DIR/unicode-control-codepoints.rs:16:30
    |
 LL |     println!("{:?}", b"/* } if isAdmin  begin admins only ");
-   |                             ^ byte constant must be ASCII but is '\u{2066}'
+   |                             ^ must be ASCII but is '\u{2066}'
    |
 help: if you meant to use the UTF-8 encoding of '\u{2066}', use \xHH escapes
    |
 LL |     println!("{:?}", b"/* } \xE2\x81\xA6if isAdmin  begin admins only ");
    |                             ~~~~~~~~~~~~
 
-error: non-ASCII character in byte constant
+error: non-ASCII character in byte string literal
   --> $DIR/unicode-control-codepoints.rs:16:41
    |
 LL |     println!("{:?}", b"/* } if isAdmin  begin admins only ");
-   |                                       ^ byte constant must be ASCII but is '\u{2069}'
+   |                                       ^ must be ASCII but is '\u{2069}'
    |
 help: if you meant to use the UTF-8 encoding of '\u{2069}', use \xHH escapes
    |
 LL |     println!("{:?}", b"/* } if isAdmin\xE2\x81\xA9  begin admins only ");
    |                                       ~~~~~~~~~~~~
 
-error: non-ASCII character in byte constant
+error: non-ASCII character in byte string literal
   --> $DIR/unicode-control-codepoints.rs:16:43
    |
 LL |     println!("{:?}", b"/* } if isAdmin  begin admins only ");
-   |                                        ^ byte constant must be ASCII but is '\u{2066}'
+   |                                        ^ must be ASCII but is '\u{2066}'
    |
 help: if you meant to use the UTF-8 encoding of '\u{2066}', use \xHH escapes
    |
 LL |     println!("{:?}", b"/* } if isAdmin \xE2\x81\xA6 begin admins only ");
    |                                        ~~~~~~~~~~~~
 
-error: raw byte string must be ASCII
+error: non-ASCII character in raw byte string literal
   --> $DIR/unicode-control-codepoints.rs:21:29
    |
 LL |     println!("{:?}", br##"/* } if isAdmin  begin admins only "##);
    |                             ^ must be ASCII but is '\u{202e}'
 
-error: raw byte string must be ASCII
+error: non-ASCII character in raw byte string literal
   --> $DIR/unicode-control-codepoints.rs:21:33
    |
 LL |     println!("{:?}", br##"/* } if isAdmin  begin admins only "##);
    |                                ^ must be ASCII but is '\u{2066}'
 
-error: raw byte string must be ASCII
+error: non-ASCII character in raw byte string literal
   --> $DIR/unicode-control-codepoints.rs:21:44
    |
 LL |     println!("{:?}", br##"/* } if isAdmin  begin admins only "##);
    |                                          ^ must be ASCII but is '\u{2069}'
 
-error: raw byte string must be ASCII
+error: non-ASCII character in raw byte string literal
   --> $DIR/unicode-control-codepoints.rs:21:46
    |
 LL |     println!("{:?}", br##"/* } if isAdmin  begin admins only "##);
diff --git a/src/test/ui/parser/use-colon-as-mod-sep.rs b/src/test/ui/parser/use-colon-as-mod-sep.rs
new file mode 100644 (file)
index 0000000..e1e8756
--- /dev/null
@@ -0,0 +1,11 @@
+// Recover from using a colon as a path separator.
+
+use std::process:Command;
+//~^ ERROR expected `::`, found `:`
+use std:fs::File;
+//~^ ERROR expected `::`, found `:`
+use std:collections:HashMap;
+//~^ ERROR expected `::`, found `:`
+//~| ERROR expected `::`, found `:`
+
+fn main() { }
diff --git a/src/test/ui/parser/use-colon-as-mod-sep.stderr b/src/test/ui/parser/use-colon-as-mod-sep.stderr
new file mode 100644 (file)
index 0000000..e825dfe
--- /dev/null
@@ -0,0 +1,28 @@
+error: expected `::`, found `:`
+  --> $DIR/use-colon-as-mod-sep.rs:3:17
+   |
+LL | use std::process:Command;
+   |                 ^ help: use double colon
+   |
+   = note: import paths are delimited using `::`
+
+error: expected `::`, found `:`
+  --> $DIR/use-colon-as-mod-sep.rs:5:8
+   |
+LL | use std:fs::File;
+   |        ^ help: use double colon
+
+error: expected `::`, found `:`
+  --> $DIR/use-colon-as-mod-sep.rs:7:8
+   |
+LL | use std:collections:HashMap;
+   |        ^ help: use double colon
+
+error: expected `::`, found `:`
+  --> $DIR/use-colon-as-mod-sep.rs:7:20
+   |
+LL | use std:collections:HashMap;
+   |                    ^ help: use double colon
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/pattern/issue-52240.rs b/src/test/ui/pattern/issue-52240.rs
new file mode 100644 (file)
index 0000000..5def557
--- /dev/null
@@ -0,0 +1,16 @@
+// issue-52240: Can turn immutable into mut with `ref mut`
+
+enum Foo {
+    Bar(i32),
+}
+
+fn main() {
+    let arr = vec!(Foo::Bar(0));
+    if let (Some(Foo::Bar(ref mut val)), _) = (&arr.get(0), 0) {
+        //~^ ERROR cannot borrow data in a `&` reference as mutable
+        *val = 9001;
+    }
+    match arr[0] {
+        Foo::Bar(ref s) => println!("{}", s)
+    }
+}
diff --git a/src/test/ui/pattern/issue-52240.stderr b/src/test/ui/pattern/issue-52240.stderr
new file mode 100644 (file)
index 0000000..69b663b
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0596]: cannot borrow data in a `&` reference as mutable
+  --> $DIR/issue-52240.rs:9:27
+   |
+LL |     if let (Some(Foo::Bar(ref mut val)), _) = (&arr.get(0), 0) {
+   |                           ^^^^^^^^^^^ cannot borrow as mutable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
index 4971263af08ad1864f36a5dbf81bfecedd319411..fc1be052fb79189139557a6322acc0429a465af2 100644 (file)
@@ -4,7 +4,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     let phantom_pinned = identity(pin!(PhantomPinned));
    |                                   ^^^^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
    |                                   |
-   |                                   creates a temporary which is freed while still in use
+   |                                   creates a temporary value which is freed while still in use
 LL |
 LL |     stuff(phantom_pinned)
    |           -------------- borrow later used here
@@ -18,7 +18,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     let phantom_pinned = {
    |         -------------- borrow later stored here
 LL |         let phantom_pinned = pin!(PhantomPinned);
-   |                              ^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |                              ^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
 ...
 LL |     };
    |     - temporary value is freed at the end of this statement
diff --git a/src/test/ui/privacy/auxiliary/issue-75907.rs b/src/test/ui/privacy/auxiliary/issue-75907.rs
new file mode 100644 (file)
index 0000000..389c9c3
--- /dev/null
@@ -0,0 +1,17 @@
+pub struct Bar(pub u8, u8, u8);
+
+pub fn make_bar() -> Bar {
+    Bar(1, 12, 10)
+}
+
+mod inner {
+    pub struct Foo(u8, pub u8, u8);
+
+    impl Foo {
+        pub fn new() -> Foo {
+            Foo(1, 12, 10)
+        }
+    }
+}
+
+pub use inner::Foo;
index c1f9ee8dfdf73e1081e3841e9a8e8d26b4c41676..4479b0d8f61baf5bd75f911c9e8e8ddb5390006e 100644 (file)
@@ -6,7 +6,7 @@ mod outer { //~ ERROR Direct: pub(crate), Reexported: pub(crate), Reachable: pub
     pub mod inner1 { //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
 
         #[rustc_effective_visibility]
-        extern "C" {} //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+        extern "C" {} //~ ERROR not in the table
 
         #[rustc_effective_visibility]
         pub trait PubTrait { //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
@@ -18,6 +18,7 @@ pub trait PubTrait { //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: p
 
         #[rustc_effective_visibility]
         struct PrivStruct; //~ ERROR not in the table
+                           //~| ERROR not in the table
 
         #[rustc_effective_visibility]
         pub union PubUnion { //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
@@ -31,6 +32,7 @@ pub union PubUnion { //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: p
         pub enum Enum { //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
             #[rustc_effective_visibility]
             A( //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+               //~| ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
                 #[rustc_effective_visibility]
                 PubUnion,  //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
             ),
index 5a8f7db38fc8a4db83fd53df3a1bf958b507ae7a..019aaf8086a6a82d91f35dcee4a981c5aff8f2d6 100644 (file)
@@ -10,7 +10,7 @@ error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImpl
 LL |     pub mod inner1 {
    |     ^^^^^^^^^^^^^^
 
-error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+error: not in the table
   --> $DIR/effective_visibilities.rs:9:9
    |
 LL |         extern "C" {}
@@ -28,92 +28,104 @@ error: not in the table
 LL |         struct PrivStruct;
    |         ^^^^^^^^^^^^^^^^^
 
+error: not in the table
+  --> $DIR/effective_visibilities.rs:20:9
+   |
+LL |         struct PrivStruct;
+   |         ^^^^^^^^^^^^^^^^^
+
 error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
-  --> $DIR/effective_visibilities.rs:23:9
+  --> $DIR/effective_visibilities.rs:24:9
    |
 LL |         pub union PubUnion {
    |         ^^^^^^^^^^^^^^^^^^
 
 error: not in the table
-  --> $DIR/effective_visibilities.rs:25:13
+  --> $DIR/effective_visibilities.rs:26:13
    |
 LL |             a: u8,
    |             ^^^^^
 
 error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
-  --> $DIR/effective_visibilities.rs:27:13
+  --> $DIR/effective_visibilities.rs:28:13
    |
 LL |             pub b: u8,
    |             ^^^^^^^^^
 
 error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
-  --> $DIR/effective_visibilities.rs:31:9
+  --> $DIR/effective_visibilities.rs:32:9
    |
 LL |         pub enum Enum {
    |         ^^^^^^^^^^^^^
 
 error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
-  --> $DIR/effective_visibilities.rs:33:13
+  --> $DIR/effective_visibilities.rs:34:13
+   |
+LL |             A(
+   |             ^
+
+error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+  --> $DIR/effective_visibilities.rs:34:13
    |
 LL |             A(
    |             ^
 
 error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
-  --> $DIR/effective_visibilities.rs:35:17
+  --> $DIR/effective_visibilities.rs:37:17
    |
 LL |                 PubUnion,
    |                 ^^^^^^^^
 
 error: not in the table
-  --> $DIR/effective_visibilities.rs:41:5
+  --> $DIR/effective_visibilities.rs:43:5
    |
 LL |     macro_rules! none_macro {
    |     ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: Direct: pub(self), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
-  --> $DIR/effective_visibilities.rs:47:5
+  --> $DIR/effective_visibilities.rs:49:5
    |
 LL |     macro_rules! public_macro {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: Direct: pub(crate), Reexported: pub(crate), Reachable: pub, ReachableThroughImplTrait: pub
-  --> $DIR/effective_visibilities.rs:52:5
+  --> $DIR/effective_visibilities.rs:54:5
    |
 LL |     pub struct ReachableStruct {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: Direct: pub(crate), Reexported: pub(crate), Reachable: pub, ReachableThroughImplTrait: pub
-  --> $DIR/effective_visibilities.rs:54:9
+  --> $DIR/effective_visibilities.rs:56:9
    |
 LL |         pub a: u8,
    |         ^^^^^^^^^
 
 error: Direct: pub, Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
-  --> $DIR/effective_visibilities.rs:59:9
+  --> $DIR/effective_visibilities.rs:61:9
    |
 LL | pub use outer::inner1;
    |         ^^^^^^^^^^^^^
 
 error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
-  --> $DIR/effective_visibilities.rs:65:5
+  --> $DIR/effective_visibilities.rs:67:5
    |
 LL |     pub type HalfPublicImport = u8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: Direct: pub(crate), Reexported: pub(crate), Reachable: pub(crate), ReachableThroughImplTrait: pub(crate)
-  --> $DIR/effective_visibilities.rs:68:5
+  --> $DIR/effective_visibilities.rs:70:5
    |
 LL |     pub(crate) const HalfPublicImport: u8 = 0;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: Direct: pub, Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
-  --> $DIR/effective_visibilities.rs:72:9
+  --> $DIR/effective_visibilities.rs:74:9
    |
 LL | pub use half_public_import::HalfPublicImport;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: Direct: pub, Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
-  --> $DIR/effective_visibilities.rs:72:9
+  --> $DIR/effective_visibilities.rs:74:9
    |
 LL | pub use half_public_import::HalfPublicImport;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -130,5 +142,5 @@ error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImpl
 LL |             type B;
    |             ^^^^^^
 
-error: aborting due to 22 previous errors
+error: aborting due to 24 previous errors
 
diff --git a/src/test/ui/privacy/effective_visibilities_glob.rs b/src/test/ui/privacy/effective_visibilities_glob.rs
new file mode 100644 (file)
index 0000000..eb9dcd6
--- /dev/null
@@ -0,0 +1,21 @@
+// Effective visibility tracking for imports is fine-grained, so `S2` is not fully exported
+// even if its parent import (`m::*`) is fully exported as a `use` item.
+
+#![feature(rustc_attrs)]
+
+mod m {
+    #[rustc_effective_visibility]
+    pub struct S1 {} //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+    #[rustc_effective_visibility]
+    pub struct S2 {} //~ ERROR Direct: pub(crate), Reexported: pub(crate), Reachable: pub(crate), ReachableThroughImplTrait: pub(crate)
+}
+
+mod glob {
+    #[rustc_effective_visibility]
+    pub use crate::m::*; //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+}
+
+#[rustc_effective_visibility]
+pub use glob::S1; //~ ERROR Direct: pub, Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+
+fn main() {}
diff --git a/src/test/ui/privacy/effective_visibilities_glob.stderr b/src/test/ui/privacy/effective_visibilities_glob.stderr
new file mode 100644 (file)
index 0000000..0496cd5
--- /dev/null
@@ -0,0 +1,26 @@
+error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+  --> $DIR/effective_visibilities_glob.rs:8:5
+   |
+LL |     pub struct S1 {}
+   |     ^^^^^^^^^^^^^
+
+error: Direct: pub(crate), Reexported: pub(crate), Reachable: pub(crate), ReachableThroughImplTrait: pub(crate)
+  --> $DIR/effective_visibilities_glob.rs:10:5
+   |
+LL |     pub struct S2 {}
+   |     ^^^^^^^^^^^^^
+
+error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+  --> $DIR/effective_visibilities_glob.rs:15:13
+   |
+LL |     pub use crate::m::*;
+   |             ^^^^^^^^
+
+error: Direct: pub, Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+  --> $DIR/effective_visibilities_glob.rs:19:9
+   |
+LL | pub use glob::S1;
+   |         ^^^^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/privacy/issue-75907.rs b/src/test/ui/privacy/issue-75907.rs
new file mode 100644 (file)
index 0000000..6da99cf
--- /dev/null
@@ -0,0 +1,18 @@
+// Test for diagnostic improvement issue #75907
+
+mod foo {
+    pub(crate) struct Foo(u8);
+    pub(crate) struct Bar(pub u8, u8, Foo);
+
+    pub(crate) fn make_bar() -> Bar {
+        Bar(1, 12, Foo(10))
+    }
+}
+
+use foo::{make_bar, Bar, Foo};
+
+fn main() {
+    let Bar(x, y, Foo(z)) = make_bar();
+    //~^ ERROR cannot match against a tuple struct which contains private fields
+    //~| ERROR cannot match against a tuple struct which contains private fields
+}
diff --git a/src/test/ui/privacy/issue-75907.stderr b/src/test/ui/privacy/issue-75907.stderr
new file mode 100644 (file)
index 0000000..2f89e31
--- /dev/null
@@ -0,0 +1,29 @@
+error[E0532]: cannot match against a tuple struct which contains private fields
+  --> $DIR/issue-75907.rs:15:9
+   |
+LL |     let Bar(x, y, Foo(z)) = make_bar();
+   |         ^^^
+   |
+note: constructor is not visible here due to private fields
+  --> $DIR/issue-75907.rs:15:16
+   |
+LL |     let Bar(x, y, Foo(z)) = make_bar();
+   |                ^  ^^^^^^ private field
+   |                |
+   |                private field
+
+error[E0532]: cannot match against a tuple struct which contains private fields
+  --> $DIR/issue-75907.rs:15:19
+   |
+LL |     let Bar(x, y, Foo(z)) = make_bar();
+   |                   ^^^
+   |
+note: constructor is not visible here due to private fields
+  --> $DIR/issue-75907.rs:15:23
+   |
+LL |     let Bar(x, y, Foo(z)) = make_bar();
+   |                       ^ private field
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0532`.
diff --git a/src/test/ui/privacy/issue-75907_b.rs b/src/test/ui/privacy/issue-75907_b.rs
new file mode 100644 (file)
index 0000000..fdfc590
--- /dev/null
@@ -0,0 +1,14 @@
+// Test for diagnostic improvement issue #75907, extern crate
+// aux-build:issue-75907.rs
+
+extern crate issue_75907 as a;
+
+use a::{make_bar, Bar, Foo};
+
+fn main() {
+    let Bar(x, y, z) = make_bar();
+    //~^ ERROR cannot match against a tuple struct which contains private fields
+
+    let Foo(x, y, z) = Foo::new();
+    //~^ ERROR cannot match against a tuple struct which contains private fields
+}
diff --git a/src/test/ui/privacy/issue-75907_b.stderr b/src/test/ui/privacy/issue-75907_b.stderr
new file mode 100644 (file)
index 0000000..b82d084
--- /dev/null
@@ -0,0 +1,31 @@
+error[E0532]: cannot match against a tuple struct which contains private fields
+  --> $DIR/issue-75907_b.rs:9:9
+   |
+LL |     let Bar(x, y, z) = make_bar();
+   |         ^^^
+   |
+note: constructor is not visible here due to private fields
+  --> $DIR/issue-75907_b.rs:9:16
+   |
+LL |     let Bar(x, y, z) = make_bar();
+   |                ^  ^ private field
+   |                |
+   |                private field
+
+error[E0532]: cannot match against a tuple struct which contains private fields
+  --> $DIR/issue-75907_b.rs:12:9
+   |
+LL |     let Foo(x, y, z) = Foo::new();
+   |         ^^^
+   |
+note: constructor is not visible here due to private fields
+  --> $DIR/issue-75907_b.rs:12:13
+   |
+LL |     let Foo(x, y, z) = Foo::new();
+   |             ^     ^ private field
+   |             |
+   |             private field
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0532`.
index d1146d970306264b1485cfc6f243bd51134a62f4..8d51b7e17185b585411384795256ef5c84bae9b0 100644 (file)
@@ -1,5 +1,5 @@
 // aux-build:expand-expr.rs
-
+#![feature(concat_bytes)]
 extern crate expand_expr;
 
 use expand_expr::{
     concat!("contents: ", include_str!("auxiliary/included-file.txt"))
 );
 
+expand_expr_is!(
+    b"contents: Included file contents\n",
+    concat_bytes!(b"contents: ", include_bytes!("auxiliary/included-file.txt"))
+);
+
 // Correct value is checked for multiple sources.
 check_expand_expr_file!(file!());
 
index 8dc2d0cfc2f8505d3aaf50d0827c2afeea04befa..c6c4695fd9c43ee3093272a895cd3ff6f70b74af 100644 (file)
@@ -1,29 +1,29 @@
 error: expected one of `.`, `?`, or an operator, found `;`
-  --> $DIR/expand-expr.rs:101:27
+  --> $DIR/expand-expr.rs:106:27
    |
 LL | expand_expr_fail!("string"; hello);
    |                           ^ expected one of `.`, `?`, or an operator
 
 error: expected expression, found `$`
-  --> $DIR/expand-expr.rs:104:19
+  --> $DIR/expand-expr.rs:109:19
    |
 LL | expand_expr_fail!($);
    |                   ^ expected expression
 
 error: expected expression, found `$`
-  --> $DIR/expand-expr.rs:33:23
+  --> $DIR/expand-expr.rs:38:23
    |
 LL |     ($($t:tt)*) => { $($t)* };
    |                       ^^^^ expected expression
 
 error: expected expression, found `$`
-  --> $DIR/expand-expr.rs:106:28
+  --> $DIR/expand-expr.rs:111:28
    |
 LL | expand_expr_fail!(echo_pm!($));
    |                            ^ expected expression
 
 error: macro expansion ignores token `hello` and any following
-  --> $DIR/expand-expr.rs:110:47
+  --> $DIR/expand-expr.rs:115:47
    |
 LL | expand_expr_is!("string", echo_tts!("string"; hello));
    |                           --------------------^^^^^-- help: you might be missing a semicolon here: `;`
@@ -33,7 +33,7 @@ LL | expand_expr_is!("string", echo_tts!("string"; hello));
    = note: the usage of `echo_tts!` is likely invalid in expression context
 
 error: macro expansion ignores token `;` and any following
-  --> $DIR/expand-expr.rs:111:44
+  --> $DIR/expand-expr.rs:116:44
    |
 LL | expand_expr_is!("string", echo_pm!("string"; hello));
    |                           -----------------^-------- help: you might be missing a semicolon here: `;`
@@ -43,7 +43,7 @@ LL | expand_expr_is!("string", echo_pm!("string"; hello));
    = note: the usage of `echo_pm!` is likely invalid in expression context
 
 error: recursion limit reached while expanding `recursive_expand!`
-  --> $DIR/expand-expr.rs:119:16
+  --> $DIR/expand-expr.rs:124:16
    |
 LL | const _: u32 = recursive_expand!();
    |                ^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/regions/issue-11612.rs b/src/test/ui/regions/issue-11612.rs
new file mode 100644 (file)
index 0000000..9f7f1cc
--- /dev/null
@@ -0,0 +1,24 @@
+// check-pass
+#![allow(dead_code)]
+// #11612
+// We weren't updating the auto adjustments with all the resolved
+// type information after type check.
+
+// pretty-expanded FIXME #23616
+
+trait A { fn dummy(&self) { } }
+
+struct B<'a, T:'a> {
+    f: &'a T
+}
+
+impl<'a, T> A for B<'a, T> {}
+
+fn foo(_: &dyn A) {}
+
+fn bar<G>(b: &B<G>) {
+    foo(b);       // Coercion should work
+    foo(b as &dyn A); // Explicit cast should work as well
+}
+
+fn main() {}
index 8042b1740b141790de405001d97c1ab6f8daa592..8ef7e22536bf94a4847261ad3fe6bf476fbf88de 100644 (file)
@@ -5,7 +5,7 @@ LL | fn call1<'a>(x: &'a usize) {
    |          -- lifetime `'a` defined here
 ...
 LL |     let z: &'a & usize = &(&y);
-   |            -----------    ^^^^ creates a temporary which is freed while still in use
+   |            -----------    ^^^^ creates a temporary value which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'a`
 ...
index 476e82f046f01a7f0abe8ded74a43417a637fc06..c32bbe0ee1fb4af53e72fa75e5e34a6bd580dd60 100644 (file)
@@ -4,7 +4,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |         x = &id(3);
    |              ^^^^^- temporary value is freed at the end of this statement
    |              |
-   |              creates a temporary which is freed while still in use
+   |              creates a temporary value which is freed while still in use
 LL |         assert_eq!(*x, 3);
    |         ----------------- borrow later used here
    |
diff --git a/src/test/ui/resolve/issue-103474.rs b/src/test/ui/resolve/issue-103474.rs
new file mode 100644 (file)
index 0000000..14f2259
--- /dev/null
@@ -0,0 +1,28 @@
+struct S {}
+impl S {
+    fn first(&self) {}
+
+    fn second(&self) {
+        first()
+        //~^ ERROR cannot find function `first` in this scope
+    }
+
+    fn third(&self) {
+        no_method_err()
+        //~^ ERROR cannot find function `no_method_err` in this scope
+    }
+}
+
+// https://github.com/rust-lang/rust/pull/103531#discussion_r1004728080
+struct Foo {
+    i: i32,
+}
+
+impl Foo {
+    fn needs_self() {
+        this.i
+        //~^ ERROR cannot find value `this` in this scope
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/resolve/issue-103474.stderr b/src/test/ui/resolve/issue-103474.stderr
new file mode 100644 (file)
index 0000000..415d231
--- /dev/null
@@ -0,0 +1,35 @@
+error[E0425]: cannot find value `this` in this scope
+  --> $DIR/issue-103474.rs:23:9
+   |
+LL |         this.i
+   |         ^^^^ not found in this scope
+   |
+help: you might have meant to use `self` here instead
+   |
+LL |         self.i
+   |         ~~~~
+help: if you meant to use `self`, you are also missing a `self` receiver argument
+   |
+LL |     fn needs_self(&self) {
+   |                   +++++
+
+error[E0425]: cannot find function `first` in this scope
+  --> $DIR/issue-103474.rs:6:9
+   |
+LL |         first()
+   |         ^^^^^ not found in this scope
+   |
+help: consider using the associated function
+   |
+LL |         self.first()
+   |         +++++
+
+error[E0425]: cannot find function `no_method_err` in this scope
+  --> $DIR/issue-103474.rs:11:9
+   |
+LL |         no_method_err()
+   |         ^^^^^^^^^^^^^ not found in this scope
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0425`.
index e7c53ff44e6fe0ac3250894733f564fe57a430e6..36f3da7c9553794129913273f3194ddfcdb9da84 100644 (file)
@@ -85,7 +85,7 @@ LL |         static_method();
 help: consider using the associated function
    |
 LL |         Self::static_method();
-   |         ~~~~~~~~~~~~~~~~~~~
+   |         ++++++
 
 error[E0425]: cannot find function `purr` in this scope
   --> $DIR/issue-2356.rs:54:9
@@ -114,7 +114,7 @@ LL |     grow_older();
 help: consider using the associated function
    |
 LL |     Self::grow_older();
-   |     ~~~~~~~~~~~~~~~~
+   |     ++++++
 
 error[E0425]: cannot find function `shave` in this scope
   --> $DIR/issue-2356.rs:74:5
diff --git a/src/test/ui/resolve/issue-35675.rs b/src/test/ui/resolve/issue-35675.rs
new file mode 100644 (file)
index 0000000..6837616
--- /dev/null
@@ -0,0 +1,42 @@
+// these two HELPs are actually in a new line between this line and the `enum Fruit` line
+enum Fruit {
+    Apple(i64),
+    Orange(i64),
+}
+
+fn should_return_fruit() -> Apple {
+    //~^ ERROR cannot find type `Apple` in this scope
+    Apple(5)
+    //~^ ERROR cannot find function, tuple struct or tuple variant `Apple` in this scope
+}
+
+fn should_return_fruit_too() -> Fruit::Apple {
+    //~^ ERROR expected type, found variant `Fruit::Apple`
+    Apple(5)
+    //~^ ERROR cannot find function, tuple struct or tuple variant `Apple` in this scope
+}
+
+fn foo() -> Ok {
+    //~^ ERROR expected type, found variant `Ok`
+    Ok(())
+}
+
+fn bar() -> Variant3 {
+    //~^ ERROR cannot find type `Variant3` in this scope
+}
+
+fn qux() -> Some {
+    //~^ ERROR expected type, found variant `Some`
+    Some(1)
+}
+
+fn main() {}
+
+mod x {
+    pub enum Enum {
+        Variant1,
+        Variant2(),
+        Variant3(usize),
+        Variant4 {},
+    }
+}
diff --git a/src/test/ui/resolve/issue-35675.stderr b/src/test/ui/resolve/issue-35675.stderr
new file mode 100644 (file)
index 0000000..4a06196
--- /dev/null
@@ -0,0 +1,75 @@
+error[E0412]: cannot find type `Apple` in this scope
+  --> $DIR/issue-35675.rs:7:29
+   |
+LL | fn should_return_fruit() -> Apple {
+   |                             ^^^^^ not found in this scope
+   |
+help: there is an enum variant `Fruit::Apple`; try using the variant's enum
+   |
+LL | fn should_return_fruit() -> Fruit {
+   |                             ~~~~~
+
+error[E0425]: cannot find function, tuple struct or tuple variant `Apple` in this scope
+  --> $DIR/issue-35675.rs:9:5
+   |
+LL |     Apple(5)
+   |     ^^^^^ not found in this scope
+   |
+help: consider importing this tuple variant
+   |
+LL | use Fruit::Apple;
+   |
+
+error[E0573]: expected type, found variant `Fruit::Apple`
+  --> $DIR/issue-35675.rs:13:33
+   |
+LL | fn should_return_fruit_too() -> Fruit::Apple {
+   |                                 ^^^^^^^^^^^^
+   |                                 |
+   |                                 not a type
+   |                                 help: try using the variant's enum: `Fruit`
+
+error[E0425]: cannot find function, tuple struct or tuple variant `Apple` in this scope
+  --> $DIR/issue-35675.rs:15:5
+   |
+LL |     Apple(5)
+   |     ^^^^^ not found in this scope
+   |
+help: consider importing this tuple variant
+   |
+LL | use Fruit::Apple;
+   |
+
+error[E0573]: expected type, found variant `Ok`
+  --> $DIR/issue-35675.rs:19:13
+   |
+LL | fn foo() -> Ok {
+   |             ^^
+   |             |
+   |             not a type
+   |             help: try using the variant's enum: `std::result::Result`
+
+error[E0412]: cannot find type `Variant3` in this scope
+  --> $DIR/issue-35675.rs:24:13
+   |
+LL | fn bar() -> Variant3 {
+   |             ^^^^^^^^ not found in this scope
+   |
+help: there is an enum variant `x::Enum::Variant3`; try using the variant's enum
+   |
+LL | fn bar() -> x::Enum {
+   |             ~~~~~~~
+
+error[E0573]: expected type, found variant `Some`
+  --> $DIR/issue-35675.rs:28:13
+   |
+LL | fn qux() -> Some {
+   |             ^^^^
+   |             |
+   |             not a type
+   |             help: try using the variant's enum: `std::option::Option`
+
+error: aborting due to 7 previous errors
+
+Some errors have detailed explanations: E0412, E0425, E0573.
+For more information about an error, try `rustc --explain E0412`.
diff --git a/src/test/ui/resolve/issue-5927.rs b/src/test/ui/resolve/issue-5927.rs
new file mode 100644 (file)
index 0000000..14f9582
--- /dev/null
@@ -0,0 +1,7 @@
+fn main() {
+    let z = match 3 {
+        x(1) => x(1) //~ ERROR cannot find tuple struct or tuple variant `x` in this scope
+        //~^ ERROR cannot find function `x` in this scope
+    };
+    assert!(z == 3);
+}
diff --git a/src/test/ui/resolve/issue-5927.stderr b/src/test/ui/resolve/issue-5927.stderr
new file mode 100644 (file)
index 0000000..d6cd685
--- /dev/null
@@ -0,0 +1,16 @@
+error[E0531]: cannot find tuple struct or tuple variant `x` in this scope
+  --> $DIR/issue-5927.rs:3:9
+   |
+LL |         x(1) => x(1)
+   |         ^ not found in this scope
+
+error[E0425]: cannot find function `x` in this scope
+  --> $DIR/issue-5927.rs:3:17
+   |
+LL |         x(1) => x(1)
+   |                 ^ not found in this scope
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0425, E0531.
+For more information about an error, try `rustc --explain E0425`.
index 6ee32314607ad899ec4415f770aa967e6897b504..9577952119adb2c480bc9b2caf5731574304da51 100644 (file)
@@ -1,12 +1,10 @@
 error[E0277]: the trait bound `f32: Termination` is not satisfied
-  --> $DIR/termination-trait-test-wrong-type.rs:6:1
+  --> $DIR/termination-trait-test-wrong-type.rs:6:31
    |
-LL |   #[test]
-   |   ------- in this procedural macro expansion
-LL | / fn can_parse_zero_as_f32() -> Result<f32, ParseFloatError> {
-LL | |     "0".parse()
-LL | | }
-   | |_^ the trait `Termination` is not implemented for `f32`
+LL | #[test]
+   | ------- in this procedural macro expansion
+LL | fn can_parse_zero_as_f32() -> Result<f32, ParseFloatError> {
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Termination` is not implemented for `f32`
    |
    = note: required for `Result<f32, ParseFloatError>` to implement `Termination`
 note: required by a bound in `assert_test_result`
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-gate.rs b/src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-gate.rs
new file mode 100644 (file)
index 0000000..348ca0a
--- /dev/null
@@ -0,0 +1,4 @@
+#[derive_const(Default)] //~ ERROR use of unstable library feature
+pub struct S;
+
+fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-gate.stderr b/src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-gate.stderr
new file mode 100644 (file)
index 0000000..cc9bdd2
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0658]: use of unstable library feature 'derive_const'
+  --> $DIR/derive-const-gate.rs:1:3
+   |
+LL | #[derive_const(Default)]
+   |   ^^^^^^^^^^^^
+   |
+   = help: add `#![feature(derive_const)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.rs b/src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.rs
new file mode 100644 (file)
index 0000000..92843a8
--- /dev/null
@@ -0,0 +1,13 @@
+#![feature(derive_const)]
+
+pub struct A;
+
+impl Default for A {
+    fn default() -> A { A }
+}
+
+#[derive_const(Default)]
+pub struct S(A);
+//~^ cannot call non-const fn
+
+fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.stderr b/src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.stderr
new file mode 100644 (file)
index 0000000..d463c77
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0015]: cannot call non-const fn `<A as Default>::default` in constant functions
+  --> $DIR/derive-const-non-const-type.rs:10:14
+   |
+LL | #[derive_const(Default)]
+   |                ------- in this derive macro expansion
+LL | pub struct S(A);
+   |              ^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+   = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-use.rs b/src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-use.rs
new file mode 100644 (file)
index 0000000..d1fbeac
--- /dev/null
@@ -0,0 +1,19 @@
+// check-pass
+#![feature(const_trait_impl, const_cmp, const_default_impls, derive_const)]
+
+pub struct A;
+
+impl const Default for A {
+    fn default() -> A { A }
+}
+
+impl const PartialEq for A {
+    fn eq(&self, _: &A) -> bool { true }
+}
+
+#[derive_const(Default, PartialEq)]
+pub struct S((), A);
+
+const _: () = assert!(S((), A) == S::default());
+
+fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.rs b/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.rs
new file mode 100644 (file)
index 0000000..3ac9099
--- /dev/null
@@ -0,0 +1,46 @@
+// Tests that trait bounds on specializing trait impls must be `~const` if the
+// same bound is present on the default impl and is `~const` there.
+
+#![feature(const_trait_impl)]
+#![feature(rustc_attrs)]
+#![feature(min_specialization)]
+
+#[rustc_specialization_trait]
+trait Specialize {}
+
+#[const_trait]
+trait Foo {}
+
+#[const_trait]
+trait Bar {}
+
+// bgr360: I was only able to exercise the code path that raises the
+// "missing ~const qualifier" error by making this base impl non-const, even
+// though that doesn't really make sense to do. As seen below, if the base impl
+// is made const, rustc fails earlier with an overlapping impl failure.
+impl<T> Bar for T
+where
+    T: ~const Foo,
+{}
+
+impl<T> Bar for T
+where
+    T: Foo, //~ ERROR missing `~const` qualifier
+    T: Specialize,
+{}
+
+#[const_trait]
+trait Baz {}
+
+impl<T> const Baz for T
+where
+    T: ~const Foo,
+{}
+
+impl<T> const Baz for T //~ ERROR conflicting implementations of trait `Baz`
+where
+    T: Foo,
+    T: Specialize,
+{}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr b/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr
new file mode 100644 (file)
index 0000000..4aea197
--- /dev/null
@@ -0,0 +1,18 @@
+error: missing `~const` qualifier for specialization
+  --> $DIR/const-default-bound-non-const-specialized-bound.rs:28:8
+   |
+LL |     T: Foo,
+   |        ^^^
+
+error[E0119]: conflicting implementations of trait `Baz`
+  --> $DIR/const-default-bound-non-const-specialized-bound.rs:40:1
+   |
+LL | impl<T> const Baz for T
+   | ----------------------- first implementation here
+...
+LL | impl<T> const Baz for T
+   | ^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.rs b/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.rs
new file mode 100644 (file)
index 0000000..9ddea42
--- /dev/null
@@ -0,0 +1,39 @@
+// Tests that a const default trait impl can be specialized by another const
+// trait impl and that the specializing impl will be used during const-eval.
+
+// run-pass
+
+#![feature(const_trait_impl)]
+#![feature(min_specialization)]
+
+#[const_trait]
+trait Value {
+    fn value() -> u32;
+}
+
+const fn get_value<T: ~const Value>() -> u32 {
+    T::value()
+}
+
+impl<T> const Value for T {
+    default fn value() -> u32 {
+        0
+    }
+}
+
+struct FortyTwo;
+
+impl const Value for FortyTwo {
+    fn value() -> u32 {
+        42
+    }
+}
+
+const ZERO: u32 = get_value::<()>();
+
+const FORTY_TWO: u32 = get_value::<FortyTwo>();
+
+fn main() {
+    assert_eq!(ZERO, 0);
+    assert_eq!(FORTY_TWO, 42);
+}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-impl-non-const-specialized-impl.rs b/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-impl-non-const-specialized-impl.rs
new file mode 100644 (file)
index 0000000..a3bb9b3
--- /dev/null
@@ -0,0 +1,26 @@
+// Tests that specializing trait impls must be at least as const as the default impl.
+
+#![feature(const_trait_impl)]
+#![feature(min_specialization)]
+
+#[const_trait]
+trait Value {
+    fn value() -> u32;
+}
+
+impl<T> const Value for T {
+    default fn value() -> u32 {
+        0
+    }
+}
+
+struct FortyTwo;
+
+impl Value for FortyTwo { //~ ERROR cannot specialize on const impl with non-const impl
+    fn value() -> u32 {
+        println!("You can't do that (constly)");
+        42
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-impl-non-const-specialized-impl.stderr b/src/test/ui/rfc-2632-const-trait-impl/specialization/const-default-impl-non-const-specialized-impl.stderr
new file mode 100644 (file)
index 0000000..2476680
--- /dev/null
@@ -0,0 +1,8 @@
+error: cannot specialize on const impl with non-const impl
+  --> $DIR/const-default-impl-non-const-specialized-impl.rs:19:1
+   |
+LL | impl Value for FortyTwo {
+   | ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/default-keyword.rs b/src/test/ui/rfc-2632-const-trait-impl/specialization/default-keyword.rs
new file mode 100644 (file)
index 0000000..2aac0a2
--- /dev/null
@@ -0,0 +1,15 @@
+// check-pass
+
+#![feature(const_trait_impl)]
+#![feature(min_specialization)]
+
+#[const_trait]
+trait Foo {
+    fn foo();
+}
+
+impl const Foo for u32 {
+    default fn foo() {}
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs b/src/test/ui/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs
new file mode 100644 (file)
index 0000000..9c2c2cf
--- /dev/null
@@ -0,0 +1,37 @@
+// Tests that `~const` trait bounds can be used to specialize const trait impls.
+
+// check-pass
+
+#![feature(const_trait_impl)]
+#![feature(rustc_attrs)]
+#![feature(min_specialization)]
+
+#[const_trait]
+#[rustc_specialization_trait]
+trait Specialize {}
+
+#[const_trait]
+trait Foo {}
+
+impl<T> const Foo for T {}
+
+impl<T> const Foo for T
+where
+    T: ~const Specialize,
+{}
+
+#[const_trait]
+trait Bar {}
+
+impl<T> const Bar for T
+where
+    T: ~const Foo,
+{}
+
+impl<T> const Bar for T
+where
+    T: ~const Foo,
+    T: ~const Specialize,
+{}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs b/src/test/ui/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs
new file mode 100644 (file)
index 0000000..1e6b1c6
--- /dev/null
@@ -0,0 +1,45 @@
+// Tests that `T: ~const Foo` in a specializing impl is treated as equivalent to
+// `T: Foo` in the default impl for the purposes of specialization (i.e., it
+// does not think that the user is attempting to specialize on trait `Foo`).
+
+// check-pass
+
+#![feature(rustc_attrs)]
+#![feature(min_specialization)]
+#![feature(const_trait_impl)]
+
+#[rustc_specialization_trait]
+trait Specialize {}
+
+#[const_trait]
+trait Foo {}
+
+#[const_trait]
+trait Bar {}
+
+impl<T> Bar for T
+where
+    T: Foo,
+{}
+
+impl<T> const Bar for T
+where
+    T: ~const Foo,
+    T: Specialize,
+{}
+
+#[const_trait]
+trait Baz {}
+
+impl<T> const Baz for T
+where
+    T: Foo,
+{}
+
+impl<T> const Baz for T
+where
+    T: ~const Foo,
+    T: Specialize,
+{}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.rs b/src/test/ui/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.rs
new file mode 100644 (file)
index 0000000..35aa52f
--- /dev/null
@@ -0,0 +1,39 @@
+// Tests that a non-const default impl can be specialized by a const trait impl,
+// but that the default impl cannot be used in a const context.
+
+// run-pass
+
+#![feature(const_trait_impl)]
+#![feature(min_specialization)]
+
+#[const_trait]
+trait Value {
+    fn value() -> u32;
+}
+
+const fn get_value<T: ~const Value>() -> u32 {
+    T::value()
+}
+
+impl<T> Value for T {
+    default fn value() -> u32 {
+        println!("You can't do that (constly)");
+        0
+    }
+}
+
+struct FortyTwo;
+
+impl const Value for FortyTwo {
+    fn value() -> u32 {
+        42
+    }
+}
+
+fn main() {
+    let zero = get_value::<()>();
+    assert_eq!(zero, 0);
+
+    const FORTY_TWO: u32 = get_value::<FortyTwo>();
+    assert_eq!(FORTY_TWO, 42);
+}
index ff0cd489d47440cd448e46f61675335f6f5a4930..9ab170f092006a05799cbca6298c1262b7b5ac93 100644 (file)
@@ -17,7 +17,9 @@ impl<T: ~const Default> const A for T {
     }
 }
 
-impl<T: Default + Sup> A for T { //~ ERROR: cannot specialize
+impl<T: Default + Sup> A for T {
+//~^ ERROR: cannot specialize
+//~| ERROR: missing `~const` qualifier
     fn a() -> u32 {
         3
     }
index 3296c109c4e7361bf7b2b4904577bf374725209b..843fc6ce84d45aa49c0531192b47877f3803d26f 100644 (file)
@@ -1,8 +1,14 @@
-error: cannot specialize on trait `Default`
+error: cannot specialize on const impl with non-const impl
+  --> $DIR/specializing-constness.rs:20:1
+   |
+LL | impl<T: Default + Sup> A for T {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing `~const` qualifier for specialization
   --> $DIR/specializing-constness.rs:20:9
    |
 LL | impl<T: Default + Sup> A for T {
    |         ^^^^^^^
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/sanitize/memory-passing.rs b/src/test/ui/sanitize/memory-passing.rs
new file mode 100644 (file)
index 0000000..6d9b70a
--- /dev/null
@@ -0,0 +1,32 @@
+// needs-sanitizer-support
+// needs-sanitizer-memory
+//
+// revisions: unoptimized optimized
+//
+// [optimized]compile-flags: -Z sanitizer=memory -Zsanitizer-memory-track-origins -O
+// [unoptimized]compile-flags: -Z sanitizer=memory -Zsanitizer-memory-track-origins
+//
+// run-pass
+//
+// This test case intentionally limits the usage of the std,
+// since it will be linked with an uninstrumented version of it.
+
+#![feature(core_intrinsics)]
+#![feature(start)]
+#![allow(invalid_value)]
+
+use std::hint::black_box;
+
+fn calling_black_box_on_zst_ok() {
+    // It's OK to call black_box on a value of a zero-sized type, even if its
+    // underlying the memory location is uninitialized. For non-zero-sized types,
+    // this would be an MSAN error.
+    let zst = ();
+    black_box(zst);
+}
+
+#[start]
+fn main(_: isize, _: *const *const u8) -> isize {
+    calling_black_box_on_zst_ok();
+    0
+}
index d501200d73cec9c2b536e277a58fdb1fc6a1c73e..063c3f013c5390474fc2b54f14ad2fbfe7bdd413 100644 (file)
@@ -10,6 +10,10 @@ error[E0425]: cannot find function `sleep` in this scope
 LL |       sleep();
    |       ^^^^^ not found in this scope
    |
+help: consider using the associated function
+   |
+LL |       self.sleep();
+   |       +++++
 help: consider importing this function
    |
 LL | use std::thread::sleep;
diff --git a/src/test/ui/sized/coinductive-1-gat.rs b/src/test/ui/sized/coinductive-1-gat.rs
new file mode 100644 (file)
index 0000000..cdf7092
--- /dev/null
@@ -0,0 +1,14 @@
+// check-pass
+struct Node<C: Trait>(C::Assoc::<Self>);
+
+trait Trait {
+    type Assoc<T>;
+}
+
+impl Trait for Vec<()> {
+    type Assoc<T> = Vec<T>;
+}
+
+fn main() {
+    let _ = Node::<Vec<()>>(Vec::new());
+}
diff --git a/src/test/ui/sized/coinductive-1.rs b/src/test/ui/sized/coinductive-1.rs
new file mode 100644 (file)
index 0000000..7bcd0f1
--- /dev/null
@@ -0,0 +1,14 @@
+// check-pass
+struct Node<C: Trait<Self>>(C::Assoc);
+
+trait Trait<T> {
+    type Assoc;
+}
+
+impl<T> Trait<T> for Vec<()> {
+    type Assoc = Vec<T>;
+}
+
+fn main() {
+    let _ = Node::<Vec<()>>(Vec::new());
+}
diff --git a/src/test/ui/sized/coinductive-2.rs b/src/test/ui/sized/coinductive-2.rs
new file mode 100644 (file)
index 0000000..212274d
--- /dev/null
@@ -0,0 +1,28 @@
+// run-pass
+struct Node<C: CollectionFactory<Self>> {
+    _children: C::Collection,
+}
+
+trait CollectionFactory<T> {
+    type Collection;
+}
+
+impl<T> CollectionFactory<T> for Vec<()> {
+    type Collection = Vec<T>;
+}
+
+trait Collection<T>: Sized {
+    fn push(&mut self, v: T);
+}
+
+impl<T> Collection<T> for Vec<T> {
+    fn push(&mut self, v: T) {
+        self.push(v)
+    }
+}
+
+fn main() {
+    let _ = Node::<Vec<()>> {
+        _children: Vec::new(),
+    };
+}
diff --git a/src/test/ui/sized/recursive-type-1.rs b/src/test/ui/sized/recursive-type-1.rs
new file mode 100644 (file)
index 0000000..cd68059
--- /dev/null
@@ -0,0 +1,10 @@
+// check-pass
+trait A { type Assoc; }
+
+impl A for () {
+    // FIXME: it would be nice for this to at least cause a warning.
+    type Assoc = Foo<()>;
+}
+struct Foo<T: A>(T::Assoc);
+
+fn main() {}
diff --git a/src/test/ui/sized/recursive-type-2.rs b/src/test/ui/sized/recursive-type-2.rs
new file mode 100644 (file)
index 0000000..7d95417
--- /dev/null
@@ -0,0 +1,13 @@
+// build-fail
+//~^ ERROR cycle detected when computing layout of `Foo<()>`
+
+trait A { type Assoc: ?Sized; }
+
+impl A for () {
+    type Assoc = Foo<()>;
+}
+struct Foo<T: A>(T::Assoc);
+
+fn main() {
+    let x: Foo<()>;
+}
diff --git a/src/test/ui/sized/recursive-type-2.stderr b/src/test/ui/sized/recursive-type-2.stderr
new file mode 100644 (file)
index 0000000..d0e6e9d
--- /dev/null
@@ -0,0 +1,13 @@
+error[E0391]: cycle detected when computing layout of `Foo<()>`
+   |
+   = note: ...which requires computing layout of `<() as A>::Assoc`...
+   = note: ...which again requires computing layout of `Foo<()>`, completing the cycle
+note: cycle used when elaborating drops for `main`
+  --> $DIR/recursive-type-2.rs:11:1
+   |
+LL | fn main() {
+   | ^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0391`.
index 6240f103c99b062a9b60bce70c161ef94efe65a8..18abfb5c3fbecb2c589e7bde35cc77e7b7008895 100644 (file)
@@ -18,7 +18,7 @@ fn f() {
 
     v3.push(&id('x'));           // statement 6
     //~^ ERROR temporary value dropped while borrowed
-    //~| NOTE creates a temporary which is freed while still in use
+    //~| NOTE creates a temporary value which is freed while still in use
     //~| NOTE temporary value is freed at the end of this statement
     //~| HELP consider using a `let` binding to create a longer lived value
 
@@ -28,7 +28,7 @@ fn f() {
 
         v4.push(&id('y'));
         //~^ ERROR temporary value dropped while borrowed
-        //~| NOTE creates a temporary which is freed while still in use
+        //~| NOTE creates a temporary value which is freed while still in use
         //~| NOTE temporary value is freed at the end of this statement
         //~| NOTE consider using a `let` binding to create a longer lived value
         v4.use_ref();
@@ -39,7 +39,7 @@ fn f() {
 
     v5.push(&id('z'));
     //~^ ERROR temporary value dropped while borrowed
-    //~| NOTE creates a temporary which is freed while still in use
+    //~| NOTE creates a temporary value which is freed while still in use
     //~| NOTE temporary value is freed at the end of this statement
     //~| HELP consider using a `let` binding to create a longer lived value
 
index a236dab3ae562ef96a19c2c7423c0a9169835dbb..2dc29a78d204d15a35b4e55818b8e29f76c8e6d3 100644 (file)
@@ -16,7 +16,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     v3.push(&id('x'));           // statement 6
    |              ^^^^^^^ - temporary value is freed at the end of this statement
    |              |
-   |              creates a temporary which is freed while still in use
+   |              creates a temporary value which is freed while still in use
 ...
 LL |     (v1, v2, v3, /* v4 is above. */ v5).use_ref();
    |              -- borrow later used here
@@ -33,7 +33,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |         v4.push(&id('y'));
    |                  ^^^^^^^ - temporary value is freed at the end of this statement
    |                  |
-   |                  creates a temporary which is freed while still in use
+   |                  creates a temporary value which is freed while still in use
 ...
 LL |         v4.use_ref();
    |         ------------ borrow later used here
@@ -46,7 +46,7 @@ error[E0716]: temporary value dropped while borrowed
 LL |     v5.push(&id('z'));
    |              ^^^^^^^ - temporary value is freed at the end of this statement
    |              |
-   |              creates a temporary which is freed while still in use
+   |              creates a temporary value which is freed while still in use
 ...
 LL |     (v1, v2, v3, /* v4 is above. */ v5).use_ref();
    |                                     -- borrow later used here
index cb5289d24b4fc4ee5ee9a3c272ba48860c43e791..25e344fedfb25e1e0eea58c3a6e78341caacd55f 100644 (file)
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/borrowck-ref-into-rvalue.rs:4:11
    |
 LL |     match Some("Hello".to_string()) {
-   |           ^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
 ...
 LL |     }
    |     - temporary value is freed at the end of this statement
index 460ad9ac7444502da198362c2f3273b317035134..d9cce2254dd95b802c955bb7d98fe366b7ea792f 100644 (file)
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/issue-15480.rs:6:10
    |
 LL |         &id(3)
-   |          ^^^^^ creates a temporary which is freed while still in use
+   |          ^^^^^ creates a temporary value which is freed while still in use
 LL |     ];
    |      - temporary value is freed at the end of this statement
 ...
index ba0c45acf237df7a447fe476558a17113ded0fbb..81e858fa0ce017d764d458eb5566757e7eda8d01 100644 (file)
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/regions-close-over-borrowed-ref-in-obj.rs:12:27
    |
 LL |         let ss: &isize = &id(1);
-   |                           ^^^^^ creates a temporary which is freed while still in use
+   |                           ^^^^^ creates a temporary value which is freed while still in use
 ...
 LL |     }
    |     - temporary value is freed at the end of this statement
index 27df25be3fa03580a44316b222127c7ac1efdcf1..b70bf69d688a5960acce607161fec561b4b5b00d 100644 (file)
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/slice-borrow.rs:6:28
    |
 LL |         let x: &[isize] = &vec![1, 2, 3, 4, 5];
-   |                            ^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |                            ^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
 ...
 LL |     }
    |     - temporary value is freed at the end of this statement
diff --git a/src/test/ui/static/issue-5216.rs b/src/test/ui/static/issue-5216.rs
new file mode 100644 (file)
index 0000000..4072a57
--- /dev/null
@@ -0,0 +1,10 @@
+fn f() { }
+struct S(Box<dyn FnMut() + Sync>);
+pub static C: S = S(f); //~ ERROR mismatched types
+
+
+fn g() { }
+type T = Box<dyn FnMut() + Sync>;
+pub static D: T = g; //~ ERROR mismatched types
+
+fn main() {}
diff --git a/src/test/ui/static/issue-5216.stderr b/src/test/ui/static/issue-5216.stderr
new file mode 100644 (file)
index 0000000..1afff28
--- /dev/null
@@ -0,0 +1,28 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-5216.rs:3:21
+   |
+LL | pub static C: S = S(f);
+   |                   - ^ expected struct `Box`, found fn item
+   |                   |
+   |                   arguments to this struct are incorrect
+   |
+   = note: expected struct `Box<(dyn FnMut() + Sync + 'static)>`
+             found fn item `fn() {f}`
+note: tuple struct defined here
+  --> $DIR/issue-5216.rs:2:8
+   |
+LL | struct S(Box<dyn FnMut() + Sync>);
+   |        ^
+
+error[E0308]: mismatched types
+  --> $DIR/issue-5216.rs:8:19
+   |
+LL | pub static D: T = g;
+   |                   ^ expected struct `Box`, found fn item
+   |
+   = note: expected struct `Box<(dyn FnMut() + Sync + 'static)>`
+             found fn item `fn() {g}`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
index 112bfc003048d0c7b885a5ae22d9f8ce17cb6509..cedcb7367949f51cfc1578233826a05731b367e6 100644 (file)
@@ -13,7 +13,7 @@ LL | static PROMOTION_FAIL_S: Option<&'static WithDtor> = Some(&WithDtor);
    |                                                      ------^^^^^^^^-
    |                                                      |     |       |
    |                                                      |     |       temporary value is freed at the end of this statement
-   |                                                      |     creates a temporary which is freed while still in use
+   |                                                      |     creates a temporary value which is freed while still in use
    |                                                      using this value as a static requires that borrow lasts for `'static`
 
 error[E0493]: destructor of `WithDtor` cannot be evaluated at compile-time
@@ -31,7 +31,7 @@ LL | const PROMOTION_FAIL_C: Option<&'static WithDtor> = Some(&WithDtor);
    |                                                     ------^^^^^^^^-
    |                                                     |     |       |
    |                                                     |     |       temporary value is freed at the end of this statement
-   |                                                     |     creates a temporary which is freed while still in use
+   |                                                     |     creates a temporary value which is freed while still in use
    |                                                     using this value as a constant requires that borrow lasts for `'static`
 
 error[E0493]: destructor of `(WithDtor, i32)` cannot be evaluated at compile-time
index ff15884bd445d1ca3ace54e8f2348db6f0d5314a..133d8ec2e1e519bf4d6f58cc55b7a59a369b9c92 100644 (file)
@@ -6,7 +6,7 @@ LL | fn state1(self_: &mut StateMachineIter) -> Option<&'static str> {
 LL |     self_.statefn = &id(state2 as StateMachineFunc);
    |     -----------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement
    |     |                |
-   |     |                creates a temporary which is freed while still in use
+   |     |                creates a temporary value which is freed while still in use
    |     assignment requires that borrow lasts for `'1`
 
 error[E0716]: temporary value dropped while borrowed
@@ -17,7 +17,7 @@ LL | fn state2(self_: &mut StateMachineIter) -> Option<(&'static str)> {
 LL |     self_.statefn = &id(state3 as StateMachineFunc);
    |     -----------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement
    |     |                |
-   |     |                creates a temporary which is freed while still in use
+   |     |                creates a temporary value which is freed while still in use
    |     assignment requires that borrow lasts for `'1`
 
 error[E0716]: temporary value dropped while borrowed
@@ -28,7 +28,7 @@ LL | fn state3(self_: &mut StateMachineIter) -> Option<(&'static str)> {
 LL |     self_.statefn = &id(finished as StateMachineFunc);
    |     -----------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement
    |     |                |
-   |     |                creates a temporary which is freed while still in use
+   |     |                creates a temporary value which is freed while still in use
    |     assignment requires that borrow lasts for `'1`
 
 error[E0515]: cannot return value referencing temporary value
index 15261259ed412acaeab624d9e572ea60890f698e..1a607e3c014a3134006f59b3e899adfd4733f974 100644 (file)
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/static-region-bound.rs:10:14
    |
 LL |     let x = &id(3);
-   |              ^^^^^ creates a temporary which is freed while still in use
+   |              ^^^^^ creates a temporary value which is freed while still in use
 LL |     f(x);
    |     ---- argument requires that borrow lasts for `'static`
 LL | }
index 6f92fbb1eb689f81c3c6bd45c83720265d458b8a..2d29dec888e8d32f40f110e71278cd85aa231701 100644 (file)
@@ -2,7 +2,7 @@ error[E0716]: temporary value dropped while borrowed
   --> $DIR/issue-44373.rs:4:42
    |
 LL |     let _val: &'static [&'static u32] = &[&FOO];
-   |               -----------------------    ^^^^^^ creates a temporary which is freed while still in use
+   |               -----------------------    ^^^^^^ creates a temporary value which is freed while still in use
    |               |
    |               type annotation requires that borrow lasts for `'static`
 LL | }
index 88920b852905be955928e756c18aaf04cbaf21e6..febdd67338c991263c9f398ad89c7db59b988f4a 100644 (file)
@@ -7,13 +7,18 @@ LL |         foo();
 help: consider using the associated function
    |
 LL |         Self::foo();
-   |         ~~~~~~~~~
+   |         ++++++
 
 error[E0425]: cannot find function `bar` in this scope
   --> $DIR/assoc_fn_without_self.rs:17:9
    |
 LL |         bar();
    |         ^^^ not found in this scope
+   |
+help: consider using the associated function
+   |
+LL |         self.bar();
+   |         +++++
 
 error[E0425]: cannot find function `baz` in this scope
   --> $DIR/assoc_fn_without_self.rs:18:9
@@ -24,7 +29,7 @@ LL |         baz(2, 3);
 help: consider using the associated function
    |
 LL |         Self::baz(2, 3);
-   |         ~~~~~~~~~
+   |         ++++++
 
 error[E0425]: cannot find function `foo` in this scope
   --> $DIR/assoc_fn_without_self.rs:14:13
index 3d9ac40ec367bf15ff54bb4fa6f075878abdf44b..02148b7f7adfd97a68e02a58102a3b28ab0599f8 100644 (file)
@@ -25,12 +25,22 @@ error[E0308]: mismatched types
    |
 LL |     if Some(x) = foo {}
    |        ^^^^^^^^^^^^^ expected `bool`, found `()`
+   |
+help: consider adding `let`
+   |
+LL |     if let Some(x) = foo {}
+   |        +++
 
 error[E0308]: mismatched types
   --> $DIR/if-let-typo.rs:6:8
    |
 LL |     if Some(foo) = bar {}
    |        ^^^^^^^^^^^^^^^ expected `bool`, found `()`
+   |
+help: consider adding `let`
+   |
+LL |     if let Some(foo) = bar {}
+   |        +++
 
 error[E0308]: mismatched types
   --> $DIR/if-let-typo.rs:7:8
@@ -51,6 +61,11 @@ error[E0308]: mismatched types
    |
 LL |     if Some(3) = foo {}
    |        ^^^^^^^^^^^^^ expected `bool`, found `()`
+   |
+help: consider adding `let`
+   |
+LL |     if let Some(3) = foo {}
+   |        +++
 
 error: aborting due to 7 previous errors
 
index c56ea7c030d8e1b685dd34df73e7ddf95e9569cc..fac68c053eb4f4f952176bf59041a40e62da2084 100644 (file)
@@ -22,5 +22,5 @@ fn main() {
     let item = std::mem::MaybeUninit::new(Struct { p: 42_u32 });
     item.method();
     //~^ ERROR no method named `method` found for union `MaybeUninit` in the current scope [E0599]
-    //~| HELP if this `MaybeUninit::<Struct<u32>>` has been initialized, use one of the `assume_init` methods to access the inner value
+    //~| HELP if this `MaybeUninit<Struct<u32>>` has been initialized, use one of the `assume_init` methods to access the inner value
 }
index eddfd9d63409d3d6eca49c29c3317ce2e4562e58..984366123c82793f649f37d47c06b8fa017d0870 100644 (file)
@@ -17,7 +17,7 @@ error[E0599]: no method named `method` found for union `MaybeUninit` in the curr
 LL |     item.method();
    |          ^^^^^^ method not found in `MaybeUninit<Struct<u32>>`
    |
-   = help: if this `MaybeUninit::<Struct<u32>>` has been initialized, use one of the `assume_init` methods to access the inner value
+   = help: if this `MaybeUninit<Struct<u32>>` has been initialized, use one of the `assume_init` methods to access the inner value
 note: the method `method` exists on the type `Struct<u32>`
   --> $DIR/inner_type2.rs:6:5
    |
index 4f76c5f2e75b2341ca846903592b1a299757d024..b17c4dc5dfb50998df9cca962e3023e696215420 100644 (file)
@@ -13,7 +13,7 @@ LL |     fn func() {}
 help: use associated function syntax instead
    |
 LL |     i32::func();
-   |     ~~~~~~~~~
+   |     ~~~~~~~~~~~
 help: disambiguate the associated function for the candidate
    |
 LL |     <i32 as Trait>::func(x);
diff --git a/src/test/ui/suggestions/issue-104086-suggest-let.rs b/src/test/ui/suggestions/issue-104086-suggest-let.rs
new file mode 100644 (file)
index 0000000..d22ad27
--- /dev/null
@@ -0,0 +1,30 @@
+fn main() {
+    x = x = x;
+    //~^ ERROR cannot find value `x` in this scope
+    //~| ERROR cannot find value `x` in this scope
+    //~| ERROR cannot find value `x` in this scope
+
+    x = y = y = y;
+    //~^ ERROR cannot find value `y` in this scope
+    //~| ERROR cannot find value `y` in this scope
+    //~| ERROR cannot find value `y` in this scope
+    //~| ERROR cannot find value `x` in this scope
+
+    x = y = y;
+    //~^ ERROR cannot find value `x` in this scope
+    //~| ERROR cannot find value `y` in this scope
+    //~| ERROR cannot find value `y` in this scope
+
+    x = x = y;
+    //~^ ERROR cannot find value `x` in this scope
+    //~| ERROR cannot find value `x` in this scope
+    //~| ERROR cannot find value `y` in this scope
+
+    x = x; // will suggest add `let`
+    //~^ ERROR cannot find value `x` in this scope
+    //~| ERROR cannot find value `x` in this scope
+
+    x = y // will suggest add `let`
+    //~^ ERROR cannot find value `x` in this scope
+    //~| ERROR cannot find value `y` in this scope
+}
diff --git a/src/test/ui/suggestions/issue-104086-suggest-let.stderr b/src/test/ui/suggestions/issue-104086-suggest-let.stderr
new file mode 100644 (file)
index 0000000..fb4ea31
--- /dev/null
@@ -0,0 +1,135 @@
+error[E0425]: cannot find value `x` in this scope
+  --> $DIR/issue-104086-suggest-let.rs:2:5
+   |
+LL |     x = x = x;
+   |     ^
+   |
+help: you might have meant to introduce a new binding
+   |
+LL |     let x = x = x;
+   |     +++
+
+error[E0425]: cannot find value `x` in this scope
+  --> $DIR/issue-104086-suggest-let.rs:2:9
+   |
+LL |     x = x = x;
+   |         ^ not found in this scope
+
+error[E0425]: cannot find value `x` in this scope
+  --> $DIR/issue-104086-suggest-let.rs:2:13
+   |
+LL |     x = x = x;
+   |             ^ not found in this scope
+
+error[E0425]: cannot find value `x` in this scope
+  --> $DIR/issue-104086-suggest-let.rs:7:5
+   |
+LL |     x = y = y = y;
+   |     ^
+   |
+help: you might have meant to introduce a new binding
+   |
+LL |     let x = y = y = y;
+   |     +++
+
+error[E0425]: cannot find value `y` in this scope
+  --> $DIR/issue-104086-suggest-let.rs:7:9
+   |
+LL |     x = y = y = y;
+   |         ^ not found in this scope
+
+error[E0425]: cannot find value `y` in this scope
+  --> $DIR/issue-104086-suggest-let.rs:7:13
+   |
+LL |     x = y = y = y;
+   |             ^ not found in this scope
+
+error[E0425]: cannot find value `y` in this scope
+  --> $DIR/issue-104086-suggest-let.rs:7:17
+   |
+LL |     x = y = y = y;
+   |                 ^ not found in this scope
+
+error[E0425]: cannot find value `x` in this scope
+  --> $DIR/issue-104086-suggest-let.rs:13:5
+   |
+LL |     x = y = y;
+   |     ^
+   |
+help: you might have meant to introduce a new binding
+   |
+LL |     let x = y = y;
+   |     +++
+
+error[E0425]: cannot find value `y` in this scope
+  --> $DIR/issue-104086-suggest-let.rs:13:9
+   |
+LL |     x = y = y;
+   |         ^ not found in this scope
+
+error[E0425]: cannot find value `y` in this scope
+  --> $DIR/issue-104086-suggest-let.rs:13:13
+   |
+LL |     x = y = y;
+   |             ^ not found in this scope
+
+error[E0425]: cannot find value `x` in this scope
+  --> $DIR/issue-104086-suggest-let.rs:18:5
+   |
+LL |     x = x = y;
+   |     ^
+   |
+help: you might have meant to introduce a new binding
+   |
+LL |     let x = x = y;
+   |     +++
+
+error[E0425]: cannot find value `x` in this scope
+  --> $DIR/issue-104086-suggest-let.rs:18:9
+   |
+LL |     x = x = y;
+   |         ^ not found in this scope
+
+error[E0425]: cannot find value `y` in this scope
+  --> $DIR/issue-104086-suggest-let.rs:18:13
+   |
+LL |     x = x = y;
+   |             ^ not found in this scope
+
+error[E0425]: cannot find value `x` in this scope
+  --> $DIR/issue-104086-suggest-let.rs:23:5
+   |
+LL |     x = x; // will suggest add `let`
+   |     ^
+   |
+help: you might have meant to introduce a new binding
+   |
+LL |     let x = x; // will suggest add `let`
+   |     +++
+
+error[E0425]: cannot find value `x` in this scope
+  --> $DIR/issue-104086-suggest-let.rs:23:9
+   |
+LL |     x = x; // will suggest add `let`
+   |         ^ not found in this scope
+
+error[E0425]: cannot find value `x` in this scope
+  --> $DIR/issue-104086-suggest-let.rs:27:5
+   |
+LL |     x = y // will suggest add `let`
+   |     ^
+   |
+help: you might have meant to introduce a new binding
+   |
+LL |     let x = y // will suggest add `let`
+   |     +++
+
+error[E0425]: cannot find value `y` in this scope
+  --> $DIR/issue-104086-suggest-let.rs:27:9
+   |
+LL |     x = y // will suggest add `let`
+   |         ^ not found in this scope
+
+error: aborting due to 17 previous errors
+
+For more information about this error, try `rustc --explain E0425`.
index fd5d46a4e923e8fdc295f2befb66eaed6b73ee13..c4105186244db3bd170af04d24875401755c386a 100644 (file)
@@ -2,17 +2,17 @@
 
 fn main() {
     b'µ';
-    //~^ ERROR: non-ASCII character in byte constant
+    //~^ ERROR: non-ASCII character in byte literal
     //~| HELP: if you meant to use the unicode code point for 'µ', use a \xHH escape
-    //~| NOTE: byte constant must be ASCII
+    //~| NOTE: must be ASCII
 
     b'字';
-    //~^ ERROR: non-ASCII character in byte constant
+    //~^ ERROR: non-ASCII character in byte literal
     //~| NOTE: this multibyte character does not fit into a single byte
-    //~| NOTE: byte constant must be ASCII
+    //~| NOTE: must be ASCII
 
     b"字";
-    //~^ ERROR: non-ASCII character in byte constant
+    //~^ ERROR: non-ASCII character in byte string literal
     //~| HELP: if you meant to use the UTF-8 encoding of '字', use \xHH escapes
-    //~| NOTE: byte constant must be ASCII
+    //~| NOTE: must be ASCII
 }
index 6e26bc1f01cef5abfda10bbf8d9d5990af2d9ae8..1e7c43e6538f697f6820fab8f9eaea5297329604 100644 (file)
@@ -1,28 +1,28 @@
-error: non-ASCII character in byte constant
+error: non-ASCII character in byte literal
   --> $DIR/multibyte-escapes.rs:4:7
    |
 LL |     b'µ';
-   |       ^ byte constant must be ASCII
+   |       ^ must be ASCII
    |
 help: if you meant to use the unicode code point for 'µ', use a \xHH escape
    |
 LL |     b'\xB5';
    |       ~~~~
 
-error: non-ASCII character in byte constant
+error: non-ASCII character in byte literal
   --> $DIR/multibyte-escapes.rs:9:7
    |
 LL |     b'字';
    |       ^^
    |       |
-   |       byte constant must be ASCII
+   |       must be ASCII
    |       this multibyte character does not fit into a single byte
 
-error: non-ASCII character in byte constant
+error: non-ASCII character in byte string literal
   --> $DIR/multibyte-escapes.rs:14:7
    |
 LL |     b"字";
-   |       ^^ byte constant must be ASCII
+   |       ^^ must be ASCII
    |
 help: if you meant to use the UTF-8 encoding of '字', use \xHH escapes
    |
diff --git a/src/test/ui/suggestions/option-to-bool.rs b/src/test/ui/suggestions/option-to-bool.rs
new file mode 100644 (file)
index 0000000..2a1823b
--- /dev/null
@@ -0,0 +1,9 @@
+#![cfg_attr(let_chains, feature(let_chains))]
+
+fn foo(x: Option<i32>) {
+    if true && x {}
+    //~^ ERROR mismatched types
+    //~| HELP use `Option::is_some` to test if the `Option` has a value
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/option-to-bool.stderr b/src/test/ui/suggestions/option-to-bool.stderr
new file mode 100644 (file)
index 0000000..57a934b
--- /dev/null
@@ -0,0 +1,16 @@
+error[E0308]: mismatched types
+  --> $DIR/option-to-bool.rs:4:16
+   |
+LL |     if true && x {}
+   |                ^ expected `bool`, found enum `Option`
+   |
+   = note: expected type `bool`
+              found enum `Option<i32>`
+help: use `Option::is_some` to test if the `Option` has a value
+   |
+LL |     if true && x.is_some() {}
+   |                 ++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish-placeholder.rs b/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish-placeholder.rs
new file mode 100644 (file)
index 0000000..a39b871
--- /dev/null
@@ -0,0 +1,11 @@
+struct GenericAssocMethod<T>(T);
+
+impl<T> GenericAssocMethod<T> {
+    fn default_hello() {}
+}
+
+fn main() {
+    let x = GenericAssocMethod(33);
+    x.default_hello();
+    //~^ ERROR no method named `default_hello` found
+}
diff --git a/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish-placeholder.stderr b/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish-placeholder.stderr
new file mode 100644 (file)
index 0000000..c247e73
--- /dev/null
@@ -0,0 +1,22 @@
+error[E0599]: no method named `default_hello` found for struct `GenericAssocMethod<{integer}>` in the current scope
+  --> $DIR/suggest-assoc-fn-call-with-turbofish-placeholder.rs:9:7
+   |
+LL | struct GenericAssocMethod<T>(T);
+   | ---------------------------- method `default_hello` not found for this struct
+...
+LL |     x.default_hello();
+   |     --^^^^^^^^^^^^^--
+   |     | |
+   |     | this is an associated function, not a method
+   |     help: use associated function syntax instead: `GenericAssocMethod::<_>::default_hello()`
+   |
+   = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
+note: the candidate is defined in an impl for the type `GenericAssocMethod<T>`
+  --> $DIR/suggest-assoc-fn-call-with-turbofish-placeholder.rs:4:5
+   |
+LL |     fn default_hello() {}
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
index 996d57731187d824bfcdaea24187a161a7e1fac1..7c9f0b6c212e102037faef5e9f3f1bff2444a778 100644 (file)
@@ -2,10 +2,10 @@ error[E0599]: no method named `hello` found for struct `RefMut<'_, HasAssocMetho
   --> $DIR/suggest-assoc-fn-call-with-turbofish-through-deref.rs:11:11
    |
 LL |     state.hello();
-   |     ------^^^^^
+   |     ------^^^^^--
    |     |     |
    |     |     this is an associated function, not a method
-   |     help: use associated function syntax instead: `HasAssocMethod::hello`
+   |     help: use associated function syntax instead: `HasAssocMethod::hello()`
    |
    = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
 note: the candidate is defined in an impl for the type `HasAssocMethod`
diff --git a/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish.fixed b/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish.fixed
new file mode 100644 (file)
index 0000000..02dd071
--- /dev/null
@@ -0,0 +1,26 @@
+// run-rustfix
+
+struct GenericAssocMethod<T>(T);
+
+impl<T> GenericAssocMethod<T> {
+    fn default_hello() {}
+    fn self_ty_hello(_: Self) {}
+    fn self_ty_ref_hello(_: &Self) {}
+}
+
+fn main() {
+    // Test for inferred types
+    let x = GenericAssocMethod(33);
+    GenericAssocMethod::<_>::self_ty_ref_hello(&x);
+    //~^ ERROR no method named `self_ty_ref_hello` found
+    GenericAssocMethod::<_>::self_ty_hello(x);
+    //~^ ERROR no method named `self_ty_hello` found
+    // Test for known types
+    let y = GenericAssocMethod(33i32);
+    GenericAssocMethod::<i32>::default_hello();
+    //~^ ERROR no method named `default_hello` found
+    GenericAssocMethod::<i32>::self_ty_ref_hello(&y);
+    //~^ ERROR no method named `self_ty_ref_hello` found
+    GenericAssocMethod::<i32>::self_ty_hello(y);
+    //~^ ERROR no method named `self_ty_hello` found
+}
index 2a829db538390e6178c170477bf08b498018b022..1d0ca8e780abf85a88dab2bab833a6d763baa835 100644 (file)
@@ -1,11 +1,26 @@
+// run-rustfix
+
 struct GenericAssocMethod<T>(T);
 
 impl<T> GenericAssocMethod<T> {
     fn default_hello() {}
+    fn self_ty_hello(_: Self) {}
+    fn self_ty_ref_hello(_: &Self) {}
 }
 
 fn main() {
-    let x = GenericAssocMethod(33i32);
-    x.default_hello();
+    // Test for inferred types
+    let x = GenericAssocMethod(33);
+    x.self_ty_ref_hello();
+    //~^ ERROR no method named `self_ty_ref_hello` found
+    x.self_ty_hello();
+    //~^ ERROR no method named `self_ty_hello` found
+    // Test for known types
+    let y = GenericAssocMethod(33i32);
+    y.default_hello();
     //~^ ERROR no method named `default_hello` found
+    y.self_ty_ref_hello();
+    //~^ ERROR no method named `self_ty_ref_hello` found
+    y.self_ty_hello();
+    //~^ ERROR no method named `self_ty_hello` found
 }
index 3fb418b1c0aac03b2219acdd070ce2d7462865e6..92b03fc77142c3f4bf7f6a260fa69bbe1babd4b1 100644 (file)
@@ -1,22 +1,98 @@
+error[E0599]: no method named `self_ty_ref_hello` found for struct `GenericAssocMethod<{integer}>` in the current scope
+  --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:14:7
+   |
+LL | struct GenericAssocMethod<T>(T);
+   | ---------------------------- method `self_ty_ref_hello` not found for this struct
+...
+LL |     x.self_ty_ref_hello();
+   |     --^^^^^^^^^^^^^^^^^--
+   |     | |
+   |     | this is an associated function, not a method
+   |     help: use associated function syntax instead: `GenericAssocMethod::<_>::self_ty_ref_hello(&x)`
+   |
+   = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
+note: the candidate is defined in an impl for the type `GenericAssocMethod<T>`
+  --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:8:5
+   |
+LL |     fn self_ty_ref_hello(_: &Self) {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0599]: no method named `self_ty_hello` found for struct `GenericAssocMethod<{integer}>` in the current scope
+  --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:16:7
+   |
+LL | struct GenericAssocMethod<T>(T);
+   | ---------------------------- method `self_ty_hello` not found for this struct
+...
+LL |     x.self_ty_hello();
+   |     --^^^^^^^^^^^^^--
+   |     | |
+   |     | this is an associated function, not a method
+   |     help: use associated function syntax instead: `GenericAssocMethod::<_>::self_ty_hello(x)`
+   |
+   = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
+note: the candidate is defined in an impl for the type `GenericAssocMethod<T>`
+  --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:7:5
+   |
+LL |     fn self_ty_hello(_: Self) {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error[E0599]: no method named `default_hello` found for struct `GenericAssocMethod<i32>` in the current scope
-  --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:9:7
+  --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:20:7
    |
 LL | struct GenericAssocMethod<T>(T);
    | ---------------------------- method `default_hello` not found for this struct
 ...
-LL |     x.default_hello();
-   |     --^^^^^^^^^^^^^
+LL |     y.default_hello();
+   |     --^^^^^^^^^^^^^--
    |     | |
    |     | this is an associated function, not a method
-   |     help: use associated function syntax instead: `GenericAssocMethod::<i32>::default_hello`
+   |     help: use associated function syntax instead: `GenericAssocMethod::<i32>::default_hello()`
    |
    = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
 note: the candidate is defined in an impl for the type `GenericAssocMethod<T>`
-  --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:4:5
+  --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:6:5
    |
 LL |     fn default_hello() {}
    |     ^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error
+error[E0599]: no method named `self_ty_ref_hello` found for struct `GenericAssocMethod<i32>` in the current scope
+  --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:22:7
+   |
+LL | struct GenericAssocMethod<T>(T);
+   | ---------------------------- method `self_ty_ref_hello` not found for this struct
+...
+LL |     y.self_ty_ref_hello();
+   |     --^^^^^^^^^^^^^^^^^--
+   |     | |
+   |     | this is an associated function, not a method
+   |     help: use associated function syntax instead: `GenericAssocMethod::<i32>::self_ty_ref_hello(&y)`
+   |
+   = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
+note: the candidate is defined in an impl for the type `GenericAssocMethod<T>`
+  --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:8:5
+   |
+LL |     fn self_ty_ref_hello(_: &Self) {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0599]: no method named `self_ty_hello` found for struct `GenericAssocMethod<i32>` in the current scope
+  --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:24:7
+   |
+LL | struct GenericAssocMethod<T>(T);
+   | ---------------------------- method `self_ty_hello` not found for this struct
+...
+LL |     y.self_ty_hello();
+   |     --^^^^^^^^^^^^^--
+   |     | |
+   |     | this is an associated function, not a method
+   |     help: use associated function syntax instead: `GenericAssocMethod::<i32>::self_ty_hello(y)`
+   |
+   = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
+note: the candidate is defined in an impl for the type `GenericAssocMethod<T>`
+  --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:7:5
+   |
+LL |     fn self_ty_hello(_: Self) {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/suggestions/unnecessary_dot_for_floating_point_literal.rs b/src/test/ui/suggestions/unnecessary_dot_for_floating_point_literal.rs
new file mode 100644 (file)
index 0000000..c1a9445
--- /dev/null
@@ -0,0 +1,6 @@
+fn main() {
+    let _: f64 = 0..10; //~ ERROR mismatched types
+    let _: f64 = 1..; //~ ERROR mismatched types
+    let _: f64 = ..10; //~ ERROR mismatched types
+    let _: f64 = std::ops::Range { start: 0, end: 1 }; //~ ERROR mismatched types
+}
diff --git a/src/test/ui/suggestions/unnecessary_dot_for_floating_point_literal.stderr b/src/test/ui/suggestions/unnecessary_dot_for_floating_point_literal.stderr
new file mode 100644 (file)
index 0000000..773f139
--- /dev/null
@@ -0,0 +1,59 @@
+error[E0308]: mismatched types
+  --> $DIR/unnecessary_dot_for_floating_point_literal.rs:2:18
+   |
+LL |     let _: f64 = 0..10;
+   |            ---   ^^^^^ expected `f64`, found struct `std::ops::Range`
+   |            |
+   |            expected due to this
+   |
+   = note: expected type `f64`
+            found struct `std::ops::Range<{integer}>`
+help: remove the unnecessary `.` operator for a floating point literal
+   |
+LL |     let _: f64 = 0.10;
+   |                   ~
+
+error[E0308]: mismatched types
+  --> $DIR/unnecessary_dot_for_floating_point_literal.rs:3:18
+   |
+LL |     let _: f64 = 1..;
+   |            ---   ^^^ expected `f64`, found struct `RangeFrom`
+   |            |
+   |            expected due to this
+   |
+   = note: expected type `f64`
+            found struct `RangeFrom<{integer}>`
+help: remove the unnecessary `.` operator for a floating point literal
+   |
+LL |     let _: f64 = 1.;
+   |                   ~
+
+error[E0308]: mismatched types
+  --> $DIR/unnecessary_dot_for_floating_point_literal.rs:4:18
+   |
+LL |     let _: f64 = ..10;
+   |            ---   ^^^^ expected `f64`, found struct `RangeTo`
+   |            |
+   |            expected due to this
+   |
+   = note: expected type `f64`
+            found struct `RangeTo<{integer}>`
+help: remove the unnecessary `.` operator and add an integer part for a floating point literal
+   |
+LL |     let _: f64 = 0.10;
+   |                  ~~
+
+error[E0308]: mismatched types
+  --> $DIR/unnecessary_dot_for_floating_point_literal.rs:5:18
+   |
+LL |     let _: f64 = std::ops::Range { start: 0, end: 1 };
+   |            ---   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `f64`, found struct `std::ops::Range`
+   |            |
+   |            expected due to this
+   |
+   = note: expected type `f64`
+            found struct `std::ops::Range<{integer}>`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
index 0cc901eecaa2cc072b15a997518b536dea8519d7..b4b50d98192b1b0eca22229899409b553bc3daf0 100644 (file)
@@ -1,4 +1,4 @@
-error: target features paca, pacg must all be enabled or disabled together
+error: the target features paca, pacg must all be either enabled or disabled together
 
 error: aborting due to previous error
 
index 0cc901eecaa2cc072b15a997518b536dea8519d7..b4b50d98192b1b0eca22229899409b553bc3daf0 100644 (file)
@@ -1,4 +1,4 @@
-error: target features paca, pacg must all be enabled or disabled together
+error: the target features paca, pacg must all be either enabled or disabled together
 
 error: aborting due to previous error
 
index 0cc901eecaa2cc072b15a997518b536dea8519d7..b4b50d98192b1b0eca22229899409b553bc3daf0 100644 (file)
@@ -1,4 +1,4 @@
-error: target features paca, pacg must all be enabled or disabled together
+error: the target features paca, pacg must all be either enabled or disabled together
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/traits/invalid_operator_trait.rs b/src/test/ui/traits/invalid_operator_trait.rs
new file mode 100644 (file)
index 0000000..7ea3b0d
--- /dev/null
@@ -0,0 +1,23 @@
+#![crate_type = "lib"]
+#![feature(lang_items)]
+#![feature(no_core)]
+#![no_core]
+
+#[lang="sized"]
+pub trait Sized {
+    // Empty.
+}
+
+#[lang = "add"]
+trait Add<RHS=Self> {
+    type Output;
+
+    fn add<Y>(self, _: RHS) -> Self::Output;
+    //~^ ERROR `add` must not have any generic parameters
+}
+
+#[allow(unreachable_code)]
+fn ice(a: usize) {
+    let r = loop {};
+    r = r + a;
+}
diff --git a/src/test/ui/traits/invalid_operator_trait.stderr b/src/test/ui/traits/invalid_operator_trait.stderr
new file mode 100644 (file)
index 0000000..8c6e369
--- /dev/null
@@ -0,0 +1,8 @@
+error: `add` must not have any generic parameters
+  --> $DIR/invalid_operator_trait.rs:15:5
+   |
+LL |     fn add<Y>(self, _: RHS) -> Self::Output;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/traits/issue-7013.rs b/src/test/ui/traits/issue-7013.rs
new file mode 100644 (file)
index 0000000..1fb0130
--- /dev/null
@@ -0,0 +1,26 @@
+use std::cell::RefCell;
+use std::rc::Rc;
+
+trait Foo {
+    fn set(&mut self, v: Rc<RefCell<A>>);
+}
+
+struct B {
+    v: Option<Rc<RefCell<A>>>
+}
+
+impl Foo for B {
+    fn set(&mut self, v: Rc<RefCell<A>>)
+    {
+        self.v = Some(v);
+    }
+}
+
+struct A {
+    v: Box<dyn Foo + Send>,
+}
+
+fn main() {
+    let a = A {v: Box::new(B{v: None}) as Box<dyn Foo + Send>};
+    //~^ ERROR `Rc<RefCell<A>>` cannot be sent between threads safely
+}
diff --git a/src/test/ui/traits/issue-7013.stderr b/src/test/ui/traits/issue-7013.stderr
new file mode 100644 (file)
index 0000000..4575f4d
--- /dev/null
@@ -0,0 +1,18 @@
+error[E0277]: `Rc<RefCell<A>>` cannot be sent between threads safely
+  --> $DIR/issue-7013.rs:24:19
+   |
+LL |     let a = A {v: Box::new(B{v: None}) as Box<dyn Foo + Send>};
+   |                   ^^^^^^^^^^^^^^^^^^^^ `Rc<RefCell<A>>` cannot be sent between threads safely
+   |
+   = help: within `B`, the trait `Send` is not implemented for `Rc<RefCell<A>>`
+   = note: required because it appears within the type `Option<Rc<RefCell<A>>>`
+note: required because it appears within the type `B`
+  --> $DIR/issue-7013.rs:8:8
+   |
+LL | struct B {
+   |        ^
+   = note: required for the cast from `B` to the object type `dyn Foo + Send`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
index e210f11b3e0c12a49439fc5f7144d2c7453802c4..b6a04585583c933079d52ac7c76cffeefe53938e 100644 (file)
@@ -46,12 +46,7 @@ LL |     let ips: Vec<_> = (0..100_000).map(|_| u32::from(0u32.into())).collect(
    |                                            |
    |                                            required by a bound introduced by this call
    |
-   = note: multiple `impl`s satisfying `u32: From<_>` found in the following crates: `core`, `std`:
-           - impl From<Ipv4Addr> for u32;
-           - impl From<NonZeroU32> for u32;
-           - impl From<bool> for u32;
-           - impl From<char> for u32;
-           and 3 more
+   = note: cannot satisfy `u32: From<_>`
 help: try using a fully qualified path to specify the expected types
    |
 LL |     let ips: Vec<_> = (0..100_000).map(|_| u32::from(<u32 as Into<T>>::into(0u32))).collect();
index c8289b2e30b4d41e1c35eeb2ea43a55b3ec34b99..37bae2e90a595a0252eabf1f907ff6b59857ce37 100644 (file)
@@ -1,10 +1,12 @@
+// check-pass
+
 trait A<Y, N> {
     type B;
 }
 
 type MaybeBox<T> = <T as A<T, Box<T>>>::B;
 struct P {
-    t: MaybeBox<P>, //~ ERROR: overflow evaluating the requirement `P: Sized`
+    t: MaybeBox<P>,
 }
 
 impl<Y, N> A<Y, N> for P {
diff --git a/src/test/ui/traits/issue-82830.stderr b/src/test/ui/traits/issue-82830.stderr
deleted file mode 100644 (file)
index 6a597a4..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-error[E0275]: overflow evaluating the requirement `P: Sized`
-  --> $DIR/issue-82830.rs:7:8
-   |
-LL |     t: MaybeBox<P>,
-   |        ^^^^^^^^^^^
-   |
-note: required for `P` to implement `A<P, Box<P>>`
-  --> $DIR/issue-82830.rs:10:12
-   |
-LL | impl<Y, N> A<Y, N> for P {
-   |            ^^^^^^^     ^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0275`.
diff --git a/src/test/ui/traits/suggest-fully-qualified-closure.rs b/src/test/ui/traits/suggest-fully-qualified-closure.rs
new file mode 100644 (file)
index 0000000..c077921
--- /dev/null
@@ -0,0 +1,24 @@
+// check-fail
+// known-bug: #103705
+// normalize-stderr-test "\[closure@.*\]" -> "[closure@]"
+// normalize-stderr-test "\+* ~" -> "+++ ~"
+
+// The output of this currently suggests writing a closure in the qualified path.
+
+trait MyTrait<T> {
+   fn lol<F:FnOnce()>(&self, f:F) -> u16;
+}
+
+struct Qqq;
+
+impl MyTrait<u32> for Qqq{
+   fn lol<F:FnOnce()>(&self, _f:F) -> u16 { 5 }
+}
+impl MyTrait<u64> for Qqq{
+   fn lol<F:FnOnce()>(&self, _f:F) -> u16 { 6 }
+}
+
+fn main() {
+    let q = Qqq;
+    q.lol(||());
+}
diff --git a/src/test/ui/traits/suggest-fully-qualified-closure.stderr b/src/test/ui/traits/suggest-fully-qualified-closure.stderr
new file mode 100644 (file)
index 0000000..3df623c
--- /dev/null
@@ -0,0 +1,34 @@
+error[E0282]: type annotations needed
+  --> $DIR/suggest-fully-qualified-closure.rs:23:7
+   |
+LL |     q.lol(||());
+   |       ^^^
+   |
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <Qqq as MyTrait<T>>::lol::<[closure@]>(&q, ||());
+   |     +++ ~
+
+error[E0283]: type annotations needed
+  --> $DIR/suggest-fully-qualified-closure.rs:23:7
+   |
+LL |     q.lol(||());
+   |       ^^^
+   |
+note: multiple `impl`s satisfying `Qqq: MyTrait<_>` found
+  --> $DIR/suggest-fully-qualified-closure.rs:14:1
+   |
+LL | impl MyTrait<u32> for Qqq{
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl MyTrait<u64> for Qqq{
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <Qqq as MyTrait<T>>::lol::<[closure@]>(&q, ||());
+   |     +++ ~
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0282, E0283.
+For more information about an error, try `rustc --explain E0282`.
index 484a222bc012d4381b170c1ac235c3c3d47034eb..570ec5160bfe9809011c113e9c06fccdf0397bc8 100644 (file)
@@ -1,7 +1,6 @@
 // run-pass
 
 #![feature(trait_upcasting)]
-#![allow(incomplete_features)]
 
 trait Foo: PartialEq<i32> + std::fmt::Debug + Send + Sync {
     fn a(&self) -> i32 {
index 8d0a9ef0ace693dff0c3bc808fc86d9d09a749a5..eae5cf8d58d0196c9a2445d1772b93d0bb0c4a06 100644 (file)
@@ -1,6 +1,5 @@
 // run-pass
 #![feature(trait_upcasting)]
-#![allow(incomplete_features)]
 
 trait Foo<T: Default + ToString>: Bar<i32> + Bar<T> {}
 trait Bar<T: Default + ToString> {
index e4e23c1a26e78d8072b12df911b0c7eada1d2b6a..a4f81c464b40266090aeb90913eeb9adf200aaf7 100644 (file)
@@ -1,7 +1,6 @@
 // run-pass
 
 #![feature(trait_upcasting)]
-#![allow(incomplete_features)]
 
 trait Foo: PartialEq<i32> + std::fmt::Debug + Send + Sync {
     fn a(&self) -> i32 {
index 24022450406a7a32e9da535ce7f275aee6d1c3d2..e634bbd5ac6f5d7782921f16bbd41c2a78e69390 100644 (file)
@@ -1,5 +1,4 @@
 #![feature(trait_upcasting)]
-#![allow(incomplete_features)]
 
 trait Foo {
     fn a(&self) -> i32 {
index b4530ed0c3a94fcbff4f622dd4c48689fc874d6f..3aa21ee3dddfbbdf5f8a8c8c359a2a49583024e4 100644 (file)
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:54:35
+  --> $DIR/invalid-upcast.rs:53:35
    |
 LL |     let _: &dyn std::fmt::Debug = baz;
    |            --------------------   ^^^ expected trait `Debug`, found trait `Baz`
@@ -10,7 +10,7 @@ LL |     let _: &dyn std::fmt::Debug = baz;
               found reference `&dyn Baz`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:56:24
+  --> $DIR/invalid-upcast.rs:55:24
    |
 LL |     let _: &dyn Send = baz;
    |            ---------   ^^^ expected trait `Send`, found trait `Baz`
@@ -21,7 +21,7 @@ LL |     let _: &dyn Send = baz;
               found reference `&dyn Baz`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:58:24
+  --> $DIR/invalid-upcast.rs:57:24
    |
 LL |     let _: &dyn Sync = baz;
    |            ---------   ^^^ expected trait `Sync`, found trait `Baz`
@@ -32,7 +32,7 @@ LL |     let _: &dyn Sync = baz;
               found reference `&dyn Baz`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:61:25
+  --> $DIR/invalid-upcast.rs:60:25
    |
 LL |     let bar: &dyn Bar = baz;
    |              --------   ^^^ expected trait `Bar`, found trait `Baz`
@@ -43,7 +43,7 @@ LL |     let bar: &dyn Bar = baz;
               found reference `&dyn Baz`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:63:35
+  --> $DIR/invalid-upcast.rs:62:35
    |
 LL |     let _: &dyn std::fmt::Debug = bar;
    |            --------------------   ^^^ expected trait `Debug`, found trait `Bar`
@@ -54,7 +54,7 @@ LL |     let _: &dyn std::fmt::Debug = bar;
               found reference `&dyn Bar`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:65:24
+  --> $DIR/invalid-upcast.rs:64:24
    |
 LL |     let _: &dyn Send = bar;
    |            ---------   ^^^ expected trait `Send`, found trait `Bar`
@@ -65,7 +65,7 @@ LL |     let _: &dyn Send = bar;
               found reference `&dyn Bar`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:67:24
+  --> $DIR/invalid-upcast.rs:66:24
    |
 LL |     let _: &dyn Sync = bar;
    |            ---------   ^^^ expected trait `Sync`, found trait `Bar`
@@ -76,7 +76,7 @@ LL |     let _: &dyn Sync = bar;
               found reference `&dyn Bar`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:70:25
+  --> $DIR/invalid-upcast.rs:69:25
    |
 LL |     let foo: &dyn Foo = baz;
    |              --------   ^^^ expected trait `Foo`, found trait `Baz`
@@ -87,7 +87,7 @@ LL |     let foo: &dyn Foo = baz;
               found reference `&dyn Baz`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:72:35
+  --> $DIR/invalid-upcast.rs:71:35
    |
 LL |     let _: &dyn std::fmt::Debug = foo;
    |            --------------------   ^^^ expected trait `Debug`, found trait `Foo`
@@ -98,7 +98,7 @@ LL |     let _: &dyn std::fmt::Debug = foo;
               found reference `&dyn Foo`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:74:24
+  --> $DIR/invalid-upcast.rs:73:24
    |
 LL |     let _: &dyn Send = foo;
    |            ---------   ^^^ expected trait `Send`, found trait `Foo`
@@ -109,7 +109,7 @@ LL |     let _: &dyn Send = foo;
               found reference `&dyn Foo`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:76:24
+  --> $DIR/invalid-upcast.rs:75:24
    |
 LL |     let _: &dyn Sync = foo;
    |            ---------   ^^^ expected trait `Sync`, found trait `Foo`
@@ -120,7 +120,7 @@ LL |     let _: &dyn Sync = foo;
               found reference `&dyn Foo`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:79:25
+  --> $DIR/invalid-upcast.rs:78:25
    |
 LL |     let foo: &dyn Foo = bar;
    |              --------   ^^^ expected trait `Foo`, found trait `Bar`
@@ -131,7 +131,7 @@ LL |     let foo: &dyn Foo = bar;
               found reference `&dyn Bar`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:81:35
+  --> $DIR/invalid-upcast.rs:80:35
    |
 LL |     let _: &dyn std::fmt::Debug = foo;
    |            --------------------   ^^^ expected trait `Debug`, found trait `Foo`
@@ -142,7 +142,7 @@ LL |     let _: &dyn std::fmt::Debug = foo;
               found reference `&dyn Foo`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:83:24
+  --> $DIR/invalid-upcast.rs:82:24
    |
 LL |     let _: &dyn Send = foo;
    |            ---------   ^^^ expected trait `Send`, found trait `Foo`
@@ -153,7 +153,7 @@ LL |     let _: &dyn Send = foo;
               found reference `&dyn Foo`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:85:24
+  --> $DIR/invalid-upcast.rs:84:24
    |
 LL |     let _: &dyn Sync = foo;
    |            ---------   ^^^ expected trait `Sync`, found trait `Foo`
index 6d88002540c1ac43c355241244183a1ec04834fa..b672963ae98876c5e4553a6e3b2be7bbb9771787 100644 (file)
@@ -1,6 +1,5 @@
 // run-pass
 #![feature(trait_upcasting)]
-#![allow(incomplete_features)]
 
 struct Test {
     func: Box<dyn FnMut() + 'static>,
index f029a6f081f583087e0f57d98148cc178e3d8728..9825158c2dd38a52974ad004156c44123991154c 100644 (file)
@@ -1,7 +1,6 @@
 // run-pass
 
 #![feature(trait_upcasting)]
-#![allow(incomplete_features)]
 
 trait Foo: PartialEq<i32> + std::fmt::Debug + Send + Sync {
     fn a(&self) -> i32 {
index 6986ad6217240423c3772114e11ddbb9fa3c943a..2e53a00a90e9c8e955d4c7e8b1b1d449d1961f5e 100644 (file)
@@ -1,12 +1,11 @@
 // check-fail
 #![feature(trait_upcasting)]
-#![allow(incomplete_features)]
 
 trait Bar<T> {
     fn bar(&self, _: T) {}
 }
 
-trait Foo : Bar<i32> + Bar<u32> {
+trait Foo: Bar<i32> + Bar<u32> {
     fn foo(&self, _: ()) {}
 }
 
index 9564813512c4af5bf9e8eb0c42a76a802efa43b9..0ad18be03cdf9d259a2da0eb0e899f163bd67a0a 100644 (file)
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/multiple-occurrence-ambiguousity.rs:21:26
+  --> $DIR/multiple-occurrence-ambiguousity.rs:20:26
    |
 LL |     let t: &dyn Bar<_> = s;
    |            -----------   ^ expected trait `Bar`, found trait `Foo`
index 1164e43611a1d20aefcfa69032ba626c96c4d2ec..9ccfc9306ac0c46e04097ebd9a0ba9ad334cba07 100644 (file)
@@ -1,7 +1,6 @@
 // run-pass
 
 #![feature(trait_upcasting)]
-#![allow(incomplete_features)]
 
 trait A {
     fn foo_a(&self);
index 0f3cb285bf4c3446939eab534d00307518fd591b..a3e41696956cb930a65ac3e7c0a2b3f03f9fe9b3 100644 (file)
@@ -1,7 +1,6 @@
 // run-pass
 
 #![feature(trait_upcasting)]
-#![allow(incomplete_features)]
 
 use std::rc::Rc;
 use std::sync::Arc;
index 3508e15284bf2406da408f26d33ae2b76abcdc7c..136d15af0e8b2de5f7fb1d99c3b1df15deb7b57a 100644 (file)
@@ -1,5 +1,4 @@
 #![feature(trait_upcasting)]
-#![allow(incomplete_features)]
 
 trait Foo: PartialEq<i32> + std::fmt::Debug + Send + Sync {
     fn a(&self) -> i32 {
index af7a410f6d92c205a25cae81e1fd7acdf9f39d21..918159e845b9e7e5e98b9145aab67aaa3a012605 100644 (file)
@@ -1,64 +1,64 @@
 error[E0599]: no method named `c` found for reference `&dyn Bar` in the current scope
-  --> $DIR/subtrait-method.rs:56:9
+  --> $DIR/subtrait-method.rs:55:9
    |
 LL |     bar.c();
    |         ^ help: there is a method with a similar name: `a`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `Baz` defines an item `c`, perhaps you need to implement it
-  --> $DIR/subtrait-method.rs:28:1
+  --> $DIR/subtrait-method.rs:27:1
    |
 LL | trait Baz: Bar {
    | ^^^^^^^^^^^^^^
 
 error[E0599]: no method named `b` found for reference `&dyn Foo` in the current scope
-  --> $DIR/subtrait-method.rs:60:9
+  --> $DIR/subtrait-method.rs:59:9
    |
 LL |     foo.b();
    |         ^ help: there is a method with a similar name: `a`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `Bar` defines an item `b`, perhaps you need to implement it
-  --> $DIR/subtrait-method.rs:18:1
+  --> $DIR/subtrait-method.rs:17:1
    |
 LL | trait Bar: Foo {
    | ^^^^^^^^^^^^^^
 
 error[E0599]: no method named `c` found for reference `&dyn Foo` in the current scope
-  --> $DIR/subtrait-method.rs:62:9
+  --> $DIR/subtrait-method.rs:61:9
    |
 LL |     foo.c();
    |         ^ help: there is a method with a similar name: `a`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `Baz` defines an item `c`, perhaps you need to implement it
-  --> $DIR/subtrait-method.rs:28:1
+  --> $DIR/subtrait-method.rs:27:1
    |
 LL | trait Baz: Bar {
    | ^^^^^^^^^^^^^^
 
 error[E0599]: no method named `b` found for reference `&dyn Foo` in the current scope
-  --> $DIR/subtrait-method.rs:66:9
+  --> $DIR/subtrait-method.rs:65:9
    |
 LL |     foo.b();
    |         ^ help: there is a method with a similar name: `a`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `Bar` defines an item `b`, perhaps you need to implement it
-  --> $DIR/subtrait-method.rs:18:1
+  --> $DIR/subtrait-method.rs:17:1
    |
 LL | trait Bar: Foo {
    | ^^^^^^^^^^^^^^
 
 error[E0599]: no method named `c` found for reference `&dyn Foo` in the current scope
-  --> $DIR/subtrait-method.rs:68:9
+  --> $DIR/subtrait-method.rs:67:9
    |
 LL |     foo.c();
    |         ^ help: there is a method with a similar name: `a`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `Baz` defines an item `c`, perhaps you need to implement it
-  --> $DIR/subtrait-method.rs:28:1
+  --> $DIR/subtrait-method.rs:27:1
    |
 LL | trait Baz: Bar {
    | ^^^^^^^^^^^^^^
index 79ddedd4187560fbfe8e4c2e44da0e170545f552..6bc9f4a75d3338f9aff95bd80db1fa3fa59be204 100644 (file)
@@ -1,5 +1,4 @@
 #![feature(trait_upcasting)]
-#![allow(incomplete_features)]
 
 trait Foo: Bar<i32> + Bar<u32> {}
 trait Bar<T> {
index 3985372119e886a98443f00bc890f08aa370f8bc..fe269d8e99bf55ed0b6f43d7a2288a7a3c022e81 100644 (file)
@@ -1,5 +1,5 @@
 error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar<_>`
-  --> $DIR/type-checking-test-1.rs:17:13
+  --> $DIR/type-checking-test-1.rs:16:13
    |
 LL |     let _ = x as &dyn Bar<_>; // Ambiguous
    |             ^^^^^^^^^^^^^^^^ invalid cast
@@ -10,7 +10,7 @@ LL |     let _ = &x as &dyn Bar<_>; // Ambiguous
    |             +
 
 error[E0277]: the trait bound `&dyn Foo: Bar<_>` is not satisfied
-  --> $DIR/type-checking-test-1.rs:17:13
+  --> $DIR/type-checking-test-1.rs:16:13
    |
 LL |     let _ = x as &dyn Bar<_>; // Ambiguous
    |             ^ the trait `Bar<_>` is not implemented for `&dyn Foo`
index 32754c53803786ca145e63e56f00356f7f53b2a5..36b11dffdb158ba608caa531a3ad55aaceddf375 100644 (file)
@@ -1,5 +1,4 @@
 #![feature(trait_upcasting)]
-#![allow(incomplete_features)]
 
 trait Foo<T>: Bar<i32> + Bar<T> {}
 trait Bar<T> {
index 93c71f54eb53a6b6ddad16edff44b18ea83144eb..ef007d5cb909f9ae1c47e0844d4e9e3531b7e5cc 100644 (file)
@@ -1,5 +1,5 @@
 error[E0605]: non-primitive cast: `&dyn Foo<i32>` as `&dyn Bar<u32>`
-  --> $DIR/type-checking-test-2.rs:20:13
+  --> $DIR/type-checking-test-2.rs:19:13
    |
 LL |     let _ = x as &dyn Bar<u32>; // Error
    |             ^^^^^^^^^^^^^^^^^^ invalid cast
@@ -10,7 +10,7 @@ LL |     let _ = &x as &dyn Bar<u32>; // Error
    |             +
 
 error[E0277]: the trait bound `&dyn Foo<i32>: Bar<u32>` is not satisfied
-  --> $DIR/type-checking-test-2.rs:20:13
+  --> $DIR/type-checking-test-2.rs:19:13
    |
 LL |     let _ = x as &dyn Bar<u32>; // Error
    |             ^ the trait `Bar<u32>` is not implemented for `&dyn Foo<i32>`
@@ -18,7 +18,7 @@ LL |     let _ = x as &dyn Bar<u32>; // Error
    = note: required for the cast from `&dyn Foo<i32>` to the object type `dyn Bar<u32>`
 
 error[E0605]: non-primitive cast: `&dyn Foo<u32>` as `&dyn Bar<_>`
-  --> $DIR/type-checking-test-2.rs:26:13
+  --> $DIR/type-checking-test-2.rs:25:13
    |
 LL |     let a = x as &dyn Bar<_>; // Ambiguous
    |             ^^^^^^^^^^^^^^^^ invalid cast
@@ -29,7 +29,7 @@ LL |     let a = &x as &dyn Bar<_>; // Ambiguous
    |             +
 
 error[E0277]: the trait bound `&dyn Foo<u32>: Bar<_>` is not satisfied
-  --> $DIR/type-checking-test-2.rs:26:13
+  --> $DIR/type-checking-test-2.rs:25:13
    |
 LL |     let a = x as &dyn Bar<_>; // Ambiguous
    |             ^ the trait `Bar<_>` is not implemented for `&dyn Foo<u32>`
index e48ba709af1fd8505d76d5823bec81ae302d09ca..e6cb6a753998f0ec375f47d0be3239f605ef7f98 100644 (file)
@@ -1,22 +1,18 @@
 error: lifetime may not live long enough
-  --> $DIR/type-checking-test-3.rs:13:13
+  --> $DIR/type-checking-test-3.rs:11:13
    |
 LL | fn test_wrong1<'a>(x: &dyn Foo<'static>, y: &'a u32) {
    |                -- lifetime `'a` defined here
 LL |     let _ = x as &dyn Bar<'a>; // Error
    |             ^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
-   |
-   = help: consider replacing `'a` with `'static`
 
 error: lifetime may not live long enough
-  --> $DIR/type-checking-test-3.rs:18:13
+  --> $DIR/type-checking-test-3.rs:16:13
    |
 LL | fn test_wrong2<'a>(x: &dyn Foo<'a>) {
    |                -- lifetime `'a` defined here
 LL |     let _ = x as &dyn Bar<'static>; // Error
    |             ^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
-   |
-   = help: consider replacing `'a` with `'static`
 
 error: aborting due to 2 previous errors
 
index b3aa2279a30a00d7c1899ed7b81ffe0091811f30..b2db3a127974c3d57bf8da73a6fbcb0e070cca3a 100644 (file)
@@ -1,5 +1,4 @@
 #![feature(trait_upcasting)]
-#![allow(incomplete_features)]
 
 trait Foo<'a>: Bar<'a> {}
 trait Bar<'a> {}
@@ -10,12 +9,12 @@ fn test_correct(x: &dyn Foo<'static>) {
 
 fn test_wrong1<'a>(x: &dyn Foo<'static>, y: &'a u32) {
     let _ = x as &dyn Bar<'a>; // Error
-    //~^ ERROR lifetime may not live long enough
+                               //~^ ERROR lifetime may not live long enough
 }
 
 fn test_wrong2<'a>(x: &dyn Foo<'a>) {
     let _ = x as &dyn Bar<'static>; // Error
-    //~^ ERROR lifetime may not live long enough
+                                    //~^ ERROR lifetime may not live long enough
 }
 
 fn main() {}
index 5ad151b50924de38c2100687666d6615ca7b5df5..e6cb6a753998f0ec375f47d0be3239f605ef7f98 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/type-checking-test-3.rs:12:13
+  --> $DIR/type-checking-test-3.rs:11:13
    |
 LL | fn test_wrong1<'a>(x: &dyn Foo<'static>, y: &'a u32) {
    |                -- lifetime `'a` defined here
@@ -7,7 +7,7 @@ LL |     let _ = x as &dyn Bar<'a>; // Error
    |             ^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
 
 error: lifetime may not live long enough
-  --> $DIR/type-checking-test-3.rs:17:13
+  --> $DIR/type-checking-test-3.rs:16:13
    |
 LL | fn test_wrong2<'a>(x: &dyn Foo<'a>) {
    |                -- lifetime `'a` defined here
index a3411f40ad0fb527c5b0df2cee6fdc69a9293e52..8d506e5807ece13e6819651672937600bf97b49d 100644 (file)
@@ -1,33 +1,52 @@
 error: lifetime may not live long enough
-  --> $DIR/type-checking-test-4.rs:17:13
+  --> $DIR/type-checking-test-4.rs:15:13
    |
 LL | fn test_wrong1<'a>(x: &dyn Foo<'static>, y: &'a u32) {
    |                -- lifetime `'a` defined here
 LL |     let _ = x as &dyn Bar<'static, 'a>; // Error
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
-   |
-   = help: consider replacing `'a` with `'static`
 
 error: lifetime may not live long enough
-  --> $DIR/type-checking-test-4.rs:22:13
+  --> $DIR/type-checking-test-4.rs:20:13
    |
 LL | fn test_wrong2<'a>(x: &dyn Foo<'static>, y: &'a u32) {
    |                -- lifetime `'a` defined here
 LL |     let _ = x as &dyn Bar<'a, 'static>; // Error
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
-   |
-   = help: consider replacing `'a` with `'static`
 
 error: lifetime may not live long enough
-  --> $DIR/type-checking-test-4.rs:29:5
+  --> $DIR/type-checking-test-4.rs:26:5
    |
 LL | fn test_wrong3<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
    |                -- lifetime `'a` defined here
-...
+LL |     let y = x as &dyn Bar<'_, '_>;
 LL |     y.get_b() // ERROR
    |     ^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/type-checking-test-4.rs:31:5
+   |
+LL | fn test_wrong4<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
+   |                -- lifetime `'a` defined here
+LL |     <_ as Bar>::get_b(x) // ERROR
+   |     ^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/type-checking-test-4.rs:36:5
+   |
+LL | fn test_wrong5<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
+   |                -- lifetime `'a` defined here
+LL |     <_ as Bar<'_, '_>>::get_b(x) // ERROR
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/type-checking-test-4.rs:44:5
    |
-   = help: consider replacing `'a` with `'static`
+LL | fn test_wrong6<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
+   |                -- lifetime `'a` defined here
+...
+LL |     z.get_b() // ERROR
+   |     ^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
 
-error: aborting due to 3 previous errors
+error: aborting due to 6 previous errors
 
index 70ccc87fc3e145596593e34055adaad5f5395252..f40c48f0d125f72a9795b19174fd06651d89644c 100644 (file)
@@ -1,5 +1,4 @@
 #![feature(trait_upcasting)]
-#![allow(incomplete_features)]
 
 trait Foo<'a>: Bar<'a, 'a> {}
 trait Bar<'a, 'b> {
@@ -14,28 +13,28 @@ fn test_correct(x: &dyn Foo<'static>) {
 
 fn test_wrong1<'a>(x: &dyn Foo<'static>, y: &'a u32) {
     let _ = x as &dyn Bar<'static, 'a>; // Error
-    //~^ ERROR lifetime may not live long enough
+                                        //~^ ERROR lifetime may not live long enough
 }
 
 fn test_wrong2<'a>(x: &dyn Foo<'static>, y: &'a u32) {
     let _ = x as &dyn Bar<'a, 'static>; // Error
-    //~^ ERROR lifetime may not live long enough
+                                        //~^ ERROR lifetime may not live long enough
 }
 
 fn test_wrong3<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
     let y = x as &dyn Bar<'_, '_>;
     y.get_b() // ERROR
-    //~^ ERROR lifetime may not live long enough
+              //~^ ERROR lifetime may not live long enough
 }
 
 fn test_wrong4<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
     <_ as Bar>::get_b(x) // ERROR
-    //~^ ERROR lifetime may not live long enough
+                         //~^ ERROR lifetime may not live long enough
 }
 
 fn test_wrong5<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
     <_ as Bar<'_, '_>>::get_b(x) // ERROR
-    //~^ ERROR lifetime may not live long enough
+                                 //~^ ERROR lifetime may not live long enough
 }
 
 fn test_wrong6<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
@@ -43,7 +42,7 @@ fn test_wrong6<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
     y.get_b(); // ERROR
     let z = y;
     z.get_b() // ERROR
-    //~^ ERROR lifetime may not live long enough
+              //~^ ERROR lifetime may not live long enough
 }
 
 fn main() {}
index 436129d0bee52d5e5ddedd4b75d212350196761d..8d506e5807ece13e6819651672937600bf97b49d 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/type-checking-test-4.rs:16:13
+  --> $DIR/type-checking-test-4.rs:15:13
    |
 LL | fn test_wrong1<'a>(x: &dyn Foo<'static>, y: &'a u32) {
    |                -- lifetime `'a` defined here
@@ -7,7 +7,7 @@ LL |     let _ = x as &dyn Bar<'static, 'a>; // Error
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
 
 error: lifetime may not live long enough
-  --> $DIR/type-checking-test-4.rs:21:13
+  --> $DIR/type-checking-test-4.rs:20:13
    |
 LL | fn test_wrong2<'a>(x: &dyn Foo<'static>, y: &'a u32) {
    |                -- lifetime `'a` defined here
@@ -15,7 +15,7 @@ LL |     let _ = x as &dyn Bar<'a, 'static>; // Error
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
 
 error: lifetime may not live long enough
-  --> $DIR/type-checking-test-4.rs:27:5
+  --> $DIR/type-checking-test-4.rs:26:5
    |
 LL | fn test_wrong3<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
    |                -- lifetime `'a` defined here
@@ -24,7 +24,7 @@ LL |     y.get_b() // ERROR
    |     ^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
 
 error: lifetime may not live long enough
-  --> $DIR/type-checking-test-4.rs:32:5
+  --> $DIR/type-checking-test-4.rs:31:5
    |
 LL | fn test_wrong4<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
    |                -- lifetime `'a` defined here
@@ -32,7 +32,7 @@ LL |     <_ as Bar>::get_b(x) // ERROR
    |     ^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
 
 error: lifetime may not live long enough
-  --> $DIR/type-checking-test-4.rs:37:5
+  --> $DIR/type-checking-test-4.rs:36:5
    |
 LL | fn test_wrong5<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
    |                -- lifetime `'a` defined here
@@ -40,7 +40,7 @@ LL |     <_ as Bar<'_, '_>>::get_b(x) // ERROR
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
 
 error: lifetime may not live long enough
-  --> $DIR/type-checking-test-4.rs:45:5
+  --> $DIR/type-checking-test-4.rs:44:5
    |
 LL | fn test_wrong6<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
    |                -- lifetime `'a` defined here
diff --git a/src/test/ui/type/issue-103271.rs b/src/test/ui/type/issue-103271.rs
new file mode 100644 (file)
index 0000000..bd3254a
--- /dev/null
@@ -0,0 +1,10 @@
+fn main() {
+    let iter_fun = <&[u32]>::iter;
+    //~^ ERROR no function or associated item named `iter` found for reference `&[u32]` in the current scope [E0599]
+    //~| function or associated item not found in `&[u32]`
+    //~| HELP the function `iter` is implemented on `[u32]`
+    for item in iter_fun(&[1,1]) {
+        let x: &u32 = item;
+        assert_eq!(x, &1);
+    }
+}
diff --git a/src/test/ui/type/issue-103271.stderr b/src/test/ui/type/issue-103271.stderr
new file mode 100644 (file)
index 0000000..02a59d4
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0599]: no function or associated item named `iter` found for reference `&[u32]` in the current scope
+  --> $DIR/issue-103271.rs:2:30
+   |
+LL |     let iter_fun = <&[u32]>::iter;
+   |                              ^^^^ function or associated item not found in `&[u32]`
+   |
+help: the function `iter` is implemented on `[u32]`
+   |
+LL |     let iter_fun = <[u32]>::iter;
+   |                     ~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/typeck/issue-103899.rs b/src/test/ui/typeck/issue-103899.rs
new file mode 100644 (file)
index 0000000..9d5341d
--- /dev/null
@@ -0,0 +1,33 @@
+// check-fail
+// failure-status: 101
+// normalize-stderr-test "note: .*" -> ""
+// normalize-stderr-test "thread 'rustc' .*" -> ""
+// normalize-stderr-test " .*\n" -> ""
+// normalize-stderr-test "  .*\n" -> ""
+// known-bug: #103899
+
+trait BaseWithAssoc {
+    type Assoc;
+}
+
+trait WrapperWithAssoc {
+    type BaseAssoc: BaseWithAssoc;
+}
+
+struct Wrapper<B> {
+    inner: B,
+}
+
+struct ProjectToBase<T: BaseWithAssoc> {
+    data_type_h: T::Assoc,
+}
+
+struct DoubleProject<L: WrapperWithAssoc> {
+    buffer: Wrapper<ProjectToBase<L::BaseAssoc>>,
+}
+
+fn trigger<L: WrapperWithAssoc<BaseAssoc = ()>>() -> DoubleProject<L> {
+    loop {}
+}
+
+fn main() {}
diff --git a/src/test/ui/typeck/issue-103899.stderr b/src/test/ui/typeck/issue-103899.stderr
new file mode 100644 (file)
index 0000000..836c6ee
--- /dev/null
@@ -0,0 +1,12 @@
+
+stack
+error:
+
+
+
+
+
+
+
+
+query#0#1end
\ No newline at end of file
diff --git a/src/test/ui/typeck/issue-10969.rs b/src/test/ui/typeck/issue-10969.rs
new file mode 100644 (file)
index 0000000..0b78fc1
--- /dev/null
@@ -0,0 +1,7 @@
+fn func(i: i32) {
+    i(); //~ERROR expected function, found `i32`
+}
+fn main() {
+    let i = 0i32;
+    i(); //~ERROR expected function, found `i32`
+}
diff --git a/src/test/ui/typeck/issue-10969.stderr b/src/test/ui/typeck/issue-10969.stderr
new file mode 100644 (file)
index 0000000..f64b61a
--- /dev/null
@@ -0,0 +1,23 @@
+error[E0618]: expected function, found `i32`
+  --> $DIR/issue-10969.rs:2:5
+   |
+LL | fn func(i: i32) {
+   |         - `i` has type `i32`
+LL |     i();
+   |     ^--
+   |     |
+   |     call expression requires function
+
+error[E0618]: expected function, found `i32`
+  --> $DIR/issue-10969.rs:6:5
+   |
+LL |     let i = 0i32;
+   |         - `i` has type `i32`
+LL |     i();
+   |     ^--
+   |     |
+   |     call expression requires function
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0618`.
diff --git a/src/test/ui/typeck/issue-50687-ice-on-borrow.rs b/src/test/ui/typeck/issue-50687-ice-on-borrow.rs
new file mode 100644 (file)
index 0000000..7a8a12c
--- /dev/null
@@ -0,0 +1,41 @@
+// This previously caused an ICE at:
+// librustc/traits/structural_impls.rs:180: impossible case reached
+
+#![no_main]
+
+use std::borrow::Borrow;
+use std::io;
+use std::io::Write;
+
+trait Constraint {}
+
+struct Container<T> {
+    t: T,
+}
+
+struct Borrowed;
+struct Owned;
+
+impl<'a, T> Write for &'a Container<T>
+where
+    T: Constraint,
+    &'a T: Write,
+{
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        Ok(buf.len())
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+}
+
+impl Borrow<Borrowed> for Owned {
+    fn borrow(&self) -> &Borrowed {
+        &Borrowed
+    }
+}
+
+fn func(owned: Owned) {
+    let _: () = Borrow::borrow(&owned); //~ ERROR mismatched types
+}
diff --git a/src/test/ui/typeck/issue-50687-ice-on-borrow.stderr b/src/test/ui/typeck/issue-50687-ice-on-borrow.stderr
new file mode 100644 (file)
index 0000000..e6a0eda
--- /dev/null
@@ -0,0 +1,18 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-50687-ice-on-borrow.rs:40:17
+   |
+LL |     let _: () = Borrow::borrow(&owned);
+   |            --   ^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found reference
+   |            |
+   |            expected due to this
+   |
+   = note: expected unit type `()`
+              found reference `&_`
+help: consider dereferencing the borrow
+   |
+LL |     let _: () = *Borrow::borrow(&owned);
+   |                 +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/use/use-crate-self.rs b/src/test/ui/use/use-crate-self.rs
new file mode 100644 (file)
index 0000000..65ab948
--- /dev/null
@@ -0,0 +1,4 @@
+use crate::{self};
+        //~^ ERROR crate root imports need to be explicitly named: `use crate as name;`
+
+fn main() {}
diff --git a/src/test/ui/use/use-crate-self.stderr b/src/test/ui/use/use-crate-self.stderr
new file mode 100644 (file)
index 0000000..dd4036b
--- /dev/null
@@ -0,0 +1,8 @@
+error: crate root imports need to be explicitly named: `use crate as name;`
+  --> $DIR/use-crate-self.rs:1:13
+   |
+LL | use crate::{self};
+   |             ^^^^
+
+error: aborting due to previous error
+
index ab6edde4ee7eadfc7a1bd65cf7e34892f2d9ab41..c19e75eb7bfc860504e800e6b3e194788e04b40c 100644 (file)
@@ -19,7 +19,7 @@ fn caller()
 {
     called()
     //[quiet]~^ ERROR the trait bound `for<'b> fn(&'b ()): Foo` is not satisfied
-    //[verbose]~^^ ERROR the trait bound `for<'b> fn(&ReLateBound(
+    //[verbose]~^^ ERROR the trait bound `for<Region(
 }
 
 fn main() {}
index 24660ec3539e6ab73eb875a6ebba10e4d9cc64a2..268cef6e27567308b55efd011ca8ca4694c3e7bf 100644 (file)
@@ -1,8 +1,8 @@
-error[E0277]: the trait bound `for<'b> fn(&ReLateBound(DebruijnIndex(1), BoundRegion { var: 0, kind: BrNamed(DefId(0:6 ~ higher_ranked_fn_type[1209]::called::'b), 'b) }) ()): Foo` is not satisfied
+error[E0277]: the trait bound `for<Region(BrNamed(DefId(0:6 ~ higher_ranked_fn_type[1209]::called::'b), 'b))> fn(&ReLateBound(DebruijnIndex(1), BoundRegion { var: 0, kind: BrNamed(DefId(0:6 ~ higher_ranked_fn_type[1209]::called::'b), 'b) }) ()): Foo` is not satisfied
   --> $DIR/higher-ranked-fn-type.rs:20:5
    |
 LL |     called()
-   |     ^^^^^^ the trait `for<'b> Foo` is not implemented for `fn(&ReLateBound(DebruijnIndex(1), BoundRegion { var: 0, kind: BrNamed(DefId(0:6 ~ higher_ranked_fn_type[1209]::called::'b), 'b) }) ())`
+   |     ^^^^^^ the trait `for<Region(BrNamed(DefId(0:6 ~ higher_ranked_fn_type[1209]::called::'b), 'b))> Foo` is not implemented for `fn(&ReLateBound(DebruijnIndex(1), BoundRegion { var: 0, kind: BrNamed(DefId(0:6 ~ higher_ranked_fn_type[1209]::called::'b), 'b) }) ())`
    |
 note: required by a bound in `called`
   --> $DIR/higher-ranked-fn-type.rs:12:25
index 44c96f31d0ba8ca5d71a8aee1e49da371f5cbf28..9d30c554186be1f6bd109170f1adbc07f8846502 100644 (file)
@@ -1,7 +1,16 @@
 # build-manifest
 
-This tool generates the manifests uploaded to static.rust-lang.org and used by
-rustup. The tool is invoked by the bootstrap tool.
+This tool generates the manifests uploaded to static.rust-lang.org and used by rustup.
+You can see a full list of all manifests at <https://static.rust-lang.org/manifests.txt>.
+This listing is updated by <https://github.com/rust-lang/generate-manifest-list> every 7 days.
+
+This gets called by `promote-release` <https://github.com/rust-lang/promote-release> via `x.py dist hash-and-sign`.
+
+## Adding a new component
+
+1. Add a new `Step` to `dist.rs`. This should usually be named after the filename of the uploaded tarball. See https://github.com/rust-lang/rust/pull/101799/files#diff-2c56335faa24486df09ba392d8900c57e2fac4633e1f7038469bcf9ed3feb871 for an example.
+    a. If appropriate, call `tarball.is_preview(true)` for the component.
+2. Add a new `PkgType` to build-manifest. Fix all the compile errors as appropriate.
 
 ## Testing changes locally
 
@@ -9,19 +18,16 @@ In order to test the changes locally you need to have a valid dist directory
 available locally. If you don't want to build all the compiler, you can easily
 create one from the nightly artifacts with:
 
-```
-#!/bin/bash
-for cmpn in rust rustc rust-std rust-docs cargo; do
-    wget https://static.rust-lang.org/dist/${cmpn}-nightly-x86_64-unknown-linux-gnu.tar.gz
+```sh
+for component in rust rustc rust-std rust-docs cargo; do
+    wget -P build/dist https://static.rust-lang.org/dist/${component}-nightly-x86_64-unknown-linux-gnu.tar.gz
 done
 ```
 
-Then, you can generate the manifest and all the packages from `path/to/dist` to
-`path/to/output` with:
+Then, you can generate the manifest and all the packages from `build/dist` to
+`build/manifest` with:
 
+```sh
+mkdir -p build/manifest
+cargo +nightly run --release -p build-manifest build/dist build/manifest 1970-01-01 http://example.com nightly
 ```
-$ cargo +nightly run path/to/dist path/to/output 1970-01-01 http://example.com CHANNEL
-```
-
-Remember to replace `CHANNEL` with the channel you produced dist artifacts of
-and `VERSION` with the current Rust version.
index b0006cb90bdd6f9b26591599c31afc5889585591..0551e835bb0e75ec71288c34b5c894245d354f8a 100644 (file)
@@ -1,8 +1,4 @@
-//! Build a dist manifest, hash and sign everything.
-//! This gets called by `promote-release`
-//! (https://github.com/rust-lang/rust-central-station/tree/master/promote-release)
-//! via `x.py dist hash-and-sign`; the cmdline arguments are set up
-//! by rustbuild (in `src/bootstrap/dist.rs`).
+#![doc = include_str!("../README.md")]
 
 mod checksum;
 mod manifest;
@@ -64,6 +60,7 @@
     "aarch64-unknown-none",
     "aarch64-unknown-none-softfloat",
     "aarch64-unknown-redox",
+    "aarch64-unknown-uefi",
     "arm-linux-androideabi",
     "arm-unknown-linux-gnueabi",
     "arm-unknown-linux-gnueabihf",
@@ -99,6 +96,7 @@
     "i686-unknown-freebsd",
     "i686-unknown-linux-gnu",
     "i686-unknown-linux-musl",
+    "i686-unknown-uefi",
     "m68k-unknown-linux-gnu",
     "mips-unknown-linux-gnu",
     "mips-unknown-linux-musl",
     "x86_64-unknown-none",
     "x86_64-unknown-redox",
     "x86_64-unknown-hermit",
+    "x86_64-unknown-uefi",
 ];
 
 /// This allows the manifest to contain rust-docs for hosts that don't build
 
 static MINGW: &[&str] = &["i686-pc-windows-gnu", "x86_64-pc-windows-gnu"];
 
-static NIGHTLY_ONLY_COMPONENTS: &[&str] = &["miri-preview", "rust-docs-json-preview"];
+static NIGHTLY_ONLY_COMPONENTS: &[PkgType] = &[PkgType::Miri, PkgType::JsonDocs];
 
 macro_rules! t {
     ($e:expr) => {
@@ -287,28 +286,9 @@ fn build_manifest(&mut self) -> Manifest {
     }
 
     fn add_packages_to(&mut self, manifest: &mut Manifest) {
-        macro_rules! package {
-            ($name:expr, $targets:expr) => {
-                self.package($name, &mut manifest.pkg, $targets, &[])
-            };
+        for pkg in PkgType::all() {
+            self.package(pkg, &mut manifest.pkg);
         }
-        package!("rustc", HOSTS);
-        package!("rustc-dev", HOSTS);
-        package!("reproducible-artifacts", HOSTS);
-        package!("rustc-docs", HOSTS);
-        package!("cargo", HOSTS);
-        package!("rust-mingw", MINGW);
-        package!("rust-std", TARGETS);
-        self.package("rust-docs", &mut manifest.pkg, HOSTS, DOCS_FALLBACK);
-        self.package("rust-docs-json-preview", &mut manifest.pkg, HOSTS, DOCS_FALLBACK);
-        package!("rust-src", &["*"]);
-        package!("rls-preview", HOSTS);
-        package!("rust-analyzer-preview", HOSTS);
-        package!("clippy-preview", HOSTS);
-        package!("miri-preview", HOSTS);
-        package!("rustfmt-preview", HOSTS);
-        package!("rust-analysis", TARGETS);
-        package!("llvm-tools-preview", TARGETS);
     }
 
     fn add_artifacts_to(&mut self, manifest: &mut Manifest) {
@@ -333,44 +313,28 @@ fn add_artifacts_to(&mut self, manifest: &mut Manifest) {
     }
 
     fn add_profiles_to(&mut self, manifest: &mut Manifest) {
-        let mut profile = |name, pkgs| self.profile(name, &mut manifest.profiles, pkgs);
-        profile("minimal", &["rustc", "cargo", "rust-std", "rust-mingw"]);
-        profile(
-            "default",
-            &[
-                "rustc",
-                "cargo",
-                "rust-std",
-                "rust-mingw",
-                "rust-docs",
-                "rustfmt-preview",
-                "clippy-preview",
-            ],
-        );
-        profile(
-            "complete",
-            &[
-                "rustc",
-                "cargo",
-                "rust-std",
-                "rust-mingw",
-                "rust-docs",
-                "rustfmt-preview",
-                "clippy-preview",
-                "rls-preview",
-                "rust-analyzer-preview",
-                "rust-src",
-                "llvm-tools-preview",
-                "rust-analysis",
-                "miri-preview",
-            ],
-        );
+        use PkgType::*;
+
+        let mut profile = |name, pkgs: &_| self.profile(name, &mut manifest.profiles, pkgs);
+
+        // Use a Vec here to make sure we don't exclude any components in an earlier profile.
+        let minimal = vec![Rustc, Cargo, RustStd, RustMingw];
+        profile("minimal", &minimal);
+
+        let mut default = minimal;
+        default.extend([HtmlDocs, Rustfmt, Clippy]);
+        profile("default", &default);
+
+        // NOTE: this profile is effectively deprecated; do not add new components to it.
+        let mut complete = default;
+        complete.extend([Rls, RustAnalyzer, RustSrc, LlvmTools, RustAnalysis, Miri]);
+        profile("complete", &complete);
 
         // The compiler libraries are not stable for end users, and they're also huge, so we only
         // `rustc-dev` for nightly users, and only in the "complete" profile. It's still possible
         // for users to install the additional component manually, if needed.
         if self.versions.channel() == "nightly" {
-            self.extend_profile("complete", &mut manifest.profiles, &["rustc-dev"]);
+            self.extend_profile("complete", &mut manifest.profiles, &[RustcDev]);
             // Do not include the rustc-docs component for now, as it causes
             // conflicts with the rust-docs component when installed. See
             // #75833.
@@ -382,12 +346,11 @@ fn add_renames_to(&self, manifest: &mut Manifest) {
         let mut rename = |from: &str, to: &str| {
             manifest.renames.insert(from.to_owned(), Rename { to: to.to_owned() })
         };
-        rename("rls", "rls-preview");
-        rename("rustfmt", "rustfmt-preview");
-        rename("clippy", "clippy-preview");
-        rename("miri", "miri-preview");
-        rename("rust-docs-json", "rust-docs-json-preview");
-        rename("rust-analyzer", "rust-analyzer-preview");
+        for pkg in PkgType::all() {
+            if pkg.is_preview() {
+                rename(pkg.tarball_component_name(), &pkg.manifest_component_name());
+            }
+        }
     }
 
     fn rust_package(&mut self, manifest: &Manifest) -> Package {
@@ -419,42 +382,52 @@ fn target_host_combination(&mut self, host: &str, manifest: &Manifest) -> Option
         let mut components = Vec::new();
         let mut extensions = Vec::new();
 
-        let host_component = |pkg| Component::from_str(pkg, host);
-
-        // rustc/rust-std/cargo/docs are all required,
-        // and so is rust-mingw if it's available for the target.
-        components.extend(vec![
-            host_component("rustc"),
-            host_component("rust-std"),
-            host_component("cargo"),
-            host_component("rust-docs"),
-        ]);
-        if host.contains("pc-windows-gnu") {
-            components.push(host_component("rust-mingw"));
-        }
+        let host_component = |pkg: &_| Component::from_pkg(pkg, host);
 
-        // Tools are always present in the manifest,
-        // but might be marked as unavailable if they weren't built.
-        extensions.extend(vec![
-            host_component("clippy-preview"),
-            host_component("miri-preview"),
-            host_component("rls-preview"),
-            host_component("rust-analyzer-preview"),
-            host_component("rustfmt-preview"),
-            host_component("llvm-tools-preview"),
-            host_component("rust-analysis"),
-            host_component("rust-docs-json-preview"),
-        ]);
-
-        extensions.extend(
-            TARGETS
-                .iter()
-                .filter(|&&target| target != host)
-                .map(|target| Component::from_str("rust-std", target)),
-        );
-        extensions.extend(HOSTS.iter().map(|target| Component::from_str("rustc-dev", target)));
-        extensions.extend(HOSTS.iter().map(|target| Component::from_str("rustc-docs", target)));
-        extensions.push(Component::from_str("rust-src", "*"));
+        for pkg in PkgType::all() {
+            match pkg {
+                // rustc/rust-std/cargo/docs are all required
+                PkgType::Rustc | PkgType::Cargo | PkgType::HtmlDocs => {
+                    components.push(host_component(pkg));
+                }
+                PkgType::RustStd => {
+                    components.push(host_component(pkg));
+                    extensions.extend(
+                        TARGETS
+                            .iter()
+                            .filter(|&&target| target != host)
+                            .map(|target| Component::from_pkg(pkg, target)),
+                    );
+                }
+                // so is rust-mingw if it's available for the target
+                PkgType::RustMingw => {
+                    if host.contains("pc-windows-gnu") {
+                        components.push(host_component(pkg));
+                    }
+                }
+                // Tools are always present in the manifest,
+                // but might be marked as unavailable if they weren't built.
+                PkgType::Clippy
+                | PkgType::Miri
+                | PkgType::Rls
+                | PkgType::RustAnalyzer
+                | PkgType::Rustfmt
+                | PkgType::LlvmTools
+                | PkgType::RustAnalysis
+                | PkgType::JsonDocs => {
+                    extensions.push(host_component(pkg));
+                }
+                PkgType::RustcDev | PkgType::RustcDocs => {
+                    extensions.extend(HOSTS.iter().map(|target| Component::from_pkg(pkg, target)));
+                }
+                PkgType::RustSrc => {
+                    extensions.push(Component::from_pkg(pkg, "*"));
+                }
+                PkgType::Rust => {}
+                // NOTE: this is intentional, these artifacts aren't intended to be used with rustup
+                PkgType::ReproducibleArtifacts => {}
+            }
+        }
 
         // If the components/extensions don't actually exist for this
         // particular host/target combination then nix it entirely from our
@@ -481,43 +454,44 @@ fn profile(
         &mut self,
         profile_name: &str,
         dst: &mut BTreeMap<String, Vec<String>>,
-        pkgs: &[&str],
+        pkgs: &[PkgType],
     ) {
-        dst.insert(profile_name.to_owned(), pkgs.iter().map(|s| (*s).to_owned()).collect());
+        dst.insert(
+            profile_name.to_owned(),
+            pkgs.iter().map(|s| s.manifest_component_name()).collect(),
+        );
     }
 
     fn extend_profile(
         &mut self,
         profile_name: &str,
         dst: &mut BTreeMap<String, Vec<String>>,
-        pkgs: &[&str],
+        pkgs: &[PkgType],
     ) {
         dst.get_mut(profile_name)
             .expect("existing profile")
-            .extend(pkgs.iter().map(|s| (*s).to_owned()));
+            .extend(pkgs.iter().map(|s| s.manifest_component_name()));
     }
 
-    fn package(
-        &mut self,
-        pkgname: &str,
-        dst: &mut BTreeMap<String, Package>,
-        targets: &[&str],
-        fallback: &[(&str, &str)],
-    ) {
-        let version_info = self
-            .versions
-            .version(&PkgType::from_component(pkgname))
-            .expect("failed to load package version");
+    fn package(&mut self, pkg: &PkgType, dst: &mut BTreeMap<String, Package>) {
+        if *pkg == PkgType::Rust {
+            // This is handled specially by `rust_package` later.
+            // Order is important, so don't call `rust_package` here.
+            return;
+        }
+
+        let fallback = if pkg.use_docs_fallback() { DOCS_FALLBACK } else { &[] };
+        let version_info = self.versions.version(&pkg).expect("failed to load package version");
         let mut is_present = version_info.present;
 
         // Never ship nightly-only components for other trains.
-        if self.versions.channel() != "nightly" && NIGHTLY_ONLY_COMPONENTS.contains(&pkgname) {
+        if self.versions.channel() != "nightly" && NIGHTLY_ONLY_COMPONENTS.contains(&pkg) {
             is_present = false; // Pretend the component is entirely missing.
         }
 
         macro_rules! tarball_name {
             ($target_name:expr) => {
-                self.versions.tarball_name(&PkgType::from_component(pkgname), $target_name).unwrap()
+                self.versions.tarball_name(pkg, $target_name).unwrap()
             };
         }
         let mut target_from_compressed_tar = |target_name| {
@@ -546,7 +520,8 @@ macro_rules! tarball_name {
             Target::unavailable()
         };
 
-        let targets = targets
+        let targets = pkg
+            .targets()
             .iter()
             .map(|name| {
                 let target = if is_present {
@@ -561,7 +536,7 @@ macro_rules! tarball_name {
             .collect();
 
         dst.insert(
-            pkgname.to_string(),
+            pkg.manifest_component_name(),
             Package {
                 version: version_info.version.unwrap_or_default(),
                 git_commit_hash: version_info.git_commit,
index 547c270d89ab70465949cbd5477c567fdef867b5..a9f19d8e5653f35157f736c3e128f16be290a256 100644 (file)
@@ -1,3 +1,4 @@
+use crate::versions::PkgType;
 use crate::Builder;
 use serde::{Serialize, Serializer};
 use std::collections::BTreeMap;
@@ -116,8 +117,8 @@ pub(crate) struct Component {
 }
 
 impl Component {
-    pub(crate) fn from_str(pkg: &str, target: &str) -> Self {
-        Self { pkg: pkg.to_string(), target: target.to_string() }
+    pub(crate) fn from_pkg(pkg: &PkgType, target: &str) -> Self {
+        Self { pkg: pkg.manifest_component_name(), target: target.to_string() }
     }
 }
 
index 0186194a41f5550797930cd0f8a9aef46312ec43..dde9745afb78564b9319c62894459ea0d40ec0fe 100644 (file)
@@ -8,55 +8,63 @@
 
 const DEFAULT_TARGET: &str = "x86_64-unknown-linux-gnu";
 
-#[derive(Debug, Hash, Eq, PartialEq, Clone)]
-pub(crate) enum PkgType {
-    Rust,
-    RustSrc,
-    Rustc,
-    Cargo,
-    Rls,
-    RustAnalyzer,
-    Clippy,
-    Rustfmt,
-    LlvmTools,
-    Miri,
-    JsonDocs,
-    Other(String),
-}
+macro_rules! pkg_type {
+    ( $($variant:ident = $component:literal $(; preview = true $(@$is_preview:tt)? )? ),+ $(,)? ) => {
+        #[derive(Debug, Hash, Eq, PartialEq, Clone)]
+        pub(crate) enum PkgType {
+            $($variant,)+
+        }
 
-impl PkgType {
-    pub(crate) fn from_component(component: &str) -> Self {
-        match component {
-            "rust" => PkgType::Rust,
-            "rust-src" => PkgType::RustSrc,
-            "rustc" => PkgType::Rustc,
-            "cargo" => PkgType::Cargo,
-            "rls" | "rls-preview" => PkgType::Rls,
-            "rust-analyzer" | "rust-analyzer-preview" => PkgType::RustAnalyzer,
-            "clippy" | "clippy-preview" => PkgType::Clippy,
-            "rustfmt" | "rustfmt-preview" => PkgType::Rustfmt,
-            "llvm-tools" | "llvm-tools-preview" => PkgType::LlvmTools,
-            "miri" | "miri-preview" => PkgType::Miri,
-            "rust-docs-json" | "rust-docs-json-preview" => PkgType::JsonDocs,
-            other => PkgType::Other(other.into()),
+        impl PkgType {
+            pub(crate) fn is_preview(&self) -> bool {
+                match self {
+                    $( $( $($is_preview)? PkgType::$variant => true, )? )+
+                    _ => false,
+                }
+            }
+
+            /// First part of the tarball name.
+            pub(crate) fn tarball_component_name(&self) -> &str {
+                match self {
+                    $( PkgType::$variant => $component,)+
+                }
+            }
+
+            pub(crate) fn all() -> &'static [PkgType] {
+                &[ $(PkgType::$variant),+ ]
+            }
         }
     }
+}
 
-    /// First part of the tarball name.
-    fn tarball_component_name(&self) -> &str {
-        match self {
-            PkgType::Rust => "rust",
-            PkgType::RustSrc => "rust-src",
-            PkgType::Rustc => "rustc",
-            PkgType::Cargo => "cargo",
-            PkgType::Rls => "rls",
-            PkgType::RustAnalyzer => "rust-analyzer",
-            PkgType::Clippy => "clippy",
-            PkgType::Rustfmt => "rustfmt",
-            PkgType::LlvmTools => "llvm-tools",
-            PkgType::Miri => "miri",
-            PkgType::JsonDocs => "rust-docs-json",
-            PkgType::Other(component) => component,
+pkg_type! {
+    Rust = "rust",
+    RustSrc = "rust-src",
+    Rustc = "rustc",
+    RustcDev = "rustc-dev",
+    RustcDocs = "rustc-docs",
+    ReproducibleArtifacts = "reproducible-artifacts",
+    RustMingw = "rust-mingw",
+    RustStd = "rust-std",
+    Cargo = "cargo",
+    HtmlDocs = "rust-docs",
+    RustAnalysis = "rust-analysis",
+    Rls = "rls"; preview = true,
+    RustAnalyzer = "rust-analyzer"; preview = true,
+    Clippy = "clippy"; preview = true,
+    Rustfmt = "rustfmt"; preview = true,
+    LlvmTools = "llvm-tools"; preview = true,
+    Miri = "miri"; preview = true,
+    JsonDocs = "rust-docs-json"; preview = true,
+}
+
+impl PkgType {
+    /// Component name in the manifest. In particular, this includes the `-preview` suffix where appropriate.
+    pub(crate) fn manifest_component_name(&self) -> String {
+        if self.is_preview() {
+            format!("{}-preview", self.tarball_component_name())
+        } else {
+            self.tarball_component_name().to_string()
         }
     }
 
@@ -73,10 +81,42 @@ fn should_use_rust_version(&self) -> bool {
             PkgType::Miri => false,
 
             PkgType::Rust => true,
+            PkgType::RustStd => true,
             PkgType::RustSrc => true,
             PkgType::Rustc => true,
             PkgType::JsonDocs => true,
-            PkgType::Other(_) => true,
+            PkgType::HtmlDocs => true,
+            PkgType::RustcDev => true,
+            PkgType::RustcDocs => true,
+            PkgType::ReproducibleArtifacts => true,
+            PkgType::RustMingw => true,
+            PkgType::RustAnalysis => true,
+        }
+    }
+
+    pub(crate) fn targets(&self) -> &[&str] {
+        use crate::{HOSTS, MINGW, TARGETS};
+        use PkgType::*;
+
+        match self {
+            Rust => HOSTS, // doesn't matter in practice, but return something to avoid panicking
+            Rustc => HOSTS,
+            RustcDev => HOSTS,
+            ReproducibleArtifacts => HOSTS,
+            RustcDocs => HOSTS,
+            Cargo => HOSTS,
+            RustMingw => MINGW,
+            RustStd => TARGETS,
+            HtmlDocs => HOSTS,
+            JsonDocs => HOSTS,
+            RustSrc => &["*"],
+            Rls => HOSTS,
+            RustAnalyzer => HOSTS,
+            Clippy => HOSTS,
+            Miri => HOSTS,
+            Rustfmt => HOSTS,
+            RustAnalysis => TARGETS,
+            LlvmTools => TARGETS,
         }
     }
 
@@ -84,6 +124,14 @@ fn should_use_rust_version(&self) -> bool {
     fn target_independent(&self) -> bool {
         *self == PkgType::RustSrc
     }
+
+    /// Whether to package these target-specific docs for another similar target.
+    pub(crate) fn use_docs_fallback(&self) -> bool {
+        match self {
+            PkgType::JsonDocs | PkgType::HtmlDocs => true,
+            _ => false,
+        }
+    }
 }
 
 #[derive(Debug, Default, Clone)]
index 9286a1beba5b28b115bad67de2ae91fb1c61eb0b..a3dfea71ca0c888a88111086898aa833c291d497 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 9286a1beba5b28b115bad67de2ae91fb1c61eb0b
+Subproject commit a3dfea71ca0c888a88111086898aa833c291d497
index aad7da61a8a54626530ef1821d3874df997ea72f..eefba8cd29c41268c3abb3dcb252e7f0b426ae10 100644 (file)
@@ -207,6 +207,7 @@ pub fn ast(cx: &EarlyContext<'_>, expr: &ast::Expr, default: &'a str) -> Self {
             | ast::ExprKind::InlineAsm(..)
             | ast::ExprKind::ConstBlock(..)
             | ast::ExprKind::Lit(..)
+            | ast::ExprKind::IncludedBytes(..)
             | ast::ExprKind::Loop(..)
             | ast::ExprKind::MacCall(..)
             | ast::ExprKind::MethodCall(..)
index 878897c410cf5e5c7014b75199df8ba15c964006..4506d1550bd4bbf4b7deadeedc89d63663b38e82 100644 (file)
@@ -23,6 +23,11 @@ error[E0308]: mismatched types
    |
 LL |         Some(reference) = cache.data.get(key) {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `()`
+   |
+help: consider adding `let`
+   |
+LL |         let Some(reference) = cache.data.get(key) {
+   |         +++
 
 error: aborting due to 3 previous errors
 
index 7842611bd4ffa20b4cc7dda47e00d5fddd108c6a..4170c32f1fe253350e5bed1e1881f0dfb0131f64 100644 (file)
 
 #[rustfmt::skip]
 const INTRA_DOC_LINK_EXCEPTIONS: &[(&str, &[&str])] = &[
-    // This will never have links that are not in other pages.
-    // To avoid repeating the exceptions twice, an empty list means all broken links are allowed.
-    ("reference/print.html", &[]),
-    // All the reference 'links' are actually ENBF highlighted as code
-    ("reference/comments.html", &[
-         "/</code> <code>!",
-         "*</code> <code>!",
-    ]),
-    ("reference/identifiers.html", &[
-         "a</code>-<code>z</code> <code>A</code>-<code>Z",
-         "a</code>-<code>z</code> <code>A</code>-<code>Z</code> <code>0</code>-<code>9</code> <code>_",
-         "a</code>-<code>z</code> <code>A</code>-<code>Z</code>] [<code>a</code>-<code>z</code> <code>A</code>-<code>Z</code> <code>0</code>-<code>9</code> <code>_",
-    ]),
-    ("reference/tokens.html", &[
-         "0</code>-<code>1",
-         "0</code>-<code>7",
-         "0</code>-<code>9",
-         "0</code>-<code>9",
-         "0</code>-<code>9</code> <code>a</code>-<code>f</code> <code>A</code>-<code>F",
-    ]),
-    ("reference/notation.html", &[
-         "b</code> <code>B",
-         "a</code>-<code>z",
-    ]),
     // This is being used in the sense of 'inclusive range', not a markdown link
     ("core/ops/struct.RangeInclusive.html", &["begin</code>, <code>end"]),
     ("std/ops/struct.RangeInclusive.html", &["begin</code>, <code>end"]),
@@ -365,6 +341,33 @@ fn check(&mut self, file: &Path, report: &mut Report) {
             }
         });
 
+        self.check_intra_doc_links(file, &pretty_path, &source, report);
+
+        // we don't need the source anymore,
+        // so drop to reduce memory-usage
+        match self.cache.get_mut(&pretty_path).unwrap() {
+            FileEntry::HtmlFile { source, .. } => *source = Rc::new(String::new()),
+            _ => unreachable!("must be html file"),
+        }
+    }
+
+    fn check_intra_doc_links(
+        &mut self,
+        file: &Path,
+        pretty_path: &str,
+        source: &str,
+        report: &mut Report,
+    ) {
+        let relative = file.strip_prefix(&self.root).expect("should always be relative to root");
+        // Don't check the reference. It has several legitimate things that
+        // look like [<code>…</code>]. The reference has its own broken link
+        // checker in its CI which handles this using pulldown_cmark.
+        //
+        // This checks both the end of the root (when checking just the
+        // reference directory) or the beginning (when checking all docs).
+        if self.root.ends_with("reference") || relative.starts_with("reference") {
+            return;
+        }
         // Search for intra-doc links that rustdoc didn't warn about
         // FIXME(#77199, 77200) Rustdoc should just warn about these directly.
         // NOTE: only looks at one line at a time; in practice this should find most links
@@ -379,12 +382,6 @@ fn check(&mut self, file: &Path, report: &mut Report) {
                 }
             }
         }
-        // we don't need the source anymore,
-        // so drop to reduce memory-usage
-        match self.cache.get_mut(&pretty_path).unwrap() {
-            FileEntry::HtmlFile { source, .. } => *source = Rc::new(String::new()),
-            _ => unreachable!("must be html file"),
-        }
     }
 
     /// Load a file from disk, or from the cache if available.
index 3efb2d733d426a8627f8b916983e11de2051f29b..607ffe0cc59feb11d3c735ea3bddd0d7b53aa0c3 100644 (file)
@@ -67,9 +67,9 @@ jobs:
         shell: bash
         run: |
           if [[ ${{ github.event_name }} == 'schedule' ]]; then
-            ./rustup-toolchain HEAD --host ${{ matrix.host_target }}
+            ./miri toolchain HEAD --host ${{ matrix.host_target }}
           else
-            ./rustup-toolchain "" --host ${{ matrix.host_target }}
+            ./miri toolchain "" --host ${{ matrix.host_target }}
           fi
 
       - name: Show Rust version
@@ -118,7 +118,7 @@ jobs:
       - name: Install "master" toolchain
         shell: bash
         run: |
-          ./rustup-toolchain "" -c clippy
+          ./miri toolchain
 
       - name: Show Rust version
         run: |
index 36bd991740a827a649685e75dba0d3fb67dcfca2..724cf26df2b9b3f85a26b45e7ea8144233dfea05 100644 (file)
@@ -4,6 +4,6 @@ tasks:
   - before: echo "..."
     init: |
       cargo install rustup-toolchain-install-master
-      ./rustup-toolchain
+      ./miri toolchain
       ./miri build
-    command: echo "Run tests with ./miri test"
\ No newline at end of file
+    command: echo "Run tests with ./miri test"
index b1e6b9c69d390846500fd6c4eaf5708fc76b697f..5c41547616ec68d0e9c8d50673cbadf45f2ffef8 100644 (file)
@@ -23,13 +23,13 @@ tested against. Other versions will likely not work. After installing
 [`rustup-toolchain-install-master`], you can run the following command to
 install that exact version of rustc as a toolchain:
 ```
-./rustup-toolchain
+./miri toolchain
 ```
 This will set up a rustup toolchain called `miri` and set it as an override for
 the current directory.
 
 You can also create a `.auto-everything` file (contents don't matter, can be empty), which
-will cause any `./miri` command to automatically call `rustup-toolchain`, `clippy` and `rustfmt`
+will cause any `./miri` command to automatically call `./miri toolchain`, `clippy` and `rustfmt`
 for you. If you don't want all of these to happen, you can add individual `.auto-toolchain`,
 `.auto-clippy` and `.auto-fmt` files respectively.
 
@@ -132,12 +132,15 @@ development version of Miri using
 and then you can use it as if it was installed by `rustup`.  Make sure you use
 the same toolchain when calling `cargo miri` that you used when installing Miri!
 Usually this means you have to write `cargo +miri miri ...` to select the `miri`
-toolchain that was installed by `./rustup-toolchain`.
+toolchain that was installed by `./miri toolchain`.
 
 There's a test for the cargo wrapper in the `test-cargo-miri` directory; run
 `./run-test.py` in there to execute it. Like `./miri test`, this respects the
 `MIRI_TEST_TARGET` environment variable to execute the test for another target.
 
+Note that installing Miri like this will "take away" Miri management from `rustup`.
+If you want to later go back to a rustup-installed Miri, run `rustup update`.
+
 ### Using a modified standard library
 
 Miri re-builds the standard library into a custom sysroot, so it is fairly easy
@@ -214,7 +217,7 @@ for changes in rustc. In both cases, `rustc-version` needs updating.
 
 To update the `rustc-version` file and install the latest rustc, you can run:
 ```
-./rustup-toolchain HEAD
+./miri toolchain HEAD
 ```
 
 Now edit Miri until `./miri test` passes, and submit a PR. Generally, it is
@@ -290,16 +293,14 @@ cargo run --release -p josh-proxy -- --local=$(pwd)/local --remote=https://githu
 
 ### Importing changes from the rustc repo
 
+Josh needs to be running, as described above.
 We assume we start on an up-to-date master branch in the Miri repo.
 
 ```sh
-# Fetch rustc side of the history. Takes ca 5 min the first time.
-# Do NOT change that commit ID, it needs to be exactly this!
-git fetch http://localhost:8000/rust-lang/rust.git:at_commit=75dd959a3a40eb5b4574f8d2e23aa6efbeb33573[:prefix=src/tools/miri]:/src/tools/miri.git master
-# Include that history into ours.
-git merge FETCH_HEAD -m "merge rustc history"
+# Fetch and merge rustc side of the history. Takes ca 5 min the first time.
+./miri rustc-pull
 # Update toolchain reference and apply formatting.
-./rustup-toolchain HEAD && ./miri fmt
+./miri toolchain HEAD && ./miri fmt
 git commit -am "rustup"
 ```
 
@@ -310,16 +311,15 @@ needed.
 
 ### Exporting changes to the rustc repo
 
-We will use the josh proxy to push to your fork of rustc. You need to make sure
-that the master branch of your fork is up-to-date. Also make sure that there
-exists no branch called `miri` in your fork. Then run the following in the Miri
-repo, assuming we are on an up-to-date master branch:
+Josh needs to be running, as described above. We will use the josh proxy to push
+to your fork of rustc. Run the following in the Miri repo, assuming we are on an
+up-to-date master branch:
 
 ```sh
 # Push the Miri changes to your rustc fork (substitute your github handle for YOUR_NAME).
-# Do NOT change that commit ID, it needs to be exactly this!
-git push http://localhost:8000/YOUR_NAME/rust.git:at_commit=75dd959a3a40eb5b4574f8d2e23aa6efbeb33573[:prefix=src/tools/miri]:/src/tools/miri.git -o base=master HEAD:miri
+./miri rustc-push YOUR_NAME miri
 ```
 
-This will create a new branch in your fork, and the output should include a link
-to create a rustc PR that will integrate those changes into the main repository.
+This will create a new branch called 'miri' in your fork, and the output should
+include a link to create a rustc PR that will integrate those changes into the
+main repository.
index 5803a88c0e757846d1e1661d411d30baf4f04e83..1185525f6865c33cd3a3d8a3d2a2731c45209e92 100644 (file)
@@ -374,14 +374,15 @@ to Miri failing to detect cases of undefined behavior in a program.
   application instead of raising an error within the context of Miri (and halting
   execution). Note that code might not expect these operations to ever panic, so
   this flag can lead to strange (mis)behavior.
-* `-Zmiri-retag-fields` changes Stacked Borrows retagging to recurse into fields.
+* `-Zmiri-retag-fields` changes Stacked Borrows retagging to recurse into *all* fields.
   This means that references in fields of structs/enums/tuples/arrays/... are retagged,
   and in particular, they are protected when passed as function arguments.
+  (The default is to recurse only in cases where rustc would actually emit a `noalias` attribute.)
 * `-Zmiri-retag-fields=<all|none|scalar>` controls when Stacked Borrows retagging recurses into
   fields. `all` means it always recurses (like `-Zmiri-retag-fields`), `none` means it never
-  recurses (the default), `scalar` means it only recurses for types where we would also emit
+  recurses, `scalar` (the default) means it only recurses for types where we would also emit
   `noalias` annotations in the generated LLVM IR (types passed as indivudal scalars or pairs of
-  scalars).
+  scalars). Setting this to `none` is **unsound**.
 * `-Zmiri-tag-gc=<blocks>` configures how often the pointer tag garbage collector runs. The default
   is to search for and remove unreachable tags once every `10000` basic blocks. Setting this to
   `0` disables the garbage collector, which causes some programs to have explosive memory usage
@@ -419,9 +420,9 @@ Some native rustc `-Z` flags are also very relevant for Miri:
 
 Moreover, Miri recognizes some environment variables:
 
-* `MIRI_AUTO_OPS` indicates whether the automatic execution of rustfmt, clippy and rustup-toolchain
-  should be skipped. If it is set to any value, they are skipped. This is used for avoiding
-  infinite recursion in `./miri` and to allow automated IDE actions to avoid the auto ops.
+* `MIRI_AUTO_OPS` indicates whether the automatic execution of rustfmt, clippy and toolchain setup
+  should be skipped. If it is set to any value, they are skipped. This is used for avoiding infinite
+  recursion in `./miri` and to allow automated IDE actions to avoid the auto ops.
 * `MIRI_LOG`, `MIRI_BACKTRACE` control logging and backtrace printing during
   Miri executions, also [see "Testing the Miri driver" in `CONTRIBUTING.md`][testing-miri].
 * `MIRIFLAGS` (recognized by `cargo miri` and the test suite) defines extra
@@ -433,8 +434,10 @@ Moreover, Miri recognizes some environment variables:
   trigger a re-build of the standard library; you have to clear the Miri build
   cache manually (on Linux, `rm -rf ~/.cache/miri`).
 * `MIRI_SYSROOT` (recognized by `cargo miri` and the Miri driver) indicates the sysroot to use. When
-  using `cargo miri`, only set this if you do not want to use the automatically created sysroot. For
-  directly invoking the Miri driver, this variable (or a `--sysroot` flag) is mandatory.
+  using `cargo miri`, this skips the automatic setup -- only set this if you do not want to use the
+  automatically created sysroot. For directly invoking the Miri driver, this variable (or a
+  `--sysroot` flag) is mandatory. When invoking `cargo miri setup`, this indicates where the sysroot
+  will be put.
 * `MIRI_TEST_TARGET` (recognized by the test suite and the `./miri` script) indicates which target
   architecture to test against.  `miri` and `cargo miri` accept the `--target` flag for the same
   purpose.
index 22da80be90211c9584f802646ec0d738f3fe94ae..df36041c75ed32f5af95b6a47907afc38fbfa7d6 100644 (file)
@@ -528,7 +528,7 @@ pub fn phase_runner(mut binary_args: impl Iterator<Item = String>, phase: Runner
     cmd.args(binary_args);
 
     // Make sure we use the build-time working directory for interpreting Miri/rustc arguments.
-    // But then we need to switch to the run-time one, which we instruct Miri do do by setting `MIRI_CWD`.
+    // But then we need to switch to the run-time one, which we instruct Miri to do by setting `MIRI_CWD`.
     cmd.current_dir(info.current_dir);
     cmd.env("MIRI_CWD", env::current_dir().unwrap());
 
index 72d8ef2f752248d0cd7a7187b40957768e61ebf7..f3841a6140839cfaae10242bbbf3f0bf9259e40c 100644 (file)
@@ -17,10 +17,8 @@ pub fn setup(subcommand: &MiriCommand, target: &str, rustc_version: &VersionMeta
     let only_setup = matches!(subcommand, MiriCommand::Setup);
     let ask_user = !only_setup;
     let print_sysroot = only_setup && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path
-    if std::env::var_os("MIRI_SYSROOT").is_some() {
-        if only_setup {
-            println!("WARNING: MIRI_SYSROOT already set, not doing anything.")
-        }
+    if !only_setup && std::env::var_os("MIRI_SYSROOT").is_some() {
+        // Skip setup step if MIRI_SYSROOT is explicitly set, *unless* we are `cargo miri setup`.
         return;
     }
 
@@ -61,8 +59,13 @@ pub fn setup(subcommand: &MiriCommand, target: &str, rustc_version: &VersionMeta
     }
 
     // Determine where to put the sysroot.
-    let user_dirs = directories::ProjectDirs::from("org", "rust-lang", "miri").unwrap();
-    let sysroot_dir = user_dirs.cache_dir();
+    let sysroot_dir = match std::env::var_os("MIRI_SYSROOT") {
+        Some(dir) => PathBuf::from(dir),
+        None => {
+            let user_dirs = directories::ProjectDirs::from("org", "rust-lang", "miri").unwrap();
+            user_dirs.cache_dir().to_owned()
+        }
+    };
     // Sysroot configuration and build details.
     let sysroot_config = if std::env::var_os("MIRI_NO_STD").is_some() {
         SysrootConfig::NoStd
@@ -111,7 +114,7 @@ pub fn setup(subcommand: &MiriCommand, target: &str, rustc_version: &VersionMeta
         (command, rustflags)
     };
     // Make sure all target-level Miri invocations know their sysroot.
-    std::env::set_var("MIRI_SYSROOT", sysroot_dir);
+    std::env::set_var("MIRI_SYSROOT", &sysroot_dir);
 
     // Do the build.
     if only_setup {
@@ -121,7 +124,7 @@ pub fn setup(subcommand: &MiriCommand, target: &str, rustc_version: &VersionMeta
         // We want to be quiet, but still let the user know that something is happening.
         eprint!("Preparing a sysroot for Miri (target: {target})... ");
     }
-    Sysroot::new(sysroot_dir, target)
+    Sysroot::new(&sysroot_dir, target)
         .build_from_source(&rust_src, BuildMode::Check, sysroot_config, rustc_version, cargo_cmd)
         .unwrap_or_else(|_| {
             if only_setup {
index e492308a62eb5f9930c4aafe708f2d9ae6ef18f6..f0986bfb1cdbe847216bff42cd684ee19924c745 100755 (executable)
@@ -42,6 +42,22 @@ many different seeds.
 Runs the benchmarks from bench-cargo-miri in hyperfine. hyperfine needs to be installed.
 <benches> can explicitly list the benchmarks to run; by default, all of them are run.
 
+./miri rustc-pull:
+Pull and merge Miri changes from the rustc repo.
+
+./miri rustc-push <github user> <branch>:
+Push Miri changes back to the rustc repo. This will update the 'master' branch
+in the Rust fork of the given user to upstream. It will also pull a copy of the
+rustc history into the Miri repo, unless you set the RUSTC_GIT env var to an
+existing clone of the rustc repo.
+
+./miri toolchain <commit> <flags>:
+Update and activate the rustup toolchain 'miri'. If no commit is given, updates
+to the commit given in the `rust-version` file. If the commit is `HEAD`, updates
+to the latest upstream rustc commit.
+`rustup-toolchain-install-master` must be installed for this to work. Any extra
+flags are passed to `rustup-toolchain-install-master`.
+
   ENVIRONMENT VARIABLES
 
 MIRI_SYSROOT:
@@ -52,37 +68,98 @@ Pass extra flags to all cargo invocations. (Ignored by `./miri cargo`.)
 EOF
 )
 
-## We need to know where we are.
+## We need to know which command to run and some global constants.
+COMMAND="$1"
+if [ -z "$COMMAND" ]; then
+    echo "$USAGE"
+    exit 1
+fi
+shift
 # macOS does not have a useful readlink/realpath so we have to use Python instead...
 MIRIDIR=$(python3 -c 'import os, sys; print(os.path.dirname(os.path.realpath(sys.argv[1])))' "$0")
+# Used for rustc syncs.
+JOSH_FILTER=":at_commit=75dd959a3a40eb5b4574f8d2e23aa6efbeb33573[:prefix=src/tools/miri]:/src/tools/miri"
+# Needed for `./miri bench`.
+TOOLCHAIN=$(cd "$MIRIDIR"; rustup show active-toolchain | head -n 1 | cut -d ' ' -f 1)
 
-## Run the auto-things.
-if [ -z "$MIRI_AUTO_OPS" ]; then
-    export MIRI_AUTO_OPS=42
-
-    # Run this first, so that the toolchain doesn't change after
-    # other code has run.
-    if [ -f "$MIRIDIR/.auto-everything" ] || [ -f "$MIRIDIR/.auto-toolchain" ] ; then
-        (cd "$MIRIDIR" && ./rustup-toolchain)
+## Early commands, that don't do auto-things and don't want the environment-altering things happening below.
+case "$COMMAND" in
+toolchain)
+    cd "$MIRIDIR"
+    # Make sure rustup-toolchain-install-master is installed.
+    if ! which rustup-toolchain-install-master >/dev/null; then
+        echo "Please install rustup-toolchain-install-master by running 'cargo install rustup-toolchain-install-master'"
+        exit 1
     fi
-
-    if [ -f "$MIRIDIR/.auto-everything" ] || [ -f "$MIRIDIR/.auto-fmt" ] ; then
-        $0 fmt
+    # Determine new commit.
+    if [[ "$1" == "" ]]; then
+        NEW_COMMIT=$(cat rust-version)
+    elif [[ "$1" == "HEAD" ]]; then
+        NEW_COMMIT=$(git ls-remote https://github.com/rust-lang/rust/ HEAD | cut -f 1)
+    else
+        NEW_COMMIT="$1"
     fi
-
-    if [ -f "$MIRIDIR/.auto-everything" ] || [ -f "$MIRIDIR/.auto-clippy" ] ; then
-        $0 clippy -- -D warnings
+    echo "$NEW_COMMIT" > rust-version
+    shift || true # don't fail if shifting fails because no commit was given
+    # Check if we already are at that commit.
+    CUR_COMMIT=$(rustc +miri --version -v 2>/dev/null | grep "^commit-hash: " | cut -d " " -f 2)
+    if [[ "$CUR_COMMIT" == "$NEW_COMMIT" ]]; then
+        echo "miri toolchain is already at commit $CUR_COMMIT."
+        rustup override set miri
+        exit 0
     fi
-fi
-
-## Determine command and toolchain.
-COMMAND="$1"
-[ $# -gt 0 ] && shift
-# Doing this *after* auto-toolchain logic above, since that might change the toolchain.
-TOOLCHAIN=$(cd "$MIRIDIR"; rustup show active-toolchain | head -n 1 | cut -d ' ' -f 1)
-
-## Handle some commands early, since they should *not* alter the environment.
-case "$COMMAND" in
+    # Install and setup new toolchain.
+    rustup toolchain uninstall miri
+    rustup-toolchain-install-master -n miri -c cargo -c rust-src -c rustc-dev -c llvm-tools -c rustfmt -c clippy "$@" -- "$NEW_COMMIT"
+    rustup override set miri
+    # Cleanup.
+    cargo clean
+    # Call 'cargo metadata' on the sources in case that changes the lockfile
+    # (which fails under some setups when it is done from inside vscode).
+    cargo metadata --format-version 1 --manifest-path "$(rustc --print sysroot)/lib/rustlib/rustc-src/rust/compiler/rustc/Cargo.toml" >/dev/null
+    # Done!
+    exit 0
+    ;;
+rustc-pull)
+    cd "$MIRIDIR"
+    git fetch http://localhost:8000/rust-lang/rust.git$JOSH_FILTER.git master
+    git merge FETCH_HEAD --no-ff -m "Merge from rustc"
+    exit 0
+    ;;
+rustc-push)
+    USER="$1"
+    BRANCH="$2"
+    if [ -z "$USER" ] || [ -z "$BRANCH" ]; then
+        echo "Usage: $0 rustc-push <github user> <branch>"
+        exit 1
+    fi
+    if [ -n "$RUSTC_GIT" ]; then
+        # Use an existing fork for the branch updates.
+        cd "$RUSTC_GIT"
+    else
+        # Do this in the local Miri repo.
+        echo "This will pull a copy of the rust-lang/rust history into this Miri checkout, growing it by about 1GB."
+        read -r -p "To avoid that, abort now and set the RUSTC_GIT environment variable to an existing rustc checkout. Proceed? [y/N] "
+        if [[ ! $REPLY =~ ^[Yy]$ ]]; then
+            exit 1
+        fi
+        cd "$MIRIDIR"
+    fi
+    # Prepare the branches. For reliable pushing we need to push to a non-existent branch
+    # and set `-o base` to a branch that holds current rustc master.
+    echo "Preparing $USER/rust..."
+    if git fetch https://github.com/$USER/rust $BRANCH &>/dev/null; then
+        echo "The '$BRANCH' seems to already exist in $USER/rust. Please delete it and try again."
+        exit 1
+    fi
+    git fetch https://github.com/rust-lang/rust master
+    git push https://github.com/$USER/rust FETCH_HEAD:master
+    # Do the actual push.
+    cd "$MIRIDIR"
+    echo "Pushing Miri changes..."
+    git push http://localhost:8000/$USER/rust.git$JOSH_FILTER.git HEAD:$BRANCH -o base=master
+    exit 0
+    ;;
 many-seeds)
     for SEED in $({ echo obase=16; seq 0 255; } | bc); do
         echo "Trying seed: $SEED"
@@ -106,9 +183,29 @@ bench)
     ;;
 esac
 
+## Run the auto-things.
+if [ -z "$MIRI_AUTO_OPS" ]; then
+    export MIRI_AUTO_OPS=42
+
+    # Run this first, so that the toolchain doesn't change after
+    # other code has run.
+    if [ -f "$MIRIDIR/.auto-everything" ] || [ -f "$MIRIDIR/.auto-toolchain" ] ; then
+        $0 toolchain
+        # Let's make sure to actually use that toolchain, too.
+        TOOLCHAIN=miri
+    fi
+
+    if [ -f "$MIRIDIR/.auto-everything" ] || [ -f "$MIRIDIR/.auto-fmt" ] ; then
+        $0 fmt
+    fi
+
+    if [ -f "$MIRIDIR/.auto-everything" ] || [ -f "$MIRIDIR/.auto-clippy" ] ; then
+        $0 clippy -- -D warnings
+    fi
+fi
+
 ## Prepare the environment
 # Determine some toolchain properties
-# export the target so its available in miri
 TARGET=$(rustc +$TOOLCHAIN --version --verbose | grep "^host:" | cut -d ' ' -f 2)
 SYSROOT=$(rustc +$TOOLCHAIN --print sysroot)
 LIBDIR=$SYSROOT/lib/rustlib/$TARGET/lib
@@ -227,10 +324,7 @@ cargo)
     $CARGO "$@"
     ;;
 *)
-    if [ -n "$COMMAND" ]; then
-      echo "Unknown command: $COMMAND"
-      echo
-    fi
-    echo "$USAGE"
+    echo "Unknown command: $COMMAND"
     exit 1
+    ;;
 esac
index d0e98a8b0dba9ce8f6346bc2dc75fbafaa25e7d6..13492d183c99996c2a0c100fa8a45d270130c327 100644 (file)
@@ -1 +1 @@
-85d089b41e2a0c0f07ab34f6c5a7c451389f25e6
+b03502b35d111bef0399a66ab3cc765f0802e8ba
diff --git a/src/tools/miri/rustup-toolchain b/src/tools/miri/rustup-toolchain
deleted file mode 100755 (executable)
index d7730f2..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/bin/bash
-set -e
-# Manages a rustup toolchain called "miri".
-#
-# All commands set "miri" as the override toolchain for the current directory,
-# and make the `rust-version` file match that toolchain.
-#
-# USAGE:
-#
-# ./rustup-toolchain: Update "miri" toolchain to match `rust-version` (the known-good version for this commit).
-#
-# ./rustup-toolchain HEAD: Update "miri" toolchain and `rust-version` file to latest rustc HEAD.
-#
-# ./rustup-toolchain $COMMIT: Update "miri" toolchain and `rust-version` file to match that commit.
-#
-# Any extra parameters are passed to `rustup-toolchain-install-master`.
-
-# Make sure rustup-toolchain-install-master is installed.
-if ! which rustup-toolchain-install-master >/dev/null; then
-    echo "Please install rustup-toolchain-install-master by running 'cargo install rustup-toolchain-install-master'"
-    exit 1
-fi
-
-# Determine new commit.
-if [[ "$1" == "" ]]; then
-    NEW_COMMIT=$(cat rust-version)
-elif [[ "$1" == "HEAD" ]]; then
-    NEW_COMMIT=$(git ls-remote https://github.com/rust-lang/rust/ HEAD | cut -f 1)
-else
-    NEW_COMMIT="$1"
-fi
-echo "$NEW_COMMIT" > rust-version
-shift || true # don't fail if shifting fails
-
-# Check if we already are at that commit.
-CUR_COMMIT=$(rustc +miri --version -v 2>/dev/null | grep "^commit-hash: " | cut -d " " -f 2)
-if [[ "$CUR_COMMIT" == "$NEW_COMMIT" ]]; then
-    echo "miri toolchain is already at commit $CUR_COMMIT."
-    rustup override set miri
-    exit 0
-fi
-
-# Install and setup new toolchain.
-rustup toolchain uninstall miri
-rustup-toolchain-install-master -n miri -c cargo -c rust-src -c rustc-dev -c llvm-tools -c rustfmt -c clippy "$@" -- "$NEW_COMMIT"
-rustup override set miri
-
-# Cleanup.
-cargo clean
-
-# Call 'cargo metadata' on the sources in case that changes the lockfile
-# (which fails under some setups when it is done from inside vscode).
-cargo metadata --format-version 1 --manifest-path "$(rustc --print sysroot)/lib/rustlib/rustc-src/rust/compiler/rustc/Cargo.toml" >/dev/null
index 791931901e2a96765ba3ca11f8cce9cf33cfe03e..eb42cdf80abbeb5de883a9dc009948fc5777f2df 100644 (file)
@@ -3,7 +3,7 @@
 
 use rustc_index::vec::Idx;
 
-use super::sync::EvalContextExtPriv;
+use super::sync::EvalContextExtPriv as _;
 use super::thread::MachineCallback;
 use super::vector_clock::VClock;
 use crate::*;
@@ -52,6 +52,43 @@ fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
     }
 }
 
+impl<'mir, 'tcx: 'mir> EvalContextExtPriv<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
+trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
+    /// Synchronize with the previous initialization attempt of an InitOnce.
+    #[inline]
+    fn init_once_observe_attempt(&mut self, id: InitOnceId) {
+        let this = self.eval_context_mut();
+        let current_thread = this.get_active_thread();
+
+        if let Some(data_race) = &this.machine.data_race {
+            data_race.validate_lock_acquire(
+                &this.machine.threads.sync.init_onces[id].data_race,
+                current_thread,
+            );
+        }
+    }
+
+    #[inline]
+    fn init_once_wake_waiter(
+        &mut self,
+        id: InitOnceId,
+        waiter: InitOnceWaiter<'mir, 'tcx>,
+    ) -> InterpResult<'tcx> {
+        let this = self.eval_context_mut();
+        let current_thread = this.get_active_thread();
+
+        this.unblock_thread(waiter.thread);
+
+        // Call callback, with the woken-up thread as `current`.
+        this.set_active_thread(waiter.thread);
+        this.init_once_observe_attempt(id);
+        waiter.callback.call(this)?;
+        this.set_active_thread(current_thread);
+
+        Ok(())
+    }
+}
+
 impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
 pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
     fn init_once_get_or_create_id(
@@ -141,20 +178,7 @@ fn init_once_complete(&mut self, id: InitOnceId) -> InterpResult<'tcx> {
         // Wake up everyone.
         // need to take the queue to avoid having `this` be borrowed multiple times
         for waiter in std::mem::take(&mut init_once.waiters) {
-            // End of the wait happens-before woken-up thread.
-            if let Some(data_race) = &this.machine.data_race {
-                data_race.validate_lock_acquire(
-                    &this.machine.threads.sync.init_onces[id].data_race,
-                    waiter.thread,
-                );
-            }
-
-            this.unblock_thread(waiter.thread);
-
-            // Call callback, with the woken-up thread as `current`.
-            this.set_active_thread(waiter.thread);
-            waiter.callback.call(this)?;
-            this.set_active_thread(current_thread);
+            this.init_once_wake_waiter(id, waiter)?;
         }
 
         Ok(())
@@ -172,28 +196,13 @@ fn init_once_fail(&mut self, id: InitOnceId) -> InterpResult<'tcx> {
         );
 
         // Each complete happens-before the end of the wait
-        // FIXME: should this really induce synchronization? If we think of it as a lock, then yes,
-        // but the docs don't talk about such details.
         if let Some(data_race) = &this.machine.data_race {
             data_race.validate_lock_release(&mut init_once.data_race, current_thread);
         }
 
         // Wake up one waiting thread, so they can go ahead and try to init this.
         if let Some(waiter) = init_once.waiters.pop_front() {
-            // End of the wait happens-before woken-up thread.
-            if let Some(data_race) = &this.machine.data_race {
-                data_race.validate_lock_acquire(
-                    &this.machine.threads.sync.init_onces[id].data_race,
-                    waiter.thread,
-                );
-            }
-
-            this.unblock_thread(waiter.thread);
-
-            // Call callback, with the woken-up thread as `current`.
-            this.set_active_thread(waiter.thread);
-            waiter.callback.call(this)?;
-            this.set_active_thread(current_thread);
+            this.init_once_wake_waiter(id, waiter)?;
         } else {
             // Nobody there to take this, so go back to 'uninit'
             init_once.status = InitOnceStatus::Uninitialized;
@@ -201,4 +210,19 @@ fn init_once_fail(&mut self, id: InitOnceId) -> InterpResult<'tcx> {
 
         Ok(())
     }
+
+    /// Synchronize with the previous completion of an InitOnce.
+    /// Must only be called after checking that it is complete.
+    #[inline]
+    fn init_once_observe_completed(&mut self, id: InitOnceId) {
+        let this = self.eval_context_mut();
+
+        assert_eq!(
+            this.init_once_status(id),
+            InitOnceStatus::Complete,
+            "observing the completion of incomplete init once"
+        );
+
+        this.init_once_observe_attempt(id);
+    }
 }
index e76610e7302804c76478e49f9389df4473863ee7..ba5ae852c5a960663d694ca6eb9ca0020047730c 100644 (file)
@@ -116,13 +116,25 @@ struct RwLock {
 
 declare_id!(CondvarId);
 
+#[derive(Debug, Copy, Clone)]
+pub enum RwLockMode {
+    Read,
+    Write,
+}
+
+#[derive(Debug)]
+pub enum CondvarLock {
+    Mutex(MutexId),
+    RwLock { id: RwLockId, mode: RwLockMode },
+}
+
 /// A thread waiting on a conditional variable.
 #[derive(Debug)]
 struct CondvarWaiter {
     /// The thread that is waiting on this variable.
     thread: ThreadId,
-    /// The mutex on which the thread is waiting.
-    mutex: MutexId,
+    /// The mutex or rwlock on which the thread is waiting.
+    lock: CondvarLock,
 }
 
 /// The conditional variable state.
@@ -569,16 +581,16 @@ fn condvar_is_awaited(&mut self, id: CondvarId) -> bool {
     }
 
     /// Mark that the thread is waiting on the conditional variable.
-    fn condvar_wait(&mut self, id: CondvarId, thread: ThreadId, mutex: MutexId) {
+    fn condvar_wait(&mut self, id: CondvarId, thread: ThreadId, lock: CondvarLock) {
         let this = self.eval_context_mut();
         let waiters = &mut this.machine.threads.sync.condvars[id].waiters;
         assert!(waiters.iter().all(|waiter| waiter.thread != thread), "thread is already waiting");
-        waiters.push_back(CondvarWaiter { thread, mutex });
+        waiters.push_back(CondvarWaiter { thread, lock });
     }
 
     /// Wake up some thread (if there is any) sleeping on the conditional
     /// variable.
-    fn condvar_signal(&mut self, id: CondvarId) -> Option<(ThreadId, MutexId)> {
+    fn condvar_signal(&mut self, id: CondvarId) -> Option<(ThreadId, CondvarLock)> {
         let this = self.eval_context_mut();
         let current_thread = this.get_active_thread();
         let condvar = &mut this.machine.threads.sync.condvars[id];
@@ -592,7 +604,7 @@ fn condvar_signal(&mut self, id: CondvarId) -> Option<(ThreadId, MutexId)> {
             if let Some(data_race) = data_race {
                 data_race.validate_lock_acquire(&condvar.data_race, waiter.thread);
             }
-            (waiter.thread, waiter.mutex)
+            (waiter.thread, waiter.lock)
         })
     }
 
index a3fc343f8b67ce5c24554760c1135876260d6e50..81132db94cf181ff1583031304e4535d47099dbc 100644 (file)
@@ -163,7 +163,7 @@ fn default() -> MiriConfig {
             mute_stdout_stderr: false,
             preemption_rate: 0.01, // 1%
             report_progress: None,
-            retag_fields: RetagFields::No,
+            retag_fields: RetagFields::OnlyScalar,
             external_so_file: None,
             gc_interval: 10_000,
             num_cpus: 1,
index 3b73d05907b4effea73fc1a019f943c0d7cc367f..8028ce753548888ca1aef048e896e0af0e134f33 100644 (file)
@@ -3,7 +3,6 @@
 #![feature(never_type)]
 #![feature(try_blocks)]
 #![feature(io_error_more)]
-#![feature(int_log)]
 #![feature(variant_count)]
 #![feature(yeet_expr)]
 #![feature(is_some_and)]
index fcb006920794c52da58e605e4a7a7270223d116f..a7275646847e29ed42c09ceede08e0cea1f6ccb7 100644 (file)
@@ -3,6 +3,7 @@
 use rustc_hir::LangItem;
 use rustc_middle::ty::{layout::TyAndLayout, query::TyCtxtAt, Ty};
 
+use crate::concurrency::sync::CondvarLock;
 use crate::concurrency::thread::{MachineCallback, Time};
 use crate::*;
 
@@ -696,8 +697,12 @@ fn pthread_cond_init(
     fn pthread_cond_signal(&mut self, cond_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> {
         let this = self.eval_context_mut();
         let id = this.condvar_get_or_create_id(cond_op, CONDVAR_ID_OFFSET)?;
-        if let Some((thread, mutex)) = this.condvar_signal(id) {
-            post_cond_signal(this, thread, mutex)?;
+        if let Some((thread, lock)) = this.condvar_signal(id) {
+            if let CondvarLock::Mutex(mutex) = lock {
+                post_cond_signal(this, thread, mutex)?;
+            } else {
+                panic!("condvar should not have an rwlock on unix");
+            }
         }
 
         Ok(0)
@@ -710,8 +715,12 @@ fn pthread_cond_broadcast(
         let this = self.eval_context_mut();
         let id = this.condvar_get_or_create_id(cond_op, CONDVAR_ID_OFFSET)?;
 
-        while let Some((thread, mutex)) = this.condvar_signal(id) {
-            post_cond_signal(this, thread, mutex)?;
+        while let Some((thread, lock)) = this.condvar_signal(id) {
+            if let CondvarLock::Mutex(mutex) = lock {
+                post_cond_signal(this, thread, mutex)?;
+            } else {
+                panic!("condvar should not have an rwlock on unix");
+            }
         }
 
         Ok(0)
@@ -729,7 +738,7 @@ fn pthread_cond_wait(
         let active_thread = this.get_active_thread();
 
         release_cond_mutex_and_block(this, active_thread, mutex_id)?;
-        this.condvar_wait(id, active_thread, mutex_id);
+        this.condvar_wait(id, active_thread, CondvarLock::Mutex(mutex_id));
 
         Ok(0)
     }
@@ -768,7 +777,7 @@ fn pthread_cond_timedwait(
         };
 
         release_cond_mutex_and_block(this, active_thread, mutex_id)?;
-        this.condvar_wait(id, active_thread, mutex_id);
+        this.condvar_wait(id, active_thread, CondvarLock::Mutex(mutex_id));
 
         // We return success for now and override it in the timeout callback.
         this.write_scalar(Scalar::from_i32(0), dest)?;
index 2a34a3a47bbb5c3f2160b8cd4ba325bdee6f5e74..e16749c986b168cfb6f77a350e69783271126d12 100644 (file)
@@ -273,6 +273,25 @@ fn emulate_foreign_item_by_name(
                 let result = this.InitOnceComplete(ptr, flags, context)?;
                 this.write_scalar(result, dest)?;
             }
+            "SleepConditionVariableSRW" => {
+                let [condvar, lock, timeout, flags] =
+                    this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
+
+                let result = this.SleepConditionVariableSRW(condvar, lock, timeout, flags, dest)?;
+                this.write_scalar(result, dest)?;
+            }
+            "WakeConditionVariable" => {
+                let [condvar] =
+                    this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
+
+                this.WakeConditionVariable(condvar)?;
+            }
+            "WakeAllConditionVariable" => {
+                let [condvar] =
+                    this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
+
+                this.WakeAllConditionVariable(condvar)?;
+            }
 
             // Dynamic symbol loading
             "GetProcAddress" => {
index 8156ae8af1ef11128bc9d61a81709835d81bae32..8f414d98dba5f70a979aa132a0caac8bbdd979c5 100644 (file)
@@ -3,11 +3,45 @@
 use rustc_target::abi::Size;
 
 use crate::concurrency::init_once::InitOnceStatus;
+use crate::concurrency::sync::{CondvarLock, RwLockMode};
 use crate::concurrency::thread::MachineCallback;
 use crate::*;
 
 const SRWLOCK_ID_OFFSET: u64 = 0;
 const INIT_ONCE_ID_OFFSET: u64 = 0;
+const CONDVAR_ID_OFFSET: u64 = 0;
+
+impl<'mir, 'tcx> EvalContextExtPriv<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
+trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
+    /// Try to reacquire the lock associated with the condition variable after we
+    /// were signaled.
+    fn reacquire_cond_lock(
+        &mut self,
+        thread: ThreadId,
+        lock: RwLockId,
+        mode: RwLockMode,
+    ) -> InterpResult<'tcx> {
+        let this = self.eval_context_mut();
+        this.unblock_thread(thread);
+
+        match mode {
+            RwLockMode::Read =>
+                if this.rwlock_is_write_locked(lock) {
+                    this.rwlock_enqueue_and_block_reader(lock, thread);
+                } else {
+                    this.rwlock_reader_lock(lock, thread);
+                },
+            RwLockMode::Write =>
+                if this.rwlock_is_locked(lock) {
+                    this.rwlock_enqueue_and_block_writer(lock, thread);
+                } else {
+                    this.rwlock_writer_lock(lock, thread);
+                },
+        }
+
+        Ok(())
+    }
+}
 
 impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
 #[allow(non_snake_case)]
@@ -177,8 +211,10 @@ fn call(&self, this: &mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx> {
                     Box::new(Callback { init_once_id: id, pending_place }),
                 )
             }
-            InitOnceStatus::Complete =>
-                this.write_scalar(this.eval_windows("c", "FALSE")?, &pending_place)?,
+            InitOnceStatus::Complete => {
+                this.init_once_observe_completed(id);
+                this.write_scalar(this.eval_windows("c", "FALSE")?, &pending_place)?;
+            }
         }
 
         // This always succeeds (even if the thread is blocked, we will succeed if we ever unblock).
@@ -325,4 +361,131 @@ fn WakeByAddressSingle(&mut self, ptr_op: &OpTy<'tcx, Provenance>) -> InterpResu
 
         Ok(())
     }
+
+    fn SleepConditionVariableSRW(
+        &mut self,
+        condvar_op: &OpTy<'tcx, Provenance>,
+        lock_op: &OpTy<'tcx, Provenance>,
+        timeout_op: &OpTy<'tcx, Provenance>,
+        flags_op: &OpTy<'tcx, Provenance>,
+        dest: &PlaceTy<'tcx, Provenance>,
+    ) -> InterpResult<'tcx, Scalar<Provenance>> {
+        let this = self.eval_context_mut();
+
+        let condvar_id = this.condvar_get_or_create_id(condvar_op, CONDVAR_ID_OFFSET)?;
+        let lock_id = this.rwlock_get_or_create_id(lock_op, SRWLOCK_ID_OFFSET)?;
+        let timeout_ms = this.read_scalar(timeout_op)?.to_u32()?;
+        let flags = this.read_scalar(flags_op)?.to_u32()?;
+
+        let timeout_time = if timeout_ms == this.eval_windows("c", "INFINITE")?.to_u32()? {
+            None
+        } else {
+            let duration = Duration::from_millis(timeout_ms.into());
+            Some(this.machine.clock.now().checked_add(duration).unwrap())
+        };
+
+        let shared_mode = 0x1; // CONDITION_VARIABLE_LOCKMODE_SHARED is not in std
+        let mode = if flags == 0 {
+            RwLockMode::Write
+        } else if flags == shared_mode {
+            RwLockMode::Read
+        } else {
+            throw_unsup_format!("unsupported `Flags` {flags} in `SleepConditionVariableSRW`");
+        };
+
+        let active_thread = this.get_active_thread();
+
+        let was_locked = match mode {
+            RwLockMode::Read => this.rwlock_reader_unlock(lock_id, active_thread),
+            RwLockMode::Write => this.rwlock_writer_unlock(lock_id, active_thread),
+        };
+
+        if !was_locked {
+            throw_ub_format!(
+                "calling SleepConditionVariableSRW with an SRWLock that is not locked by the current thread"
+            );
+        }
+
+        this.block_thread(active_thread);
+        this.condvar_wait(condvar_id, active_thread, CondvarLock::RwLock { id: lock_id, mode });
+
+        if let Some(timeout_time) = timeout_time {
+            struct Callback<'tcx> {
+                thread: ThreadId,
+                condvar_id: CondvarId,
+                lock_id: RwLockId,
+                mode: RwLockMode,
+                dest: PlaceTy<'tcx, Provenance>,
+            }
+
+            impl<'tcx> VisitTags for Callback<'tcx> {
+                fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+                    let Callback { thread: _, condvar_id: _, lock_id: _, mode: _, dest } = self;
+                    dest.visit_tags(visit);
+                }
+            }
+
+            impl<'mir, 'tcx: 'mir> MachineCallback<'mir, 'tcx> for Callback<'tcx> {
+                fn call(&self, this: &mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx> {
+                    this.reacquire_cond_lock(self.thread, self.lock_id, self.mode)?;
+
+                    this.condvar_remove_waiter(self.condvar_id, self.thread);
+
+                    let error_timeout = this.eval_windows("c", "ERROR_TIMEOUT")?;
+                    this.set_last_error(error_timeout)?;
+                    this.write_scalar(this.eval_windows("c", "FALSE")?, &self.dest)?;
+                    Ok(())
+                }
+            }
+
+            this.register_timeout_callback(
+                active_thread,
+                Time::Monotonic(timeout_time),
+                Box::new(Callback {
+                    thread: active_thread,
+                    condvar_id,
+                    lock_id,
+                    mode,
+                    dest: dest.clone(),
+                }),
+            );
+        }
+
+        this.eval_windows("c", "TRUE")
+    }
+
+    fn WakeConditionVariable(&mut self, condvar_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx> {
+        let this = self.eval_context_mut();
+        let condvar_id = this.condvar_get_or_create_id(condvar_op, CONDVAR_ID_OFFSET)?;
+
+        if let Some((thread, lock)) = this.condvar_signal(condvar_id) {
+            if let CondvarLock::RwLock { id, mode } = lock {
+                this.reacquire_cond_lock(thread, id, mode)?;
+                this.unregister_timeout_callback_if_exists(thread);
+            } else {
+                panic!("mutexes should not exist on windows");
+            }
+        }
+
+        Ok(())
+    }
+
+    fn WakeAllConditionVariable(
+        &mut self,
+        condvar_op: &OpTy<'tcx, Provenance>,
+    ) -> InterpResult<'tcx> {
+        let this = self.eval_context_mut();
+        let condvar_id = this.condvar_get_or_create_id(condvar_op, CONDVAR_ID_OFFSET)?;
+
+        while let Some((thread, lock)) = this.condvar_signal(condvar_id) {
+            if let CondvarLock::RwLock { id, mode } = lock {
+                this.reacquire_cond_lock(thread, id, mode)?;
+                this.unregister_timeout_callback_if_exists(thread);
+            } else {
+                panic!("mutexes should not exist on windows");
+            }
+        }
+
+        Ok(())
+    }
 }
index 5ec787dd44113ae9618cf639ac7e7134cc8b984b..9ce02a02ec408faae64fddf54aaf14036e352f58 100644 (file)
@@ -252,7 +252,7 @@ pub fn err_sb_ub<'tcx>(
 /// We need to make at least the following things true:
 ///
 /// U1: After creating a `Uniq`, it is at the top.
-/// U2: If the top is `Uniq`, accesses must be through that `Uniq` or remove it it.
+/// U2: If the top is `Uniq`, accesses must be through that `Uniq` or remove it.
 /// U3: If an access happens with a `Uniq`, it requires the `Uniq` to be in the stack.
 ///
 /// F1: After creating a `&`, the parts outside `UnsafeCell` have our `SharedReadOnly` on top.
@@ -1053,7 +1053,7 @@ fn visit_value(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tc
                 // pointers we need to retag, so we can stop recursion early.
                 // This optimization is crucial for ZSTs, because they can contain way more fields
                 // than we can ever visit.
-                if !place.layout.is_unsized() && place.layout.size < self.ecx.pointer_size() {
+                if place.layout.is_sized() && place.layout.size < self.ecx.pointer_size() {
                     return Ok(());
                 }
 
index 5cefdb08e7879d6816a0d06c5ad0b9a7d2a18a7b..cc774500a3c69d69351c32d542743fe8f1f81730 100644 (file)
@@ -1,4 +1,3 @@
-//@compile-flags: -Zmiri-retag-fields=scalar
 //@error-pattern: which is protected
 struct Newtype<'a>(&'a mut i32, i32);
 
index bc3883575c333381643c7c2f7eb5459cdd967cb1..1aa6e240e30f1699f5122d42d0b7a281092b7354 100644 (file)
@@ -1,4 +1,3 @@
-//@compile-flags: -Zmiri-retag-fields=scalar
 //@error-pattern: which is protected
 struct Newtype<'a>(&'a mut i32);
 
index 7fa9cf77d44b2153bc97303ca886a15925de03e7..5a9dc6afba8da9e85617915b52a0ecf2729eb232 100644 (file)
@@ -1,16 +1,15 @@
 // Make sure that we cannot return a `&mut` that got already invalidated, not even in an `Option`.
-// Due to shallow reborrowing, the error only surfaces when we look into the `Option`.
 fn foo(x: &mut (i32, i32)) -> Option<&mut i32> {
     let xraw = x as *mut (i32, i32);
     let ret = unsafe { &mut (*xraw).1 }; // let-bind to avoid 2phase
     let ret = Some(ret);
     let _val = unsafe { *xraw }; // invalidate xref
-    ret
+    ret //~ ERROR: /retag .* tag does not exist in the borrow stack/
 }
 
 fn main() {
     match foo(&mut (1, 2)) {
-        Some(_x) => {} //~ ERROR: /retag .* tag does not exist in the borrow stack/
+        Some(_x) => {}
         None => {}
     }
 }
index 1068c286c62fa39160e2612c1589444ccc33782e..c0ff35ebcde307aa39834ff5a11314ee51345033 100644 (file)
@@ -1,11 +1,11 @@
 error: Undefined Behavior: trying to retag from <TAG> for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
   --> $DIR/return_invalid_mut_option.rs:LL:CC
    |
-LL |         Some(_x) => {}
-   |              ^^
-   |              |
-   |              trying to retag from <TAG> for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
-   |              this error occurs as part of retag at ALLOC[0x4..0x8]
+LL |     ret
+   |     ^^^
+   |     |
+   |     trying to retag from <TAG> for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
+   |     this error occurs as part of retag at ALLOC[0x4..0x8]
    |
    = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
    = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
@@ -13,14 +13,19 @@ help: <TAG> was created by a Unique retag at offsets [0x4..0x8]
   --> $DIR/return_invalid_mut_option.rs:LL:CC
    |
 LL |     let ret = Some(ret);
-   |                    ^^^
+   |               ^^^^^^^^^
 help: <TAG> was later invalidated at offsets [0x0..0x8] by a read access
   --> $DIR/return_invalid_mut_option.rs:LL:CC
    |
 LL |     let _val = unsafe { *xraw }; // invalidate xref
    |                         ^^^^^
    = note: BACKTRACE:
-   = note: inside `main` at $DIR/return_invalid_mut_option.rs:LL:CC
+   = note: inside `foo` at $DIR/return_invalid_mut_option.rs:LL:CC
+note: inside `main` at $DIR/return_invalid_mut_option.rs:LL:CC
+  --> $DIR/return_invalid_mut_option.rs:LL:CC
+   |
+LL |     match foo(&mut (1, 2)) {
+   |           ^^^^^^^^^^^^^^^^
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
index c94fef90542fdc1d0e9b37df4c6d776df825f17f..8fe7f15cab0c12c2f7b5df8d71fe90e059c6c26b 100644 (file)
@@ -1,12 +1,11 @@
 // Make sure that we cannot return a `&mut` that got already invalidated, not even in a tuple.
-// Due to shallow reborrowing, the error only surfaces when we look into the tuple.
 fn foo(x: &mut (i32, i32)) -> (&mut i32,) {
     let xraw = x as *mut (i32, i32);
     let ret = (unsafe { &mut (*xraw).1 },);
     let _val = unsafe { *xraw }; // invalidate xref
-    ret
+    ret //~ ERROR: /retag .* tag does not exist in the borrow stack/
 }
 
 fn main() {
-    foo(&mut (1, 2)).0; //~ ERROR: /retag .* tag does not exist in the borrow stack/
+    foo(&mut (1, 2)).0;
 }
index 79de9b668cf2b011ca380cf2c0c78c7f558d09ea..9abf43c29f08fb3e44601d09e248eeff7288fe9c 100644 (file)
@@ -1,8 +1,8 @@
 error: Undefined Behavior: trying to retag from <TAG> for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
   --> $DIR/return_invalid_mut_tuple.rs:LL:CC
    |
-LL |     foo(&mut (1, 2)).0;
-   |     ^^^^^^^^^^^^^^^^^^
+LL |     ret
+   |     ^^^
    |     |
    |     trying to retag from <TAG> for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
    |     this error occurs as part of retag at ALLOC[0x4..0x8]
@@ -13,14 +13,19 @@ help: <TAG> was created by a Unique retag at offsets [0x4..0x8]
   --> $DIR/return_invalid_mut_tuple.rs:LL:CC
    |
 LL |     let ret = (unsafe { &mut (*xraw).1 },);
-   |                         ^^^^^^^^^^^^^^
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: <TAG> was later invalidated at offsets [0x0..0x8] by a read access
   --> $DIR/return_invalid_mut_tuple.rs:LL:CC
    |
 LL |     let _val = unsafe { *xraw }; // invalidate xref
    |                         ^^^^^
    = note: BACKTRACE:
-   = note: inside `main` at $DIR/return_invalid_mut_tuple.rs:LL:CC
+   = note: inside `foo` at $DIR/return_invalid_mut_tuple.rs:LL:CC
+note: inside `main` at $DIR/return_invalid_mut_tuple.rs:LL:CC
+  --> $DIR/return_invalid_mut_tuple.rs:LL:CC
+   |
+LL |     foo(&mut (1, 2)).0;
+   |     ^^^^^^^^^^^^^^^^
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
index 3a028ceed86ae508d5b3b4a631460343d99f7201..094ce33b9c1f73c9540a20e66417ed8fcc990f1f 100644 (file)
@@ -1,15 +1,14 @@
 // Make sure that we cannot return a `&` that got already invalidated, not even in an `Option`.
-// Due to shallow reborrowing, the error only surfaces when we look into the `Option`.
 fn foo(x: &mut (i32, i32)) -> Option<&i32> {
     let xraw = x as *mut (i32, i32);
     let ret = Some(unsafe { &(*xraw).1 });
     unsafe { *xraw = (42, 23) }; // unfreeze
-    ret
+    ret //~ ERROR: /retag .* tag does not exist in the borrow stack/
 }
 
 fn main() {
     match foo(&mut (1, 2)) {
-        Some(_x) => {} //~ ERROR: /retag .* tag does not exist in the borrow stack/
+        Some(_x) => {}
         None => {}
     }
 }
index f45456305db293628070394820959e4034f74d5e..6066bf89f5d095806cab091431260eebca461801 100644 (file)
@@ -1,11 +1,11 @@
 error: Undefined Behavior: trying to retag from <TAG> for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
   --> $DIR/return_invalid_shr_option.rs:LL:CC
    |
-LL |         Some(_x) => {}
-   |              ^^
-   |              |
-   |              trying to retag from <TAG> for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
-   |              this error occurs as part of retag at ALLOC[0x4..0x8]
+LL |     ret
+   |     ^^^
+   |     |
+   |     trying to retag from <TAG> for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
+   |     this error occurs as part of retag at ALLOC[0x4..0x8]
    |
    = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
    = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
@@ -13,14 +13,19 @@ help: <TAG> was created by a SharedReadOnly retag at offsets [0x4..0x8]
   --> $DIR/return_invalid_shr_option.rs:LL:CC
    |
 LL |     let ret = Some(unsafe { &(*xraw).1 });
-   |                             ^^^^^^^^^^
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: <TAG> was later invalidated at offsets [0x0..0x8] by a write access
   --> $DIR/return_invalid_shr_option.rs:LL:CC
    |
 LL |     unsafe { *xraw = (42, 23) }; // unfreeze
    |              ^^^^^^^^^^^^^^^^
    = note: BACKTRACE:
-   = note: inside `main` at $DIR/return_invalid_shr_option.rs:LL:CC
+   = note: inside `foo` at $DIR/return_invalid_shr_option.rs:LL:CC
+note: inside `main` at $DIR/return_invalid_shr_option.rs:LL:CC
+  --> $DIR/return_invalid_shr_option.rs:LL:CC
+   |
+LL |     match foo(&mut (1, 2)) {
+   |           ^^^^^^^^^^^^^^^^
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
index e4536626dbf2cc891673162c10877e9bc8a5a773..d0fd53e06aa2624fa88ee8b3f4f85de319e1632c 100644 (file)
@@ -1,12 +1,11 @@
 // Make sure that we cannot return a `&` that got already invalidated, not even in a tuple.
-// Due to shallow reborrowing, the error only surfaces when we look into the tuple.
 fn foo(x: &mut (i32, i32)) -> (&i32,) {
     let xraw = x as *mut (i32, i32);
     let ret = (unsafe { &(*xraw).1 },);
     unsafe { *xraw = (42, 23) }; // unfreeze
-    ret
+    ret //~ ERROR: /retag .* tag does not exist in the borrow stack/
 }
 
 fn main() {
-    foo(&mut (1, 2)).0; //~ ERROR: /retag .* tag does not exist in the borrow stack/
+    foo(&mut (1, 2)).0;
 }
index 2e41f505bb9d27b8f3625e2754be3cd1ca13f8e5..52d365246a74441852bee7c4f2912844c3933159 100644 (file)
@@ -1,8 +1,8 @@
 error: Undefined Behavior: trying to retag from <TAG> for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
   --> $DIR/return_invalid_shr_tuple.rs:LL:CC
    |
-LL |     foo(&mut (1, 2)).0;
-   |     ^^^^^^^^^^^^^^^^^^
+LL |     ret
+   |     ^^^
    |     |
    |     trying to retag from <TAG> for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
    |     this error occurs as part of retag at ALLOC[0x4..0x8]
@@ -13,14 +13,19 @@ help: <TAG> was created by a SharedReadOnly retag at offsets [0x4..0x8]
   --> $DIR/return_invalid_shr_tuple.rs:LL:CC
    |
 LL |     let ret = (unsafe { &(*xraw).1 },);
-   |                         ^^^^^^^^^^
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^
 help: <TAG> was later invalidated at offsets [0x0..0x8] by a write access
   --> $DIR/return_invalid_shr_tuple.rs:LL:CC
    |
 LL |     unsafe { *xraw = (42, 23) }; // unfreeze
    |              ^^^^^^^^^^^^^^^^
    = note: BACKTRACE:
-   = note: inside `main` at $DIR/return_invalid_shr_tuple.rs:LL:CC
+   = note: inside `foo` at $DIR/return_invalid_shr_tuple.rs:LL:CC
+note: inside `main` at $DIR/return_invalid_shr_tuple.rs:LL:CC
+  --> $DIR/return_invalid_shr_tuple.rs:LL:CC
+   |
+LL |     foo(&mut (1, 2)).0;
+   |     ^^^^^^^^^^^^^^^^
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
index b1518a49fbb1b8b6e158d4a081aedf8722498a26..19ea6c130bdd8ceb980076b42b5d45736a4c4a20 100644 (file)
@@ -230,20 +230,8 @@ fn main() {
     check_once();
     park_timeout();
     park_unpark();
-
-    if !cfg!(windows) {
-        // ignore-target-windows: Condvars on Windows are not supported yet
-        check_barriers();
-        check_conditional_variables_notify_one();
-        check_conditional_variables_timed_wait_timeout();
-        check_conditional_variables_timed_wait_notimeout();
-    } else {
-        // We need to fake the same output...
-        for _ in 0..10 {
-            println!("before wait");
-        }
-        for _ in 0..10 {
-            println!("after wait");
-        }
-    }
+    check_barriers();
+    check_conditional_variables_notify_one();
+    check_conditional_variables_timed_wait_timeout();
+    check_conditional_variables_timed_wait_notimeout();
 }
index 55206f4bfc526f008aebf4383a81224ef40ab422..c6cff038f81e0eafa5b993d0d0ab84ddc132f9e4 100644 (file)
@@ -1,4 +1,3 @@
-//@ignore-target-windows: Condvars on Windows are not supported yet.
 // We are making scheduler assumptions here.
 //@compile-flags: -Zmiri-strict-provenance -Zmiri-preemption-rate=0
 
diff --git a/src/tools/miri/tests/pass/concurrency/windows_condvar_shared.rs b/src/tools/miri/tests/pass/concurrency/windows_condvar_shared.rs
new file mode 100644 (file)
index 0000000..d89320b
--- /dev/null
@@ -0,0 +1,227 @@
+//@only-target-windows: Uses win32 api functions
+// We are making scheduler assumptions here.
+//@compile-flags: -Zmiri-preemption-rate=0
+
+use std::ffi::c_void;
+use std::ptr::null_mut;
+use std::thread;
+
+#[derive(Copy, Clone)]
+struct SendPtr<T>(*mut T);
+
+unsafe impl<T> Send for SendPtr<T> {}
+
+extern "system" {
+    fn SleepConditionVariableSRW(
+        condvar: *mut *mut c_void,
+        lock: *mut *mut c_void,
+        timeout: u32,
+        flags: u32,
+    ) -> i32;
+    fn WakeAllConditionVariable(condvar: *mut *mut c_void);
+
+    fn AcquireSRWLockExclusive(lock: *mut *mut c_void);
+    fn AcquireSRWLockShared(lock: *mut *mut c_void);
+    fn ReleaseSRWLockExclusive(lock: *mut *mut c_void);
+    fn ReleaseSRWLockShared(lock: *mut *mut c_void);
+}
+
+const CONDITION_VARIABLE_LOCKMODE_SHARED: u32 = 1;
+const INFINITE: u32 = u32::MAX;
+
+/// threads should be able to reacquire the lock while it is locked by multiple other threads in shared mode
+fn all_shared() {
+    println!("all_shared");
+
+    let mut lock = null_mut();
+    let mut condvar = null_mut();
+
+    let lock_ptr = SendPtr(&mut lock);
+    let condvar_ptr = SendPtr(&mut condvar);
+
+    let mut handles = Vec::with_capacity(10);
+
+    // waiters
+    for i in 0..5 {
+        handles.push(thread::spawn(move || {
+            unsafe {
+                AcquireSRWLockShared(lock_ptr.0);
+            }
+            println!("exclusive waiter {i} locked");
+
+            let r = unsafe {
+                SleepConditionVariableSRW(
+                    condvar_ptr.0,
+                    lock_ptr.0,
+                    INFINITE,
+                    CONDITION_VARIABLE_LOCKMODE_SHARED,
+                )
+            };
+            assert_ne!(r, 0);
+
+            println!("exclusive waiter {i} reacquired lock");
+
+            // unlocking is unnecessary because the lock is never used again
+        }));
+    }
+
+    // ensures each waiter is waiting by this point
+    thread::yield_now();
+
+    // readers
+    for i in 0..5 {
+        handles.push(thread::spawn(move || {
+            unsafe {
+                AcquireSRWLockShared(lock_ptr.0);
+            }
+            println!("reader {i} locked");
+
+            // switch to next reader or main thread
+            thread::yield_now();
+
+            unsafe {
+                ReleaseSRWLockShared(lock_ptr.0);
+            }
+            println!("reader {i} unlocked");
+        }));
+    }
+
+    // ensures each reader has acquired the lock
+    thread::yield_now();
+
+    unsafe {
+        WakeAllConditionVariable(condvar_ptr.0);
+    }
+
+    for handle in handles {
+        handle.join().unwrap();
+    }
+}
+
+// reacquiring a lock should wait until the lock is not exclusively locked
+fn shared_sleep_and_exclusive_lock() {
+    println!("shared_sleep_and_exclusive_lock");
+
+    let mut lock = null_mut();
+    let mut condvar = null_mut();
+
+    let lock_ptr = SendPtr(&mut lock);
+    let condvar_ptr = SendPtr(&mut condvar);
+
+    let mut waiters = Vec::with_capacity(5);
+    for i in 0..5 {
+        waiters.push(thread::spawn(move || {
+            unsafe {
+                AcquireSRWLockShared(lock_ptr.0);
+            }
+            println!("shared waiter {i} locked");
+
+            let r = unsafe {
+                SleepConditionVariableSRW(
+                    condvar_ptr.0,
+                    lock_ptr.0,
+                    INFINITE,
+                    CONDITION_VARIABLE_LOCKMODE_SHARED,
+                )
+            };
+            assert_ne!(r, 0);
+
+            println!("shared waiter {i} reacquired lock");
+
+            // unlocking is unnecessary because the lock is never used again
+        }));
+    }
+
+    // ensures each waiter is waiting by this point
+    thread::yield_now();
+
+    unsafe {
+        AcquireSRWLockExclusive(lock_ptr.0);
+    }
+    println!("main locked");
+
+    unsafe {
+        WakeAllConditionVariable(condvar_ptr.0);
+    }
+
+    // waiters are now waiting for the lock to be unlocked
+    thread::yield_now();
+
+    unsafe {
+        ReleaseSRWLockExclusive(lock_ptr.0);
+    }
+    println!("main unlocked");
+
+    for handle in waiters {
+        handle.join().unwrap();
+    }
+}
+
+// threads reacquiring locks should wait for all locks to be released first
+fn exclusive_sleep_and_shared_lock() {
+    println!("exclusive_sleep_and_shared_lock");
+
+    let mut lock = null_mut();
+    let mut condvar = null_mut();
+
+    let lock_ptr = SendPtr(&mut lock);
+    let condvar_ptr = SendPtr(&mut condvar);
+
+    let mut handles = Vec::with_capacity(10);
+    for i in 0..5 {
+        handles.push(thread::spawn(move || {
+            unsafe {
+                AcquireSRWLockExclusive(lock_ptr.0);
+            }
+
+            println!("exclusive waiter {i} locked");
+
+            let r = unsafe { SleepConditionVariableSRW(condvar_ptr.0, lock_ptr.0, INFINITE, 0) };
+            assert_ne!(r, 0);
+
+            println!("exclusive waiter {i} reacquired lock");
+
+            // switch to next waiter or main thread
+            thread::yield_now();
+
+            unsafe {
+                ReleaseSRWLockExclusive(lock_ptr.0);
+            }
+            println!("exclusive waiter {i} unlocked");
+        }));
+    }
+
+    for i in 0..5 {
+        handles.push(thread::spawn(move || {
+            unsafe {
+                AcquireSRWLockShared(lock_ptr.0);
+            }
+            println!("reader {i} locked");
+
+            // switch to next reader or main thread
+            thread::yield_now();
+
+            unsafe {
+                ReleaseSRWLockShared(lock_ptr.0);
+            }
+            println!("reader {i} unlocked");
+        }));
+    }
+
+    // ensures each reader has acquired the lock
+    thread::yield_now();
+
+    unsafe {
+        WakeAllConditionVariable(condvar_ptr.0);
+    }
+
+    for handle in handles {
+        handle.join().unwrap();
+    }
+}
+
+fn main() {
+    all_shared();
+    shared_sleep_and_exclusive_lock();
+    exclusive_sleep_and_shared_lock();
+}
diff --git a/src/tools/miri/tests/pass/concurrency/windows_condvar_shared.stdout b/src/tools/miri/tests/pass/concurrency/windows_condvar_shared.stdout
new file mode 100644 (file)
index 0000000..918b546
--- /dev/null
@@ -0,0 +1,60 @@
+all_shared
+exclusive waiter 0 locked
+exclusive waiter 1 locked
+exclusive waiter 2 locked
+exclusive waiter 3 locked
+exclusive waiter 4 locked
+reader 0 locked
+reader 1 locked
+reader 2 locked
+reader 3 locked
+reader 4 locked
+exclusive waiter 0 reacquired lock
+exclusive waiter 1 reacquired lock
+exclusive waiter 2 reacquired lock
+exclusive waiter 3 reacquired lock
+exclusive waiter 4 reacquired lock
+reader 0 unlocked
+reader 1 unlocked
+reader 2 unlocked
+reader 3 unlocked
+reader 4 unlocked
+shared_sleep_and_exclusive_lock
+shared waiter 0 locked
+shared waiter 1 locked
+shared waiter 2 locked
+shared waiter 3 locked
+shared waiter 4 locked
+main locked
+main unlocked
+shared waiter 0 reacquired lock
+shared waiter 1 reacquired lock
+shared waiter 2 reacquired lock
+shared waiter 3 reacquired lock
+shared waiter 4 reacquired lock
+exclusive_sleep_and_shared_lock
+exclusive waiter 0 locked
+exclusive waiter 1 locked
+exclusive waiter 2 locked
+exclusive waiter 3 locked
+exclusive waiter 4 locked
+reader 0 locked
+reader 1 locked
+reader 2 locked
+reader 3 locked
+reader 4 locked
+reader 0 unlocked
+reader 1 unlocked
+reader 2 unlocked
+reader 3 unlocked
+reader 4 unlocked
+exclusive waiter 0 reacquired lock
+exclusive waiter 0 unlocked
+exclusive waiter 1 reacquired lock
+exclusive waiter 1 unlocked
+exclusive waiter 2 reacquired lock
+exclusive waiter 2 unlocked
+exclusive waiter 3 reacquired lock
+exclusive waiter 3 unlocked
+exclusive waiter 4 reacquired lock
+exclusive waiter 4 unlocked
index d3c72c3d028cf70e6b4da81aaa88f3a0226e6169..4eb88379620597dd28a36ef8ddfb60571b534a03 100644 (file)
@@ -131,8 +131,46 @@ fn retry_on_fail() {
     waiter2.join().unwrap();
 }
 
+fn no_data_race_after_complete() {
+    let mut init_once = null_mut();
+    let mut pending = 0;
+
+    unsafe {
+        assert_eq!(InitOnceBeginInitialize(&mut init_once, 0, &mut pending, null_mut()), TRUE);
+        assert_eq!(pending, TRUE);
+    }
+
+    let init_once_ptr = SendPtr(&mut init_once);
+
+    let mut place = 0;
+    let place_ptr = SendPtr(&mut place);
+
+    let reader = thread::spawn(move || unsafe {
+        let mut pending = 0;
+
+        // this doesn't block because reader only executes after `InitOnceComplete` is called
+        assert_eq!(InitOnceBeginInitialize(init_once_ptr.0, 0, &mut pending, null_mut()), TRUE);
+        assert_eq!(pending, FALSE);
+        // this should not data race
+        place_ptr.0.read()
+    });
+
+    unsafe {
+        // this should not data race
+        place_ptr.0.write(1);
+    }
+
+    unsafe {
+        assert_eq!(InitOnceComplete(init_once_ptr.0, 0, null_mut()), TRUE);
+    }
+
+    // run reader (without preemption, it has not taken a step yet)
+    assert_eq!(reader.join().unwrap(), 1);
+}
+
 fn main() {
     single_thread();
     block_until_complete();
     retry_on_fail();
+    no_data_race_after_complete();
 }
index 724be9efc9f82e4aebed984864e07b5778902777..0ec1f8e9c693581300e8d0659eba6b63be59a2d5 100644 (file)
@@ -1,5 +1,4 @@
 //@compile-flags: -Coverflow-checks=off
-#![feature(int_log)]
 #![allow(arithmetic_overflow)]
 
 pub fn main() {
index 342269c6acbe3e21d420657cd86e1703fd27b45e..776bc2057f3501fd9d1773b717bce1e426b8407b 100644 (file)
@@ -1,4 +1,3 @@
-//@ignore-target-windows: Condvars on Windows are not supported yet.
 // We are making scheduler assumptions here.
 //@compile-flags: -Zmiri-preemption-rate=0
 
diff --git a/src/tools/miri/tests/pass/stacked-borrows/no_field_retagging.rs b/src/tools/miri/tests/pass/stacked-borrows/no_field_retagging.rs
new file mode 100644 (file)
index 0000000..48fc8e8
--- /dev/null
@@ -0,0 +1,19 @@
+//@compile-flags: -Zmiri-retag-fields=none
+
+struct Newtype<'a>(&'a mut i32);
+
+fn dealloc_while_running(_n: Newtype<'_>, dealloc: impl FnOnce()) {
+    dealloc();
+}
+
+// Make sure that we do *not* retag the fields of `Newtype`.
+fn main() {
+    let ptr = Box::into_raw(Box::new(0i32));
+    #[rustfmt::skip] // I like my newlines
+    unsafe {
+        dealloc_while_running(
+            Newtype(&mut *ptr),
+            || drop(Box::from_raw(ptr)),
+        )
+    };
+}
index 838733078209def1b9a84c17a96a30c1921a520b..296339e73845576ccc72d3c8912ac0984f7fc320 100644 (file)
@@ -1,6 +1,6 @@
 0..1: [ SharedReadWrite<TAG> ]
 0..1: [ SharedReadWrite<TAG> ]
 0..1: [ SharedReadWrite<TAG> ]
-0..1: [ SharedReadWrite<TAG> Unique<TAG> Unique<TAG> Unique<TAG> Unique<TAG> Unique<TAG> ]
-0..1: [ SharedReadWrite<TAG> Disabled<TAG> Disabled<TAG> Disabled<TAG> Disabled<TAG> Disabled<TAG> SharedReadOnly<TAG> ]
+0..1: [ SharedReadWrite<TAG> Unique<TAG> Unique<TAG> Unique<TAG> Unique<TAG> Unique<TAG> Unique<TAG> Unique<TAG> ]
+0..1: [ SharedReadWrite<TAG> Disabled<TAG> Disabled<TAG> Disabled<TAG> Disabled<TAG> Disabled<TAG> Disabled<TAG> Disabled<TAG> SharedReadOnly<TAG> ]
 0..1: [ unknown-bottom(..<TAG>) ]
index ec992da681219add9c0b4174f42981ef8f7f207b..8e7c39e72b68bddf1dd817c524adc4f31bc432db 100644 (file)
@@ -39,6 +39,8 @@ macro_rules! t {
 }
 
 static TEST: AtomicUsize = AtomicUsize::new(0);
+const RETRY_INTERVAL: u64 = 1;
+const NUMBER_OF_RETRIES: usize = 5;
 
 #[derive(Copy, Clone)]
 struct Config {
@@ -115,7 +117,7 @@ fn main() {
     let config = Config::parse_args();
     println!("starting test server");
 
-    let listener = t!(TcpListener::bind(config.bind));
+    let listener = bind_socket(config.bind);
     let (work, tmp): (PathBuf, PathBuf) = if cfg!(target_os = "android") {
         ("/data/local/tmp/work".into(), "/data/local/tmp/work/tmp".into())
     } else {
@@ -159,6 +161,16 @@ fn main() {
     }
 }
 
+fn bind_socket(addr: SocketAddr) -> TcpListener {
+    for _ in 0..(NUMBER_OF_RETRIES - 1) {
+        if let Ok(x) = TcpListener::bind(addr) {
+            return x;
+        }
+        std::thread::sleep(std::time::Duration::from_secs(RETRY_INTERVAL));
+    }
+    TcpListener::bind(addr).unwrap()
+}
+
 fn handle_push(socket: TcpStream, work: &Path, config: Config) {
     let mut reader = BufReader::new(socket);
     let dst = recv(&work, &mut reader);
index a038dce3248aa41fb5ede1be651a3cf7fce1c078..c2e21933c9a6811bcd47a61e2378c88e79a37fb3 100644 (file)
@@ -13,8 +13,7 @@ Forum for questions: https://users.rust-lang.org/c/ide/14
 
 Before submitting, please make sure that you're not running into one of these known issues:
 
- 1. extension doesn't load in VSCodium: #11080
- 2. on-the-fly diagnostics are mostly unimplemented (`cargo check` diagnostics will be shown when saving a file): #3107
+ 1. on-the-fly diagnostics are mostly unimplemented (`cargo check` diagnostics will be shown when saving a file): #3107
 
 Otherwise please try to provide information which will help us to fix the issue faster. Minimal reproducible examples with few dependencies are especially lovely <3.
 -->
index a0b1627d7e2efba51625f4332849c3ee6f02aefb..ad220ff65ca14997564c2d3186beb826fd1482b3 100644 (file)
@@ -2,8 +2,8 @@
 name: Critical Nightly Regression
 about: You are using nightly rust-analyzer and the latest version is unusable.
 title: ''
-labels: ''
-assignees: 'matklad'
+labels: 'Broken Window'
+assignees: ''
 
 ---
 
@@ -14,4 +14,3 @@ Please try to provide information which will help us to fix the issue faster. Mi
 -->
 
 This is a serious regression in nightly and it's important to fix it before the next release.
-@matklad, please take a look.
index 422fe29f9d5c37576060b0698aaa0c6c60aab603..b070dd3406f203877c2528f4e6a8805cb344737b 100644 (file)
@@ -257,8 +257,7 @@ jobs:
       - name: Publish Extension (OpenVSX, release)
         if: github.ref == 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer')
         working-directory: ./editors/code
-        # token from https://dev.azure.com/rust-analyzer/
-        run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix || true
+        run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix
         timeout-minutes: 2
 
       - name: Publish Extension (Code Marketplace, nightly)
@@ -269,5 +268,5 @@ jobs:
       - name: Publish Extension (OpenVSX, nightly)
         if: github.ref != 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer')
         working-directory: ./editors/code
-        run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix || true
+        run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix
         timeout-minutes: 2
index 6636c8a23ca5fea4e31eef52f1d9d86ab0292359..933970d10e47282924e6496cbac5a33a2d17d76d 100644 (file)
@@ -143,9 +143,12 @@ pub(crate) fn print_type_ref(type_ref: &TypeRef, buf: &mut dyn Write) -> fmt::Re
             print_type_ref(elem, buf)?;
             write!(buf, "]")?;
         }
-        TypeRef::Fn(args_and_ret, varargs) => {
+        TypeRef::Fn(args_and_ret, varargs, is_unsafe) => {
             let ((_, return_type), args) =
                 args_and_ret.split_last().expect("TypeRef::Fn is missing return type");
+            if *is_unsafe {
+                write!(buf, "unsafe ")?;
+            }
             write!(buf, "fn(")?;
             for (i, (_, typeref)) in args.iter().enumerate() {
                 if i != 0 {
index 5b4c71be7fb837eb688529d7d6ab976445655979..f8bb78ddcfe02d26b790869308108f7454e6509a 100644 (file)
@@ -119,7 +119,7 @@ pub enum TypeRef {
     Array(Box<TypeRef>, ConstScalarOrPath),
     Slice(Box<TypeRef>),
     /// A fn pointer. Last element of the vector is the return type.
-    Fn(Vec<(Option<Name>, TypeRef)>, bool /*varargs*/),
+    Fn(Vec<(Option<Name>, TypeRef)>, bool /*varargs*/, bool /*is_unsafe*/),
     ImplTrait(Vec<Interned<TypeBound>>),
     DynTrait(Vec<Interned<TypeBound>>),
     Macro(AstId<ast::MacroCall>),
@@ -229,7 +229,7 @@ pub fn from_ast(ctx: &LowerCtx<'_>, node: ast::Type) -> Self {
                     Vec::new()
                 };
                 params.push((None, ret_ty));
-                TypeRef::Fn(params, is_varargs)
+                TypeRef::Fn(params, is_varargs, inner.unsafe_token().is_some())
             }
             // for types are close enough for our purposes to the inner type for now...
             ast::Type::ForType(inner) => TypeRef::from_ast_opt(ctx, inner.ty()),
@@ -263,7 +263,7 @@ pub fn walk(&self, f: &mut impl FnMut(&TypeRef)) {
         fn go(type_ref: &TypeRef, f: &mut impl FnMut(&TypeRef)) {
             f(type_ref);
             match type_ref {
-                TypeRef::Fn(params, _) => {
+                TypeRef::Fn(params, _, _) => {
                     params.iter().for_each(|(_, param_type)| go(param_type, f))
                 }
                 TypeRef::Tuple(types) => types.iter().for_each(|t| go(t, f)),
index 5ad66132635340c410488f425529be1d4397720f..a22a4b170f61c749e68e929368ebb6233060ffd1 100644 (file)
@@ -1187,8 +1187,11 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
                 inner.hir_fmt(f)?;
                 write!(f, "]")?;
             }
-            TypeRef::Fn(parameters, is_varargs) => {
+            &TypeRef::Fn(ref parameters, is_varargs, is_unsafe) => {
                 // FIXME: Function pointer qualifiers.
+                if is_unsafe {
+                    write!(f, "unsafe ")?;
+                }
                 write!(f, "fn(")?;
                 if let Some(((_, return_type), function_parameters)) = parameters.split_last() {
                     for index in 0..function_parameters.len() {
@@ -1203,7 +1206,7 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
                             write!(f, ", ")?;
                         }
                     }
-                    if *is_varargs {
+                    if is_varargs {
                         write!(f, "{}...", if parameters.len() == 1 { "" } else { ", " })?;
                     }
                     write!(f, ")")?;
index 0efff651cc174f91fcdcd5af56d4ab6c10ec07ae..0b3c23f5747adc303cf7b66edf8f5ba3a0c636b0 100644 (file)
@@ -1020,7 +1020,7 @@ fn from_option(ty: Option<Ty>) -> Self {
     /// The primary use case is where the expected type is a fat pointer,
     /// like `&[isize]`. For example, consider the following statement:
     ///
-    ///    let x: &[isize] = &[1, 2, 3];
+    ///     let x: &[isize] = &[1, 2, 3];
     ///
     /// In this case, the expected type for the `&[1, 2, 3]` expression is
     /// `&[isize]`. If however we were to say that `[1, 2, 3]` has the
index f56108b26c45bdaea3096f4616828c28ba260d12..b1f4de826077542ad5b54ceaa1d52fb16b99d992 100644 (file)
@@ -85,6 +85,7 @@ fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
         let ty = match &self.body[tgt_expr] {
             Expr::Missing => self.err_ty(),
             &Expr::If { condition, then_branch, else_branch } => {
+                let expected = &expected.adjust_for_branches(&mut self.table);
                 self.infer_expr(
                     condition,
                     &Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(Interner)),
index 42c3b58d5ada520ba626c22c5ace408f007b2797..b68c764bdca09fa1637bf3c8a9cb37ea1742ee03 100644 (file)
@@ -38,10 +38,12 @@ macro_rules! eprintln {
 use chalk_ir::{
     fold::{Shift, TypeFoldable},
     interner::HasInterner,
-    NoSolution,
+    NoSolution, UniverseIndex,
 };
 use hir_def::{expr::ExprId, type_ref::Rawness, TypeOrConstParamId};
+use hir_expand::name;
 use itertools::Either;
+use traits::FnTrait;
 use utils::Generics;
 
 use crate::{consteval::unknown_const, db::HirDatabase, utils::generics};
@@ -208,6 +210,7 @@ pub(crate) fn make_binders<T: HasInterner<Interner = Interner>>(
 pub struct CallableSig {
     params_and_return: Arc<[Ty]>,
     is_varargs: bool,
+    safety: Safety,
 }
 
 has_interner!(CallableSig);
@@ -216,9 +219,14 @@ pub struct CallableSig {
 pub type PolyFnSig = Binders<CallableSig>;
 
 impl CallableSig {
-    pub fn from_params_and_return(mut params: Vec<Ty>, ret: Ty, is_varargs: bool) -> CallableSig {
+    pub fn from_params_and_return(
+        mut params: Vec<Ty>,
+        ret: Ty,
+        is_varargs: bool,
+        safety: Safety,
+    ) -> CallableSig {
         params.push(ret);
-        CallableSig { params_and_return: params.into(), is_varargs }
+        CallableSig { params_and_return: params.into(), is_varargs, safety }
     }
 
     pub fn from_fn_ptr(fn_ptr: &FnPointer) -> CallableSig {
@@ -235,13 +243,14 @@ pub fn from_fn_ptr(fn_ptr: &FnPointer) -> CallableSig {
                 .map(|arg| arg.assert_ty_ref(Interner).clone())
                 .collect(),
             is_varargs: fn_ptr.sig.variadic,
+            safety: fn_ptr.sig.safety,
         }
     }
 
     pub fn to_fn_ptr(&self) -> FnPointer {
         FnPointer {
             num_binders: 0,
-            sig: FnSig { abi: (), safety: Safety::Safe, variadic: self.is_varargs },
+            sig: FnSig { abi: (), safety: self.safety, variadic: self.is_varargs },
             substitution: FnSubst(Substitution::from_iter(
                 Interner,
                 self.params_and_return.iter().cloned(),
@@ -266,7 +275,11 @@ fn try_fold_with<E>(
     ) -> Result<Self, E> {
         let vec = self.params_and_return.to_vec();
         let folded = vec.try_fold_with(folder, outer_binder)?;
-        Ok(CallableSig { params_and_return: folded.into(), is_varargs: self.is_varargs })
+        Ok(CallableSig {
+            params_and_return: folded.into(),
+            is_varargs: self.is_varargs,
+            safety: self.safety,
+        })
     }
 }
 
@@ -508,3 +521,68 @@ fn try_fold_free_var_lifetime(
     });
     Canonical { value, binders: chalk_ir::CanonicalVarKinds::from_iter(Interner, kinds) }
 }
+
+pub fn callable_sig_from_fnonce(
+    self_ty: &Canonical<Ty>,
+    env: Arc<TraitEnvironment>,
+    db: &dyn HirDatabase,
+) -> Option<CallableSig> {
+    let krate = env.krate;
+    let fn_once_trait = FnTrait::FnOnce.get_id(db, krate)?;
+    let output_assoc_type = db.trait_data(fn_once_trait).associated_type_by_name(&name![Output])?;
+
+    let mut kinds = self_ty.binders.interned().to_vec();
+    let b = TyBuilder::trait_ref(db, fn_once_trait);
+    if b.remaining() != 2 {
+        return None;
+    }
+    let fn_once = b
+        .push(self_ty.value.clone())
+        .fill_with_bound_vars(DebruijnIndex::INNERMOST, kinds.len())
+        .build();
+    kinds.extend(fn_once.substitution.iter(Interner).skip(1).map(|x| {
+        let vk = match x.data(Interner) {
+            chalk_ir::GenericArgData::Ty(_) => {
+                chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)
+            }
+            chalk_ir::GenericArgData::Lifetime(_) => chalk_ir::VariableKind::Lifetime,
+            chalk_ir::GenericArgData::Const(c) => {
+                chalk_ir::VariableKind::Const(c.data(Interner).ty.clone())
+            }
+        };
+        chalk_ir::WithKind::new(vk, UniverseIndex::ROOT)
+    }));
+
+    // FIXME: chalk refuses to solve `<Self as FnOnce<^0.0>>::Output == ^0.1`, so we first solve
+    // `<Self as FnOnce<^0.0>>` and then replace `^0.0` with the concrete argument tuple.
+    let trait_env = env.env.clone();
+    let obligation = InEnvironment { goal: fn_once.cast(Interner), environment: trait_env };
+    let canonical =
+        Canonical { binders: CanonicalVarKinds::from_iter(Interner, kinds), value: obligation };
+    let subst = match db.trait_solve(krate, canonical) {
+        Some(Solution::Unique(vars)) => vars.value.subst,
+        _ => return None,
+    };
+    let args = subst.at(Interner, self_ty.binders.interned().len()).ty(Interner)?;
+    let params = match args.kind(Interner) {
+        chalk_ir::TyKind::Tuple(_, subst) => {
+            subst.iter(Interner).filter_map(|arg| arg.ty(Interner).cloned()).collect::<Vec<_>>()
+        }
+        _ => return None,
+    };
+    if params.iter().any(|ty| ty.is_unknown()) {
+        return None;
+    }
+
+    let fn_once = TyBuilder::trait_ref(db, fn_once_trait)
+        .push(self_ty.value.clone())
+        .push(args.clone())
+        .build();
+    let projection =
+        TyBuilder::assoc_type_projection(db, output_assoc_type, Some(fn_once.substitution.clone()))
+            .build();
+
+    let ret_ty = db.normalize_projection(projection, env);
+
+    Some(CallableSig::from_params_and_return(params, ret_ty.clone(), false, Safety::Safe))
+}
index 22a85cf154587fa79e05807f3196391255b6513e..baf9842d5fbf262101c6171f215456f48e31895e 100644 (file)
@@ -227,13 +227,17 @@ pub fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option<TypeNs>) {
                     .intern(Interner)
             }
             TypeRef::Placeholder => TyKind::Error.intern(Interner),
-            TypeRef::Fn(params, is_varargs) => {
+            &TypeRef::Fn(ref params, variadic, is_unsafe) => {
                 let substs = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
                     Substitution::from_iter(Interner, params.iter().map(|(_, tr)| ctx.lower_ty(tr)))
                 });
                 TyKind::Function(FnPointer {
                     num_binders: 0, // FIXME lower `for<'a> fn()` correctly
-                    sig: FnSig { abi: (), safety: Safety::Safe, variadic: *is_varargs },
+                    sig: FnSig {
+                        abi: (),
+                        safety: if is_unsafe { Safety::Unsafe } else { Safety::Safe },
+                        variadic,
+                    },
                     substitution: FnSubst(substs),
                 })
                 .intern(Interner)
@@ -1573,7 +1577,12 @@ fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
         .with_type_param_mode(ParamLoweringMode::Variable);
     let ret = ctx_ret.lower_ty(&data.ret_type);
     let generics = generics(db.upcast(), def.into());
-    let sig = CallableSig::from_params_and_return(params, ret, data.is_varargs());
+    let sig = CallableSig::from_params_and_return(
+        params,
+        ret,
+        data.is_varargs(),
+        if data.has_unsafe_kw() { Safety::Unsafe } else { Safety::Safe },
+    );
     make_binders(db, &generics, sig)
 }
 
@@ -1617,7 +1626,7 @@ fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnS
         TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
     let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)).collect::<Vec<_>>();
     let (ret, binders) = type_for_adt(db, def.into()).into_value_and_skipped_binders();
-    Binders::new(binders, CallableSig::from_params_and_return(params, ret, false))
+    Binders::new(binders, CallableSig::from_params_and_return(params, ret, false, Safety::Safe))
 }
 
 /// Build the type of a tuple struct constructor.
@@ -1644,7 +1653,7 @@ fn fn_sig_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId)
         TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
     let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)).collect::<Vec<_>>();
     let (ret, binders) = type_for_adt(db, def.parent.into()).into_value_and_skipped_binders();
-    Binders::new(binders, CallableSig::from_params_and_return(params, ret, false))
+    Binders::new(binders, CallableSig::from_params_and_return(params, ret, false, Safety::Safe))
 }
 
 /// Build the type of a tuple enum variant constructor.
index d301595bcd98a5ac3f29fda2bc5626cf8e546a8c..7e3aecc2ae0ae4688d687440390d81b29fc0356d 100644 (file)
@@ -122,6 +122,23 @@ fn test() {
     )
 }
 
+#[test]
+fn if_else_adjust_for_branches_discard_type_var() {
+    check_no_mismatches(
+        r#"
+fn test() {
+    let f = || {
+        if true {
+            &""
+        } else {
+            ""
+        }
+    };
+}
+"#,
+    );
+}
+
 #[test]
 fn match_first_coerce() {
     check_no_mismatches(
@@ -182,6 +199,22 @@ fn test() {
     );
 }
 
+#[test]
+fn match_adjust_for_branches_discard_type_var() {
+    check_no_mismatches(
+        r#"
+fn test() {
+    let f = || {
+        match 0i32 {
+            0i32 => &"",
+            _ => "",
+        }
+    };
+}
+"#,
+    );
+}
+
 #[test]
 fn return_coerce_unknown() {
     check_types(
@@ -357,7 +390,7 @@ fn test() {
     let f: fn(u32) -> isize = foo;
                            // ^^^ adjustments: Pointer(ReifyFnPointer)
     let f: unsafe fn(u32) -> isize = foo;
-                                  // ^^^ adjustments: Pointer(ReifyFnPointer)
+                                  // ^^^ adjustments: Pointer(ReifyFnPointer), Pointer(UnsafeFnPointer)
 }",
     );
 }
@@ -388,7 +421,10 @@ fn coerce_closure_to_fn_ptr() {
     check_no_mismatches(
         r"
 fn test() {
-    let f: fn(u32) -> isize = |x| { 1 };
+    let f: fn(u32) -> u32 = |x| x;
+                         // ^^^^^ adjustments: Pointer(ClosureFnPointer(Safe))
+    let f: unsafe fn(u32) -> u32 = |x| x;
+                                // ^^^^^ adjustments: Pointer(ClosureFnPointer(Unsafe))
 }",
     );
 }
index f5324208c9a4ef12cf6704f1a9066b11c7378b27..cbd9bf32a548655bcb81d5c469a6f4c794328de7 100644 (file)
@@ -2995,7 +2995,17 @@ pub fn as_callable(&self, db: &dyn HirDatabase) -> Option<Callable> {
         let callee = match self.ty.kind(Interner) {
             TyKind::Closure(id, _) => Callee::Closure(*id),
             TyKind::Function(_) => Callee::FnPtr,
-            _ => Callee::Def(self.ty.callable_def(db)?),
+            TyKind::FnDef(..) => Callee::Def(self.ty.callable_def(db)?),
+            _ => {
+                let ty = hir_ty::replace_errors_with_variables(&self.ty);
+                let sig = hir_ty::callable_sig_from_fnonce(&ty, self.env.clone(), db)?;
+                return Some(Callable {
+                    ty: self.clone(),
+                    sig,
+                    callee: Callee::Other,
+                    is_bound_method: false,
+                });
+            }
         };
 
         let sig = self.ty.callable_sig(db)?;
@@ -3464,6 +3474,7 @@ enum Callee {
     Def(CallableDefId),
     Closure(ClosureId),
     FnPtr,
+    Other,
 }
 
 pub enum CallableKind {
@@ -3472,6 +3483,8 @@ pub enum CallableKind {
     TupleEnumVariant(Variant),
     Closure,
     FnPtr,
+    /// Some other type that implements `FnOnce`.
+    Other,
 }
 
 impl Callable {
@@ -3483,6 +3496,7 @@ pub fn kind(&self) -> CallableKind {
             Def(CallableDefId::EnumVariantId(it)) => CallableKind::TupleEnumVariant(it.into()),
             Closure(_) => CallableKind::Closure,
             FnPtr => CallableKind::FnPtr,
+            Other => CallableKind::Other,
         }
     }
     pub fn receiver_param(&self, db: &dyn HirDatabase) -> Option<ast::SelfParam> {
index 60d1588a44e54dba41e753f2511ffd879ac64f73..b273ebc85a50687c8afc65097e8f182a40c935a4 100644 (file)
@@ -14,4 +14,5 @@ pub struct AssistConfig {
     pub allowed: Option<Vec<AssistKind>>,
     pub insert_use: InsertUseConfig,
     pub prefer_no_std: bool,
+    pub assist_emit_must_use: bool,
 }
index bfa9759ec84bea47b1abbe4e9687e93103af8bbc..b5f99726fe1c8a815a5656e07e7dc73b57366b71 100644 (file)
@@ -69,14 +69,14 @@ pub(crate) fn add_explicit_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
     let inferred_type = ty.display_source_code(ctx.db(), module.into()).ok()?;
     acc.add(
         AssistId("add_explicit_type", AssistKind::RefactorRewrite),
-        format!("Insert explicit type `{}`", inferred_type),
+        format!("Insert explicit type `{inferred_type}`"),
         pat_range,
         |builder| match ascribed_ty {
             Some(ascribed_ty) => {
                 builder.replace(ascribed_ty.syntax().text_range(), inferred_type);
             }
             None => {
-                builder.insert(pat_range.end(), format!(": {}", inferred_type));
+                builder.insert(pat_range.end(), format!(": {inferred_type}"));
             }
         },
     )
index f858d7a15c24276fb591c28996e1ea7f3b2f2bbe..89040a8569e63cb200ae5986c59e903e5693313c 100644 (file)
@@ -35,16 +35,16 @@ pub(crate) fn add_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt
             match builder_edit_pos {
                 InsertOrReplace::Insert(insert_pos, needs_whitespace) => {
                     let preceeding_whitespace = if needs_whitespace { " " } else { "" };
-                    builder.insert(insert_pos, &format!("{}-> {} ", preceeding_whitespace, ty))
+                    builder.insert(insert_pos, &format!("{preceeding_whitespace}-> {ty} "))
                 }
                 InsertOrReplace::Replace(text_range) => {
-                    builder.replace(text_range, &format!("-> {}", ty))
+                    builder.replace(text_range, &format!("-> {ty}"))
                 }
             }
             if let FnType::Closure { wrap_expr: true } = fn_type {
                 cov_mark::hit!(wrap_closure_non_block_expr);
                 // `|x| x` becomes `|x| -> T x` which is invalid, so wrap it in a block
-                builder.replace(tail_expr.syntax().text_range(), &format!("{{{}}}", tail_expr));
+                builder.replace(tail_expr.syntax().text_range(), &format!("{{{tail_expr}}}"));
             }
         },
     )
index c0bf238db7317a78756dd3fb97a4f04b573e4637..acf82e4b257943df6e974a934beb6f6f3d454feb 100644 (file)
@@ -93,12 +93,13 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
             builder.trigger_signature_help();
             match ctx.config.snippet_cap {
                 Some(cap) => {
-                    let snip = format!("::<{}>", get_snippet_fish_head(number_of_arguments));
+                    let fish_head = get_snippet_fish_head(number_of_arguments);
+                    let snip = format!("::<{fish_head}>");
                     builder.insert_snippet(cap, ident.text_range().end(), snip)
                 }
                 None => {
                     let fish_head = std::iter::repeat("_").take(number_of_arguments).format(", ");
-                    let snip = format!("::<{}>", fish_head);
+                    let snip = format!("::<{fish_head}>");
                     builder.insert(ident.text_range().end(), snip);
                 }
             }
@@ -109,7 +110,7 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
 /// This will create a snippet string with tabstops marked
 fn get_snippet_fish_head(number_of_arguments: usize) -> String {
     let mut fish_head = (1..number_of_arguments)
-        .format_with("", |i, f| f(&format_args!("${{{}:_}}, ", i)))
+        .format_with("", |i, f| f(&format_args!("${{{i}:_}}, ")))
         .to_string();
 
     // tabstop 0 is a special case and always the last one
index 2853d1d1be3cd57b5935f61bc4899cd2d68d30b3..57cfa17cc8e13ae7fe39b15347416f3d045bf553 100644 (file)
@@ -123,20 +123,20 @@ pub(crate) fn apply_demorgan(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
                     let lhs_range = lhs.syntax().text_range();
                     let not_lhs = invert_boolean_expression(lhs);
 
-                    edit.replace(lhs_range, format!("!({}", not_lhs.syntax().text()));
+                    edit.replace(lhs_range, format!("!({not_lhs}"));
                 }
 
                 if let Some(rhs) = terms.pop_back() {
                     let rhs_range = rhs.syntax().text_range();
                     let not_rhs = invert_boolean_expression(rhs);
 
-                    edit.replace(rhs_range, format!("{})", not_rhs.syntax().text()));
+                    edit.replace(rhs_range, format!("{not_rhs})"));
                 }
 
                 for term in terms {
                     let term_range = term.syntax().text_range();
                     let not_term = invert_boolean_expression(term);
-                    edit.replace(term_range, not_term.syntax().text());
+                    edit.replace(term_range, not_term.to_string());
                 }
             }
         },
index 678dc877d1381c69028953ac882dedc9d606b1e1..a689270bc0915b13a62253c92fbe62623618ab42 100644 (file)
@@ -127,10 +127,12 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
         .sort_by_key(|import| Reverse(relevance_score(ctx, import, current_module.as_ref())));
 
     for import in proposed_imports {
+        let import_path = import.import_path;
+
         acc.add_group(
             &group_label,
             AssistId("auto_import", AssistKind::QuickFix),
-            format!("Import `{}`", import.import_path),
+            format!("Import `{import_path}`"),
             range,
             |builder| {
                 let scope = match scope.clone() {
@@ -138,7 +140,7 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
                     ImportScope::Module(it) => ImportScope::Module(builder.make_mut(it)),
                     ImportScope::Block(it) => ImportScope::Block(builder.make_mut(it)),
                 };
-                insert_use(&scope, mod_path_to_ast(&import.import_path), &ctx.config.insert_use);
+                insert_use(&scope, mod_path_to_ast(&import_path), &ctx.config.insert_use);
             },
         );
     }
index f171dd81a811e7183d70e673e37806fbe813ce87..312cb65abd2a1ce5d7699db05308bbb912c92981 100644 (file)
@@ -54,16 +54,17 @@ fn block_to_line(acc: &mut Assists, comment: ast::Comment) -> Option<()> {
 
             let indent_spaces = indentation.to_string();
             let output = lines
-                .map(|l| l.trim_start_matches(&indent_spaces))
-                .map(|l| {
+                .map(|line| {
+                    let line = line.trim_start_matches(&indent_spaces);
+
                     // Don't introduce trailing whitespace
-                    if l.is_empty() {
+                    if line.is_empty() {
                         line_prefix.to_string()
                     } else {
-                        format!("{} {}", line_prefix, l.trim_start_matches(&indent_spaces))
+                        format!("{line_prefix} {line}")
                     }
                 })
-                .join(&format!("\n{}", indent_spaces));
+                .join(&format!("\n{indent_spaces}"));
 
             edit.replace(target, output)
         },
@@ -96,7 +97,7 @@ fn line_to_block(acc: &mut Assists, comment: ast::Comment) -> Option<()> {
             let block_prefix =
                 CommentKind { shape: CommentShape::Block, ..comment.kind() }.prefix();
 
-            let output = format!("{}\n{}\n{}*/", block_prefix, block_comment_body, indentation);
+            let output = format!("{block_prefix}\n{block_comment_body}\n{indentation}*/");
 
             edit.replace(target, output)
         },
index 9060696cdc8e9c76fd26cd5c7eda993d0ebb15d6..ff2195f7e6c4a2ebf6829889b3336eb52570c779 100644 (file)
@@ -32,19 +32,19 @@ pub(crate) fn convert_integer_literal(acc: &mut Assists, ctx: &AssistContext<'_>
         }
 
         let mut converted = match target_radix {
-            Radix::Binary => format!("0b{:b}", value),
-            Radix::Octal => format!("0o{:o}", value),
+            Radix::Binary => format!("0b{value:b}"),
+            Radix::Octal => format!("0o{value:o}"),
             Radix::Decimal => value.to_string(),
-            Radix::Hexadecimal => format!("0x{:X}", value),
+            Radix::Hexadecimal => format!("0x{value:X}"),
         };
 
-        let label = format!("Convert {} to {}{}", literal, converted, suffix.unwrap_or_default());
-
         // Appends the type suffix back into the new literal if it exists.
         if let Some(suffix) = suffix {
             converted.push_str(suffix);
         }
 
+        let label = format!("Convert {literal} to {converted}");
+
         acc.add_group(
             &group_id,
             AssistId("convert_integer_literal", AssistKind::RefactorInline),
index 95d11abe8bc0f6fea075297b0c1473e81ec7a77b..872b52c98fff2fbf5a3e56d1c27165eb2bdb61f9 100644 (file)
@@ -86,9 +86,9 @@ pub(crate) fn convert_into_to_from(acc: &mut Assists, ctx: &AssistContext<'_>) -
         impl_.syntax().text_range(),
         |builder| {
             builder.replace(src_type.syntax().text_range(), dest_type.to_string());
-            builder.replace(ast_trait.syntax().text_range(), format!("From<{}>", src_type));
+            builder.replace(ast_trait.syntax().text_range(), format!("From<{src_type}>"));
             builder.replace(into_fn_return.syntax().text_range(), "-> Self");
-            builder.replace(into_fn_params.syntax().text_range(), format!("(val: {})", src_type));
+            builder.replace(into_fn_params.syntax().text_range(), format!("(val: {src_type})"));
             builder.replace(into_fn_name.syntax().text_range(), "from");
 
             for s in selfs {
index 2cf370c090743da3730e37a47fa9785496c6343e..80eecf4a09868980f94d68b7ed8854674bcd2eee 100644 (file)
@@ -119,19 +119,19 @@ pub(crate) fn convert_for_loop_with_for_each(
             {
                 // We have either "for x in &col" and col implements a method called iter
                 //             or "for x in &mut col" and col implements a method called iter_mut
-                format_to!(buf, "{}.{}()", expr_behind_ref, method);
+                format_to!(buf, "{expr_behind_ref}.{method}()");
             } else if let ast::Expr::RangeExpr(..) = iterable {
                 // range expressions need to be parenthesized for the syntax to be correct
-                format_to!(buf, "({})", iterable);
+                format_to!(buf, "({iterable})");
             } else if impls_core_iter(&ctx.sema, &iterable) {
-                format_to!(buf, "{}", iterable);
+                format_to!(buf, "{iterable}");
             } else if let ast::Expr::RefExpr(_) = iterable {
-                format_to!(buf, "({}).into_iter()", iterable);
+                format_to!(buf, "({iterable}).into_iter()");
             } else {
-                format_to!(buf, "{}.into_iter()", iterable);
+                format_to!(buf, "{iterable}.into_iter()");
             }
 
-            format_to!(buf, ".for_each(|{}| {});", pat, body);
+            format_to!(buf, ".for_each(|{pat}| {body});");
 
             builder.replace(for_loop.syntax().text_range(), buf)
         },
index 00095de257d5ab19922c22df209b76b763281a8c..c82a3b53032595217e7f7b69f12557829c644574 100644 (file)
@@ -80,7 +80,7 @@ fn binders_to_str(binders: &[(Name, bool)], addmut: bool) -> String {
         .map(
             |(ident, ismut)| {
                 if *ismut && addmut {
-                    format!("mut {}", ident)
+                    format!("mut {ident}")
                 } else {
                     ident.to_string()
                 }
@@ -93,7 +93,7 @@ fn binders_to_str(binders: &[(Name, bool)], addmut: bool) -> String {
     } else if binders.len() == 1 {
         vars
     } else {
-        format!("({})", vars)
+        format!("({vars})")
     }
 }
 
@@ -153,7 +153,7 @@ pub(crate) fn convert_let_else_to_match(acc: &mut Assists, ctx: &AssistContext<'
 
             let only_expr = let_else_block.statements().next().is_none();
             let branch2 = match &let_else_block.tail_expr() {
-                Some(tail) if only_expr => format!("{},", tail.syntax().text()),
+                Some(tail) if only_expr => format!("{tail},"),
                 _ => let_else_block.syntax().text().to_string(),
             };
             let replace = if binders.is_empty() {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_match_to_let_else.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_match_to_let_else.rs
new file mode 100644 (file)
index 0000000..5bf04a3
--- /dev/null
@@ -0,0 +1,413 @@
+use ide_db::defs::{Definition, NameRefClass};
+use syntax::{
+    ast::{self, HasName},
+    ted, AstNode, SyntaxNode,
+};
+
+use crate::{
+    assist_context::{AssistContext, Assists},
+    AssistId, AssistKind,
+};
+
+// Assist: convert_match_to_let_else
+//
+// Converts let statement with match initializer to let-else statement.
+//
+// ```
+// # //- minicore: option
+// fn foo(opt: Option<()>) {
+//     let val = $0match opt {
+//         Some(it) => it,
+//         None => return,
+//     };
+// }
+// ```
+// ->
+// ```
+// fn foo(opt: Option<()>) {
+//     let Some(val) = opt else { return };
+// }
+// ```
+pub(crate) fn convert_match_to_let_else(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
+    let let_stmt: ast::LetStmt = ctx.find_node_at_offset()?;
+    let binding = find_binding(let_stmt.pat()?)?;
+
+    let initializer = match let_stmt.initializer() {
+        Some(ast::Expr::MatchExpr(it)) => it,
+        _ => return None,
+    };
+    let initializer_expr = initializer.expr()?;
+
+    let (extracting_arm, diverging_arm) = match find_arms(ctx, &initializer) {
+        Some(it) => it,
+        None => return None,
+    };
+    if extracting_arm.guard().is_some() {
+        cov_mark::hit!(extracting_arm_has_guard);
+        return None;
+    }
+
+    let diverging_arm_expr = diverging_arm.expr()?;
+    let extracting_arm_pat = extracting_arm.pat()?;
+    let extracted_variable = find_extracted_variable(ctx, &extracting_arm)?;
+
+    acc.add(
+        AssistId("convert_match_to_let_else", AssistKind::RefactorRewrite),
+        "Convert match to let-else",
+        let_stmt.syntax().text_range(),
+        |builder| {
+            let extracting_arm_pat = rename_variable(&extracting_arm_pat, extracted_variable, binding);
+            builder.replace(
+                let_stmt.syntax().text_range(),
+                format!("let {extracting_arm_pat} = {initializer_expr} else {{ {diverging_arm_expr} }};")
+            )
+        },
+    )
+}
+
+// Given a pattern, find the name introduced to the surrounding scope.
+fn find_binding(pat: ast::Pat) -> Option<ast::IdentPat> {
+    if let ast::Pat::IdentPat(ident) = pat {
+        Some(ident)
+    } else {
+        None
+    }
+}
+
+// Given a match expression, find extracting and diverging arms.
+fn find_arms(
+    ctx: &AssistContext<'_>,
+    match_expr: &ast::MatchExpr,
+) -> Option<(ast::MatchArm, ast::MatchArm)> {
+    let arms = match_expr.match_arm_list()?.arms().collect::<Vec<_>>();
+    if arms.len() != 2 {
+        return None;
+    }
+
+    let mut extracting = None;
+    let mut diverging = None;
+    for arm in arms {
+        if ctx.sema.type_of_expr(&arm.expr().unwrap()).unwrap().original().is_never() {
+            diverging = Some(arm);
+        } else {
+            extracting = Some(arm);
+        }
+    }
+
+    match (extracting, diverging) {
+        (Some(extracting), Some(diverging)) => Some((extracting, diverging)),
+        _ => {
+            cov_mark::hit!(non_diverging_match);
+            None
+        }
+    }
+}
+
+// Given an extracting arm, find the extracted variable.
+fn find_extracted_variable(ctx: &AssistContext<'_>, arm: &ast::MatchArm) -> Option<ast::Name> {
+    match arm.expr()? {
+        ast::Expr::PathExpr(path) => {
+            let name_ref = path.syntax().descendants().find_map(ast::NameRef::cast)?;
+            match NameRefClass::classify(&ctx.sema, &name_ref)? {
+                NameRefClass::Definition(Definition::Local(local)) => {
+                    let source = local.source(ctx.db()).value.left()?;
+                    Some(source.name()?)
+                }
+                _ => None,
+            }
+        }
+        _ => {
+            cov_mark::hit!(extracting_arm_is_not_an_identity_expr);
+            return None;
+        }
+    }
+}
+
+// Rename `extracted` with `binding` in `pat`.
+fn rename_variable(pat: &ast::Pat, extracted: ast::Name, binding: ast::IdentPat) -> SyntaxNode {
+    let syntax = pat.syntax().clone_for_update();
+    let extracted_syntax = syntax.covering_element(extracted.syntax().text_range());
+
+    // If `extracted` variable is a record field, we should rename it to `binding`,
+    // otherwise we just need to replace `extracted` with `binding`.
+
+    if let Some(record_pat_field) = extracted_syntax.ancestors().find_map(ast::RecordPatField::cast)
+    {
+        if let Some(name_ref) = record_pat_field.field_name() {
+            ted::replace(
+                record_pat_field.syntax(),
+                ast::make::record_pat_field(ast::make::name_ref(&name_ref.text()), binding.into())
+                    .syntax()
+                    .clone_for_update(),
+            );
+        }
+    } else {
+        ted::replace(extracted_syntax, binding.syntax().clone_for_update());
+    }
+
+    syntax
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::tests::{check_assist, check_assist_not_applicable};
+
+    use super::*;
+
+    #[test]
+    fn should_not_be_applicable_for_non_diverging_match() {
+        cov_mark::check!(non_diverging_match);
+        check_assist_not_applicable(
+            convert_match_to_let_else,
+            r#"
+//- minicore: option
+fn foo(opt: Option<()>) {
+    let val = $0match opt {
+        Some(it) => it,
+        None => (),
+    };
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn should_not_be_applicable_if_extracting_arm_is_not_an_identity_expr() {
+        cov_mark::check_count!(extracting_arm_is_not_an_identity_expr, 2);
+        check_assist_not_applicable(
+            convert_match_to_let_else,
+            r#"
+//- minicore: option
+fn foo(opt: Option<i32>) {
+    let val = $0match opt {
+        Some(it) => it + 1,
+        None => return,
+    };
+}
+"#,
+        );
+
+        check_assist_not_applicable(
+            convert_match_to_let_else,
+            r#"
+//- minicore: option
+fn foo(opt: Option<()>) {
+    let val = $0match opt {
+        Some(it) => {
+            let _ = 1 + 1;
+            it
+        },
+        None => return,
+    };
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn should_not_be_applicable_if_extracting_arm_has_guard() {
+        cov_mark::check!(extracting_arm_has_guard);
+        check_assist_not_applicable(
+            convert_match_to_let_else,
+            r#"
+//- minicore: option
+fn foo(opt: Option<()>) {
+    let val = $0match opt {
+        Some(it) if 2 > 1 => it,
+        None => return,
+    };
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn basic_pattern() {
+        check_assist(
+            convert_match_to_let_else,
+            r#"
+//- minicore: option
+fn foo(opt: Option<()>) {
+    let val = $0match opt {
+        Some(it) => it,
+        None => return,
+    };
+}
+    "#,
+            r#"
+fn foo(opt: Option<()>) {
+    let Some(val) = opt else { return };
+}
+    "#,
+        );
+    }
+
+    #[test]
+    fn keeps_modifiers() {
+        check_assist(
+            convert_match_to_let_else,
+            r#"
+//- minicore: option
+fn foo(opt: Option<()>) {
+    let ref mut val = $0match opt {
+        Some(it) => it,
+        None => return,
+    };
+}
+    "#,
+            r#"
+fn foo(opt: Option<()>) {
+    let Some(ref mut val) = opt else { return };
+}
+    "#,
+        );
+    }
+
+    #[test]
+    fn nested_pattern() {
+        check_assist(
+            convert_match_to_let_else,
+            r#"
+//- minicore: option, result
+fn foo(opt: Option<Result<()>>) {
+    let val = $0match opt {
+        Some(Ok(it)) => it,
+        _ => return,
+    };
+}
+    "#,
+            r#"
+fn foo(opt: Option<Result<()>>) {
+    let Some(Ok(val)) = opt else { return };
+}
+    "#,
+        );
+    }
+
+    #[test]
+    fn works_with_any_diverging_block() {
+        check_assist(
+            convert_match_to_let_else,
+            r#"
+//- minicore: option
+fn foo(opt: Option<()>) {
+    loop {
+        let val = $0match opt {
+            Some(it) => it,
+            None => break,
+        };
+    }
+}
+    "#,
+            r#"
+fn foo(opt: Option<()>) {
+    loop {
+        let Some(val) = opt else { break };
+    }
+}
+    "#,
+        );
+
+        check_assist(
+            convert_match_to_let_else,
+            r#"
+//- minicore: option
+fn foo(opt: Option<()>) {
+    loop {
+        let val = $0match opt {
+            Some(it) => it,
+            None => continue,
+        };
+    }
+}
+    "#,
+            r#"
+fn foo(opt: Option<()>) {
+    loop {
+        let Some(val) = opt else { continue };
+    }
+}
+    "#,
+        );
+
+        check_assist(
+            convert_match_to_let_else,
+            r#"
+//- minicore: option
+fn panic() -> ! {}
+
+fn foo(opt: Option<()>) {
+    loop {
+        let val = $0match opt {
+            Some(it) => it,
+            None => panic(),
+        };
+    }
+}
+    "#,
+            r#"
+fn panic() -> ! {}
+
+fn foo(opt: Option<()>) {
+    loop {
+        let Some(val) = opt else { panic() };
+    }
+}
+    "#,
+        );
+    }
+
+    #[test]
+    fn struct_pattern() {
+        check_assist(
+            convert_match_to_let_else,
+            r#"
+//- minicore: option
+struct Point {
+    x: i32,
+    y: i32,
+}
+
+fn foo(opt: Option<Point>) {
+    let val = $0match opt {
+        Some(Point { x: 0, y }) => y,
+        _ => return,
+    };
+}
+    "#,
+            r#"
+struct Point {
+    x: i32,
+    y: i32,
+}
+
+fn foo(opt: Option<Point>) {
+    let Some(Point { x: 0, y: val }) = opt else { return };
+}
+    "#,
+        );
+    }
+
+    #[test]
+    fn renames_whole_binding() {
+        check_assist(
+            convert_match_to_let_else,
+            r#"
+//- minicore: option
+fn foo(opt: Option<i32>) -> Option<i32> {
+    let val = $0match opt {
+        it @ Some(42) => it,
+        _ => return None,
+    };
+    val
+}
+    "#,
+            r#"
+fn foo(opt: Option<i32>) -> Option<i32> {
+    let val @ Some(42) = opt else { return None };
+    val
+}
+    "#,
+        );
+    }
+}
index cb75619ced9c31f46bf0c2a92adfc3902870e67f..b97be34c5f7e48324ff86a7c701dad8d6d96de38 100644 (file)
@@ -129,32 +129,15 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext<'
                 }
                 Some((path, bound_ident)) => {
                     // If-let.
-                    let match_expr = {
-                        let happy_arm = {
-                            let pat = make::tuple_struct_pat(
-                                path,
-                                once(make::ext::simple_ident_pat(make::name("it")).into()),
-                            );
-                            let expr = {
-                                let path = make::ext::ident_path("it");
-                                make::expr_path(path)
-                            };
-                            make::match_arm(once(pat.into()), None, expr)
-                        };
-
-                        let sad_arm = make::match_arm(
-                            // FIXME: would be cool to use `None` or `Err(_)` if appropriate
-                            once(make::wildcard_pat().into()),
-                            None,
-                            early_expression,
-                        );
-
-                        make::expr_match(cond_expr, make::match_arm_list(vec![happy_arm, sad_arm]))
-                    };
-
-                    let let_stmt = make::let_stmt(bound_ident, None, Some(match_expr));
-                    let let_stmt = let_stmt.indent(if_indent_level);
-                    let_stmt.syntax().clone_for_update()
+                    let pat = make::tuple_struct_pat(path, once(bound_ident));
+                    let let_else_stmt = make::let_else_stmt(
+                        pat.into(),
+                        None,
+                        cond_expr,
+                        ast::make::tail_only_block_expr(early_expression),
+                    );
+                    let let_else_stmt = let_else_stmt.indent(if_indent_level);
+                    let_else_stmt.syntax().clone_for_update()
                 }
             };
 
@@ -238,10 +221,7 @@ fn main(n: Option<String>) {
             r#"
 fn main(n: Option<String>) {
     bar();
-    let n = match n {
-        Some(it) => it,
-        _ => return,
-    };
+    let Some(n) = n else { return };
     foo(n);
 
     // comment
@@ -264,10 +244,7 @@ fn main() {
 "#,
             r#"
 fn main() {
-    let x = match Err(92) {
-        Ok(it) => it,
-        _ => return,
-    };
+    let Ok(x) = Err(92) else { return };
     foo(x);
 }
 "#,
@@ -292,10 +269,7 @@ fn main(n: Option<String>) {
             r#"
 fn main(n: Option<String>) {
     bar();
-    let n = match n {
-        Some(it) => it,
-        _ => return,
-    };
+    let Some(n) = n else { return };
     foo(n);
 
     // comment
@@ -323,10 +297,7 @@ fn main(n: Option<String>) {
             r#"
 fn main(n: Option<String>) {
     bar();
-    let mut n = match n {
-        Some(it) => it,
-        _ => return,
-    };
+    let Some(mut n) = n else { return };
     foo(n);
 
     // comment
@@ -354,10 +325,7 @@ fn main(n: Option<&str>) {
             r#"
 fn main(n: Option<&str>) {
     bar();
-    let ref n = match n {
-        Some(it) => it,
-        _ => return,
-    };
+    let Some(ref n) = n else { return };
     foo(n);
 
     // comment
@@ -412,10 +380,7 @@ fn main() {
             r#"
 fn main() {
     while true {
-        let n = match n {
-            Some(it) => it,
-            _ => continue,
-        };
+        let Some(n) = n else { continue };
         foo(n);
         bar();
     }
@@ -469,10 +434,7 @@ fn main() {
             r#"
 fn main() {
     loop {
-        let n = match n {
-            Some(it) => it,
-            _ => continue,
-        };
+        let Some(n) = n else { continue };
         foo(n);
         bar();
     }
index d8f522708460e06622d63ae8b6bcb9d92775c7b5..92e091fca126c9ac3bbfe8da5a8de017f326fec8 100644 (file)
@@ -226,7 +226,13 @@ fn edit_field_references(
 }
 
 fn generate_names(fields: impl Iterator<Item = ast::TupleField>) -> Vec<ast::Name> {
-    fields.enumerate().map(|(i, _)| ast::make::name(&format!("field{}", i + 1))).collect()
+    fields
+        .enumerate()
+        .map(|(i, _)| {
+            let idx = i + 1;
+            ast::make::name(&format!("field{idx}"))
+        })
+        .collect()
 }
 
 #[cfg(test)]
index 54a7f480a4e46abd5316a3cc719e8c54ede8a69f..b1b0f587cd33d0edc338f93c7cdfcb66d0a7b61c 100644 (file)
@@ -58,16 +58,16 @@ pub(crate) fn convert_two_arm_bool_match_to_matches_macro(
         target_range,
         |builder| {
             let mut arm_str = String::new();
-            if let Some(ref pat) = first_arm.pat() {
+            if let Some(pat) = &first_arm.pat() {
                 arm_str += &pat.to_string();
             }
-            if let Some(ref guard) = first_arm.guard() {
-                arm_str += &format!(" {}", &guard.to_string());
+            if let Some(guard) = &first_arm.guard() {
+                arm_str += &format!(" {guard}");
             }
             if invert_matches {
-                builder.replace(target_range, format!("!matches!({}, {})", expr, arm_str));
+                builder.replace(target_range, format!("!matches!({expr}, {arm_str})"));
             } else {
-                builder.replace(target_range, format!("matches!({}, {})", expr, arm_str));
+                builder.replace(target_range, format!("matches!({expr}, {arm_str})"));
             }
         },
     )
index dc581ff3bd2c7a85adcfcd4451c8b8a0ed20af57..31c2ce7c1b54ae93a6e16bbf4d34243b1e07d6f6 100644 (file)
@@ -133,7 +133,7 @@ fn generate_name(
     _usages: &Option<UsageSearchResult>,
 ) -> String {
     // FIXME: detect if name already used
-    format!("_{}", index)
+    format!("_{index}")
 }
 
 enum RefType {
@@ -168,12 +168,12 @@ fn edit_tuple_assignment(
     let add_cursor = |text: &str| {
         // place cursor on first tuple item
         let first_tuple = &data.field_names[0];
-        text.replacen(first_tuple, &format!("$0{}", first_tuple), 1)
+        text.replacen(first_tuple, &format!("$0{first_tuple}"), 1)
     };
 
     // with sub_pattern: keep original tuple and add subpattern: `tup @ (_0, _1)`
     if in_sub_pattern {
-        let text = format!(" @ {}", tuple_pat);
+        let text = format!(" @ {tuple_pat}");
         match ctx.config.snippet_cap {
             Some(cap) => {
                 let snip = add_cursor(&text);
@@ -314,9 +314,9 @@ struct RefData {
 impl RefData {
     fn format(&self, field_name: &str) -> String {
         match (self.needs_deref, self.needs_parentheses) {
-            (true, true) => format!("(*{})", field_name),
-            (true, false) => format!("*{}", field_name),
-            (false, true) => format!("({})", field_name),
+            (true, true) => format!("(*{field_name})"),
+            (true, false) => format!("*{field_name}"),
+            (false, true) => format!("({field_name})"),
             (false, false) => field_name.to_string(),
         }
     }
index d6c8ea785f84aa87f1b2904e06ddcdab103eafc1..0605883584922ee329ff9fcc879561a18b7a7c98 100644 (file)
@@ -181,7 +181,7 @@ fn make_function_name(semantics_scope: &hir::SemanticsScope<'_>) -> ast::NameRef
     let mut counter = 0;
     while names_in_scope.contains(&name) {
         counter += 1;
-        name = format!("{}{}", &default_name, counter)
+        name = format!("{default_name}{counter}")
     }
     make::name_ref(&name)
 }
@@ -1291,19 +1291,23 @@ fn make_call(ctx: &AssistContext<'_>, fun: &Function, indent: IndentLevel) -> St
     match fun.outliving_locals.as_slice() {
         [] => {}
         [var] => {
-            format_to!(buf, "let {}{} = ", mut_modifier(var), var.local.name(ctx.db()))
+            let modifier = mut_modifier(var);
+            let name = var.local.name(ctx.db());
+            format_to!(buf, "let {modifier}{name} = ")
         }
         vars => {
             buf.push_str("let (");
             let bindings = vars.iter().format_with(", ", |local, f| {
-                f(&format_args!("{}{}", mut_modifier(local), local.local.name(ctx.db())))
+                let modifier = mut_modifier(local);
+                let name = local.local.name(ctx.db());
+                f(&format_args!("{modifier}{name}"))
             });
-            format_to!(buf, "{}", bindings);
+            format_to!(buf, "{bindings}");
             buf.push_str(") = ");
         }
     }
 
-    format_to!(buf, "{}", expr);
+    format_to!(buf, "{expr}");
     let insert_comma = fun
         .body
         .parent()
@@ -1447,6 +1451,8 @@ fn format_function(
     new_indent: IndentLevel,
 ) -> String {
     let mut fn_def = String::new();
+
+    let fun_name = &fun.name;
     let params = fun.make_param_list(ctx, module);
     let ret_ty = fun.make_ret_ty(ctx, module);
     let body = make_body(ctx, old_indent, new_indent, fun);
@@ -1454,42 +1460,28 @@ fn format_function(
     let async_kw = if fun.control_flow.is_async { "async " } else { "" };
     let unsafe_kw = if fun.control_flow.is_unsafe { "unsafe " } else { "" };
     let (generic_params, where_clause) = make_generic_params_and_where_clause(ctx, fun);
+
+    format_to!(fn_def, "\n\n{new_indent}{const_kw}{async_kw}{unsafe_kw}");
     match ctx.config.snippet_cap {
-        Some(_) => format_to!(
-            fn_def,
-            "\n\n{}{}{}{}fn $0{}",
-            new_indent,
-            const_kw,
-            async_kw,
-            unsafe_kw,
-            fun.name,
-        ),
-        None => format_to!(
-            fn_def,
-            "\n\n{}{}{}{}fn {}",
-            new_indent,
-            const_kw,
-            async_kw,
-            unsafe_kw,
-            fun.name,
-        ),
+        Some(_) => format_to!(fn_def, "fn $0{fun_name}"),
+        None => format_to!(fn_def, "fn {fun_name}"),
     }
 
     if let Some(generic_params) = generic_params {
-        format_to!(fn_def, "{}", generic_params);
+        format_to!(fn_def, "{generic_params}");
     }
 
-    format_to!(fn_def, "{}", params);
+    format_to!(fn_def, "{params}");
 
     if let Some(ret_ty) = ret_ty {
-        format_to!(fn_def, " {}", ret_ty);
+        format_to!(fn_def, " {ret_ty}");
     }
 
     if let Some(where_clause) = where_clause {
-        format_to!(fn_def, " {}", where_clause);
+        format_to!(fn_def, " {where_clause}");
     }
 
-    format_to!(fn_def, " {}", body);
+    format_to!(fn_def, " {body}");
 
     fn_def
 }
index 897980c6650497132360baa4833ee68bcb5858a1..56834394aebaa8fbe7a125dc647280aa58920628 100644 (file)
@@ -127,7 +127,7 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
             for item in items_to_be_processed {
                 let item = item.indent(IndentLevel(1));
                 let mut indented_item = String::new();
-                format_to!(indented_item, "{}{}", new_item_indent, item.to_string());
+                format_to!(indented_item, "{new_item_indent}{item}");
                 body_items.push(indented_item);
             }
 
@@ -137,30 +137,28 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
                 let mut impl_body_def = String::new();
 
                 if let Some(self_ty) = impl_.self_ty() {
-                    format_to!(
-                        impl_body_def,
-                        "{}impl {} {{\n{}\n{}}}",
-                        old_item_indent + 1,
-                        self_ty.to_string(),
-                        body,
-                        old_item_indent + 1
-                    );
-
+                    {
+                        let impl_indent = old_item_indent + 1;
+                        format_to!(
+                            impl_body_def,
+                            "{impl_indent}impl {self_ty} {{\n{body}\n{impl_indent}}}",
+                        );
+                    }
                     body = impl_body_def;
 
                     // Add the import for enum/struct corresponding to given impl block
                     module.make_use_stmt_of_node_with_super(self_ty.syntax());
                     for item in module.use_items {
-                        let mut indented_item = String::new();
-                        format_to!(indented_item, "{}{}", old_item_indent + 1, item.to_string());
-                        body = format!("{}\n\n{}", indented_item, body);
+                        let item_indent = old_item_indent + 1;
+                        body = format!("{item_indent}{item}\n\n{body}");
                     }
                 }
             }
 
             let mut module_def = String::new();
 
-            format_to!(module_def, "mod {} {{\n{}\n{}}}", module.name, body, old_item_indent);
+            let module_name = module.name;
+            format_to!(module_def, "mod {module_name} {{\n{body}\n{old_item_indent}}}");
 
             let mut usages_to_be_updated_for_curr_file = vec![];
             for usages_to_be_updated_for_file in usages_to_be_processed {
@@ -199,7 +197,7 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
                     builder.delete(range);
                 }
 
-                builder.insert(impl_.syntax().text_range().end(), format!("\n\n{}", module_def));
+                builder.insert(impl_.syntax().text_range().end(), format!("\n\n{module_def}"));
             } else {
                 builder.replace(module.text_range, module_def)
             }
@@ -343,9 +341,10 @@ fn get_usage_to_be_processed(
                 && !self.text_range.contains_range(desc.text_range())
             {
                 if let Some(name_ref) = ast::NameRef::cast(desc) {
+                    let mod_name = self.name;
                     return Some((
                         name_ref.syntax().text_range(),
-                        format!("{}::{}", self.name, name_ref),
+                        format!("{mod_name}::{name_ref}"),
                     ));
                 }
             }
index 970e948dfd930f4226be3c9697f0e19dead8d044..b4e10667b07abe4a4bf196973bdcadd98018fe92 100644 (file)
@@ -296,10 +296,14 @@ fn create_struct_def(
 
 fn update_variant(variant: &ast::Variant, generics: Option<ast::GenericParamList>) -> Option<()> {
     let name = variant.name()?;
-    let ty = generics
+    let generic_args = generics
         .filter(|generics| generics.generic_params().count() > 0)
-        .map(|generics| make::ty(&format!("{}{}", &name.text(), generics.to_generic_args())))
-        .unwrap_or_else(|| make::ty(&name.text()));
+        .map(|generics| generics.to_generic_args());
+    // FIXME: replace with a `ast::make` constructor
+    let ty = match generic_args {
+        Some(generic_args) => make::ty(&format!("{name}{generic_args}")),
+        None => make::ty(&name.text()),
+    };
 
     // change from a record to a tuple field list
     let tuple_field = make::tuple_field(None, ty);
index 03aa8601d14e1ef3e34207da916dd4574d175bbf..3116935fc5e7590c81b86632cc0ba618fc9b4ea1 100644 (file)
@@ -1,8 +1,7 @@
 use either::Either;
 use ide_db::syntax_helpers::node_ext::walk_ty;
-use itertools::Itertools;
 use syntax::{
-    ast::{self, edit::IndentLevel, AstNode, HasGenericParams, HasName},
+    ast::{self, edit::IndentLevel, make, AstNode, HasGenericParams, HasName},
     match_ast,
 };
 
@@ -64,41 +63,29 @@ pub(crate) fn extract_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) ->
                 known_generics.extend(it.generic_params());
             }
             let generics = collect_used_generics(&ty, &known_generics);
+            let generic_params =
+                generics.map(|it| make::generic_param_list(it.into_iter().cloned()));
 
-            let replacement = if !generics.is_empty() {
-                format!(
-                    "Type<{}>",
-                    generics.iter().format_with(", ", |generic, f| {
-                        match generic {
-                            ast::GenericParam::ConstParam(cp) => f(&cp.name().unwrap()),
-                            ast::GenericParam::LifetimeParam(lp) => f(&lp.lifetime().unwrap()),
-                            ast::GenericParam::TypeParam(tp) => f(&tp.name().unwrap()),
-                        }
-                    })
-                )
-            } else {
-                String::from("Type")
-            };
+            let ty_args = generic_params
+                .as_ref()
+                .map_or(String::new(), |it| it.to_generic_args().to_string());
+            let replacement = format!("Type{ty_args}");
             builder.replace(target, replacement);
 
             let indent = IndentLevel::from_node(node);
-            let generics = if !generics.is_empty() {
-                format!("<{}>", generics.iter().format(", "))
-            } else {
-                String::new()
-            };
+            let generic_params = generic_params.map_or(String::new(), |it| it.to_string());
             match ctx.config.snippet_cap {
                 Some(cap) => {
                     builder.insert_snippet(
                         cap,
                         insert_pos,
-                        format!("type $0Type{} = {};\n\n{}", generics, ty, indent),
+                        format!("type $0Type{generic_params} = {ty};\n\n{indent}"),
                     );
                 }
                 None => {
                     builder.insert(
                         insert_pos,
-                        format!("type Type{} = {};\n\n{}", generics, ty, indent),
+                        format!("type Type{generic_params} = {ty};\n\n{indent}"),
                     );
                 }
             }
@@ -109,7 +96,7 @@ pub(crate) fn extract_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) ->
 fn collect_used_generics<'gp>(
     ty: &ast::Type,
     known_generics: &'gp [ast::GenericParam],
-) -> Vec<&'gp ast::GenericParam> {
+) -> Option<Vec<&'gp ast::GenericParam>> {
     // can't use a closure -> closure here cause lifetime inference fails for that
     fn find_lifetime(text: &str) -> impl Fn(&&ast::GenericParam) -> bool + '_ {
         move |gp: &&ast::GenericParam| match gp {
@@ -198,7 +185,8 @@ fn find_lifetime(text: &str) -> impl Fn(&&ast::GenericParam) -> bool + '_ {
         ast::GenericParam::LifetimeParam(_) => 0,
         ast::GenericParam::TypeParam(_) => 1,
     });
-    generics
+
+    Some(generics).filter(|it| it.len() > 0)
 }
 
 #[cfg(test)]
index 3596b6f82381b5ff1d6127ed162ca27b58aa972e..a738deffb95b302c5d02e23fc1199bb025329792 100644 (file)
@@ -91,13 +91,13 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
 
             match anchor {
                 Anchor::Before(_) | Anchor::Replace(_) => {
-                    format_to!(buf, "let {}{} = {}", var_modifier, var_name, reference_modifier)
+                    format_to!(buf, "let {var_modifier}{var_name} = {reference_modifier}")
                 }
                 Anchor::WrapInBlock(_) => {
-                    format_to!(buf, "{{ let {} = {}", var_name, reference_modifier)
+                    format_to!(buf, "{{ let {var_name} = {reference_modifier}")
                 }
             };
-            format_to!(buf, "{}", to_extract.syntax());
+            format_to!(buf, "{to_extract}");
 
             if let Anchor::Replace(stmt) = anchor {
                 cov_mark::hit!(test_extract_var_expr_stmt);
@@ -107,8 +107,8 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
                 match ctx.config.snippet_cap {
                     Some(cap) => {
                         let snip = buf.replace(
-                            &format!("let {}{}", var_modifier, var_name),
-                            &format!("let {}$0{}", var_modifier, var_name),
+                            &format!("let {var_modifier}{var_name}"),
+                            &format!("let {var_modifier}$0{var_name}"),
                         );
                         edit.replace_snippet(cap, expr_range, snip)
                     }
@@ -135,8 +135,8 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
             match ctx.config.snippet_cap {
                 Some(cap) => {
                     let snip = buf.replace(
-                        &format!("let {}{}", var_modifier, var_name),
-                        &format!("let {}$0{}", var_modifier, var_name),
+                        &format!("let {var_modifier}{var_name}"),
+                        &format!("let {var_modifier}$0{var_name}"),
                     );
                     edit.insert_snippet(cap, offset, snip)
                 }
index b33846f546653e9095520861ea3d4fa819803a91..8764543028706f9d37d068397d283d525b029d77 100644 (file)
@@ -57,8 +57,8 @@ fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext<'_>)
         if current_module.krate() == target_module.krate() { "pub(crate)" } else { "pub" };
 
     let assist_label = match target_name {
-        None => format!("Change visibility to {}", missing_visibility),
-        Some(name) => format!("Change visibility of {} to {}", name, missing_visibility),
+        None => format!("Change visibility to {missing_visibility}"),
+        Some(name) => format!("Change visibility of {name} to {missing_visibility}"),
     };
 
     acc.add(AssistId("fix_visibility", AssistKind::QuickFix), assist_label, target, |builder| {
@@ -68,15 +68,15 @@ fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext<'_>)
                 Some(current_visibility) => builder.replace_snippet(
                     cap,
                     current_visibility.syntax().text_range(),
-                    format!("$0{}", missing_visibility),
+                    format!("$0{missing_visibility}"),
                 ),
-                None => builder.insert_snippet(cap, offset, format!("$0{} ", missing_visibility)),
+                None => builder.insert_snippet(cap, offset, format!("$0{missing_visibility} ")),
             },
             None => match current_visibility {
                 Some(current_visibility) => {
                     builder.replace(current_visibility.syntax().text_range(), missing_visibility)
                 }
-                None => builder.insert(offset, format!("{} ", missing_visibility)),
+                None => builder.insert(offset, format!("{missing_visibility} ")),
             },
         }
     })
@@ -114,7 +114,7 @@ fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext<'_>
 
     let target_name = record_field_def.name(ctx.db());
     let assist_label =
-        format!("Change visibility of {}.{} to {}", parent_name, target_name, missing_visibility);
+        format!("Change visibility of {parent_name}.{target_name} to {missing_visibility}");
 
     acc.add(AssistId("fix_visibility", AssistKind::QuickFix), assist_label, target, |builder| {
         builder.edit_file(target_file);
@@ -123,15 +123,15 @@ fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext<'_>
                 Some(current_visibility) => builder.replace_snippet(
                     cap,
                     current_visibility.syntax().text_range(),
-                    format!("$0{}", missing_visibility),
+                    format!("$0{missing_visibility}"),
                 ),
-                None => builder.insert_snippet(cap, offset, format!("$0{} ", missing_visibility)),
+                None => builder.insert_snippet(cap, offset, format!("$0{missing_visibility} ")),
             },
             None => match current_visibility {
                 Some(current_visibility) => {
                     builder.replace(current_visibility.syntax().text_range(), missing_visibility)
                 }
-                None => builder.insert(offset, format!("{} ", missing_visibility)),
+                None => builder.insert(offset, format!("{missing_visibility} ")),
             },
         }
     })
index bdd3cf4f06c253692d3e3989075ec4cd56e4ba15..c9aa41c845ad5c0b0a964cb6d0d059167dd1d416 100644 (file)
@@ -124,6 +124,7 @@ fn generate_enum_projection_method(
         happy_case,
         sad_case,
     } = props;
+
     let variant = ctx.find_node_at_offset::<ast::Variant>()?;
     let variant_name = variant.name()?;
     let parent_enum = ast::Adt::Enum(variant.parent_enum());
@@ -144,7 +145,7 @@ fn generate_enum_projection_method(
         ast::StructKind::Unit => return None,
     };
 
-    let fn_name = format!("{}_{}", fn_name_prefix, &to_lower_snake_case(&variant_name.text()));
+    let fn_name = format!("{fn_name_prefix}_{}", &to_lower_snake_case(&variant_name.text()));
 
     // Return early if we've found an existing new fn
     let impl_def = find_struct_impl(ctx, &parent_enum, &[fn_name.clone()])?;
@@ -156,15 +157,25 @@ fn generate_enum_projection_method(
         assist_description,
         target,
         |builder| {
-            let vis = parent_enum.visibility().map_or(String::new(), |v| format!("{v} "));
+            let vis = parent_enum.visibility().map_or(String::new(), |v| format!("{} ", v));
+
+            let field_type_syntax = field_type.syntax();
+
+            let must_use = if ctx.config.assist_emit_must_use {
+                "#[must_use]\n    "
+            } else {
+                ""
+            };
+
             let method = format!(
-                "    {vis}fn {fn_name}({self_param}) -> {return_prefix}{field_type}{return_suffix} {{
+                "    {must_use}{vis}fn {fn_name}({self_param}) -> {return_prefix}{field_type_syntax}{return_suffix} {{
         if let Self::{variant_name}{pattern_suffix} = self {{
             {happy_case}({bound_name})
         }} else {{
             {sad_case}
         }}
-    }}");
+    }}"
+            );
 
             add_method_to_adt(builder, &parent_enum, impl_def, &method);
         },
index 9f51cdaf8b1eb0d7eccc6ae154ec038f5118504c..0c546ce5d41c6520bc9df8402d8d77753f6933b6 100644 (file)
@@ -1,3 +1,5 @@
+use std::collections::BTreeSet;
+
 use ast::make;
 use either::Either;
 use hir::{db::HirDatabase, PathResolution, Semantics, TypeInfo};
@@ -190,10 +192,10 @@ pub(crate) fn inline_call(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
                 PathResolution::Def(hir::ModuleDef::Function(f)) => f,
                 _ => return None,
             };
-            (function, format!("Inline `{}`", path))
+            (function, format!("Inline `{path}`"))
         }
         ast::CallableExpr::MethodCall(call) => {
-            (ctx.sema.resolve_method_call(call)?, format!("Inline `{}`", name_ref))
+            (ctx.sema.resolve_method_call(call)?, format!("Inline `{name_ref}`"))
         }
     };
 
@@ -373,8 +375,44 @@ fn inline(
                 })
         }
     }
+
+    let mut func_let_vars: BTreeSet<String> = BTreeSet::new();
+
+    // grab all of the local variable declarations in the function
+    for stmt in fn_body.statements() {
+        if let Some(let_stmt) = ast::LetStmt::cast(stmt.syntax().to_owned()) {
+            for has_token in let_stmt.syntax().children_with_tokens() {
+                if let Some(node) = has_token.as_node() {
+                    if let Some(ident_pat) = ast::IdentPat::cast(node.to_owned()) {
+                        func_let_vars.insert(ident_pat.syntax().text().to_string());
+                    }
+                }
+            }
+        }
+    }
+
     // Inline parameter expressions or generate `let` statements depending on whether inlining works or not.
     for ((pat, param_ty, _), usages, expr) in izip!(params, param_use_nodes, arguments).rev() {
+        // izip confuses RA due to our lack of hygiene info currently losing us type info causing incorrect errors
+        let usages: &[ast::PathExpr] = &*usages;
+        let expr: &ast::Expr = expr;
+
+        let insert_let_stmt = || {
+            let ty = sema.type_of_expr(expr).filter(TypeInfo::has_adjustment).and(param_ty.clone());
+            if let Some(stmt_list) = body.stmt_list() {
+                stmt_list.push_front(
+                    make::let_stmt(pat.clone(), ty, Some(expr.clone())).clone_for_update().into(),
+                )
+            }
+        };
+
+        // check if there is a local var in the function that conflicts with parameter
+        // if it does then emit a let statement and continue
+        if func_let_vars.contains(&expr.syntax().text().to_string()) {
+            insert_let_stmt();
+            continue;
+        }
+
         let inline_direct = |usage, replacement: &ast::Expr| {
             if let Some(field) = path_expr_as_record_field(usage) {
                 cov_mark::hit!(inline_call_inline_direct_field);
@@ -383,9 +421,7 @@ fn inline(
                 ted::replace(usage.syntax(), &replacement.syntax().clone_for_update());
             }
         };
-        // izip confuses RA due to our lack of hygiene info currently losing us type info causing incorrect errors
-        let usages: &[ast::PathExpr] = &*usages;
-        let expr: &ast::Expr = expr;
+
         match usages {
             // inline single use closure arguments
             [usage]
@@ -408,18 +444,11 @@ fn inline(
             }
             // can't inline, emit a let statement
             _ => {
-                let ty =
-                    sema.type_of_expr(expr).filter(TypeInfo::has_adjustment).and(param_ty.clone());
-                if let Some(stmt_list) = body.stmt_list() {
-                    stmt_list.push_front(
-                        make::let_stmt(pat.clone(), ty, Some(expr.clone()))
-                            .clone_for_update()
-                            .into(),
-                    )
-                }
+                insert_let_stmt();
             }
         }
     }
+
     if let Some(generic_arg_list) = generic_arg_list.clone() {
         if let Some((target, source)) = &sema.scope(node.syntax()).zip(sema.scope(fn_body.syntax()))
         {
@@ -1256,4 +1285,37 @@ fn main() {
 "#,
         )
     }
+
+    #[test]
+    fn local_variable_shadowing_callers_argument() {
+        check_assist(
+            inline_call,
+            r#"
+fn foo(bar: u32, baz: u32) -> u32 {
+    let a = 1;
+    bar * baz * a * 6
+}
+fn main() {
+    let a = 7;
+    let b = 1;
+    let res = foo$0(a, b);
+}
+"#,
+            r#"
+fn foo(bar: u32, baz: u32) -> u32 {
+    let a = 1;
+    bar * baz * a * 6
+}
+fn main() {
+    let a = 7;
+    let b = 1;
+    let res = {
+        let bar = a;
+        let a = 1;
+        bar * b * a * 6
+    };
+}
+"#,
+        );
+    }
 }
index 7259d67819416e502dcceb64452b5f3b2bedc6a6..ce44100e34bebee523197b6bf66035b810459917 100644 (file)
@@ -113,7 +113,7 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext<'_>)
         .collect::<Option<Vec<_>>>()?;
 
     let init_str = initializer_expr.syntax().text().to_string();
-    let init_in_paren = format!("({})", &init_str);
+    let init_in_paren = format!("({init_str})");
 
     let target = match target {
         ast::NameOrNameRef::Name(it) => it.syntax().text_range(),
@@ -132,7 +132,7 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext<'_>)
                 let replacement = if should_wrap { &init_in_paren } else { &init_str };
                 if ast::RecordExprField::for_field_name(&name).is_some() {
                     cov_mark::hit!(inline_field_shorthand);
-                    builder.insert(range.end(), format!(": {}", replacement));
+                    builder.insert(range.end(), format!(": {replacement}"));
                 } else {
                     builder.replace(range, replacement.clone())
                 }
index 2fc754e3e50d1b81f1376fe2167aed17282218b4..a54dc4f96de00e0f198b8c86b9d26a6d8b8bd484 100644 (file)
@@ -127,7 +127,7 @@ fn generate_unique_lifetime_param_name(
         Some(type_params) => {
             let used_lifetime_params: FxHashSet<_> =
                 type_params.lifetime_params().map(|p| p.syntax().text().to_string()).collect();
-            ('a'..='z').map(|it| format!("'{}", it)).find(|it| !used_lifetime_params.contains(it))
+            ('a'..='z').map(|it| format!("'{it}")).find(|it| !used_lifetime_params.contains(it))
         }
         None => Some("'a".to_string()),
     }
index c24015b1c5175a410d45dab0974e913b78346de1..641c90885bf530d09a509a10e496879f5f61598a 100644 (file)
@@ -78,7 +78,7 @@ pub(crate) fn merge_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
                     .join(" | ")
             };
 
-            let arm = format!("{} => {},", pats, current_expr.syntax().text());
+            let arm = format!("{pats} => {current_expr},");
 
             if let [first, .., last] = &*arms_to_merge {
                 let start = first.syntax().text_range().start();
index a6c85a2b18b34b535c9e98e3ea01fbfc4b4f2dc6..1728c03cd03e2e36f553c5dc6af983edbcfab83e 100644 (file)
@@ -40,11 +40,11 @@ pub(crate) fn move_from_mod_rs(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
 
     let target = source_file.syntax().text_range();
     let module_name = module.name(ctx.db())?.to_string();
-    let path = format!("../{}.rs", module_name);
+    let path = format!("../{module_name}.rs");
     let dst = AnchoredPathBuf { anchor: ctx.file_id(), path };
     acc.add(
         AssistId("move_from_mod_rs", AssistKind::Refactor),
-        format!("Convert {}/mod.rs to {}.rs", module_name, module_name),
+        format!("Convert {module_name}/mod.rs to {module_name}.rs"),
         target,
         |builder| {
             builder.move_file(ctx.file_id(), dst);
index b8f1b36deb93cbbbed959f05c8fe1dc047ab5926..ec3281619cc3ff7bb21d889d63dfc0d268582632 100644 (file)
@@ -133,16 +133,16 @@ pub(crate) fn move_arm_cond_to_match_guard(
             };
             let then_arm_end = match_arm.syntax().text_range().end();
             let indent_level = match_arm.indent_level();
-            let spaces = "    ".repeat(indent_level.0 as _);
+            let spaces = indent_level;
 
             let mut first = true;
             for (cond, block) in conds_blocks {
                 if !first {
-                    edit.insert(then_arm_end, format!("\n{}", spaces));
+                    edit.insert(then_arm_end, format!("\n{spaces}"));
                 } else {
                     first = false;
                 }
-                let guard = format!("{} if {} => ", match_pat, cond.syntax().text());
+                let guard = format!("{match_pat} if {cond} => ");
                 edit.insert(then_arm_end, guard);
                 let only_expr = block.statements().next().is_none();
                 match &block.tail_expr() {
@@ -158,7 +158,7 @@ pub(crate) fn move_arm_cond_to_match_guard(
             }
             if let Some(e) = tail {
                 cov_mark::hit!(move_guard_ifelse_else_tail);
-                let guard = format!("\n{}{} => ", spaces, match_pat);
+                let guard = format!("\n{spaces}{match_pat} => ");
                 edit.insert(then_arm_end, guard);
                 let only_expr = e.statements().next().is_none();
                 match &e.tail_expr() {
@@ -183,7 +183,7 @@ pub(crate) fn move_arm_cond_to_match_guard(
                     {
                         cov_mark::hit!(move_guard_ifelse_has_wildcard);
                     }
-                    _ => edit.insert(then_arm_end, format!("\n{}{} => {{}}", spaces, match_pat)),
+                    _ => edit.insert(then_arm_end, format!("\n{spaces}{match_pat} => {{}}")),
                 }
             }
         },
index 7468318a594afbea619df9e475aebdb414030484..a7c605325ea6938cfe3f102bf500add03efdf5da 100644 (file)
@@ -52,7 +52,7 @@ pub(crate) fn move_module_to_file(acc: &mut Assists, ctx: &AssistContext<'_>) ->
                 let mut buf = String::from("./");
                 match parent_module.name(ctx.db()) {
                     Some(name) if !parent_module.is_mod_rs(ctx.db()) => {
-                        format_to!(buf, "{}/", name)
+                        format_to!(buf, "{name}/")
                     }
                     _ => (),
                 }
@@ -82,7 +82,7 @@ pub(crate) fn move_module_to_file(acc: &mut Assists, ctx: &AssistContext<'_>) ->
                 items
             };
 
-            let buf = format!("mod {};", module_name);
+            let buf = format!("mod {module_name};");
 
             let replacement_start = match module_ast.mod_token() {
                 Some(mod_token) => mod_token.text_range(),
index a909ce8b26791af34208f0aa32b20017978e697b..076d25411a8180e7627fbf93084b786144270443 100644 (file)
@@ -40,11 +40,11 @@ pub(crate) fn move_to_mod_rs(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
 
     let target = source_file.syntax().text_range();
     let module_name = module.name(ctx.db())?.to_string();
-    let path = format!("./{}/mod.rs", module_name);
+    let path = format!("./{module_name}/mod.rs");
     let dst = AnchoredPathBuf { anchor: ctx.file_id(), path };
     acc.add(
         AssistId("move_to_mod_rs", AssistKind::Refactor),
-        format!("Convert {}.rs to {}/mod.rs", module_name, module_name),
+        format!("Convert {module_name}.rs to {module_name}/mod.rs"),
         target,
         |builder| {
             builder.move_file(ctx.file_id(), dst);
index 424db7437a743b4bce4fa639dc500048718f87d7..7e3fef516bfd8f2f399aba6e2c97e4fee3d6b792 100644 (file)
@@ -38,7 +38,7 @@ pub(crate) fn reformat_number_literal(acc: &mut Assists, ctx: &AssistContext<'_>
     converted.push_str(suffix);
 
     let group_id = GroupLabel("Reformat number literal".into());
-    let label = format!("Convert {} to {}", literal, converted);
+    let label = format!("Convert {literal} to {converted}");
     let range = literal.syntax().text_range();
     acc.add_group(
         &group_id,
index e57d1d065d6229361ca68604e8ace6c8b9331c1d..1ea87429c50928bc3dfc5cffe738c46c3297b4a9 100644 (file)
@@ -54,7 +54,7 @@ pub(crate) fn qualify_method_call(acc: &mut Assists, ctx: &AssistContext<'_>) ->
 
     acc.add(
         AssistId("qualify_method_call", AssistKind::RefactorInline),
-        format!("Qualify `{}` method call", ident.text()),
+        format!("Qualify `{ident}` method call"),
         range,
         |builder| {
             qualify_candidate.qualify(
index 4b2af550bc5e4902c15bdf4a158ba6ee0bef6326..e759e1561cbd0a5ba956f42bacabd232de330d58 100644 (file)
@@ -118,14 +118,14 @@ pub(crate) fn qualify(
         match self {
             QualifyCandidate::QualifierStart(segment, generics) => {
                 let generics = generics.as_ref().map_or_else(String::new, ToString::to_string);
-                replacer(format!("{}{}::{}", import, generics, segment));
+                replacer(format!("{import}{generics}::{segment}"));
             }
             QualifyCandidate::UnqualifiedName(generics) => {
                 let generics = generics.as_ref().map_or_else(String::new, ToString::to_string);
-                replacer(format!("{}{}", import, generics));
+                replacer(format!("{import}{generics}"));
             }
             QualifyCandidate::TraitAssocItem(qualifier, segment) => {
-                replacer(format!("<{} as {}>::{}", qualifier, import, segment));
+                replacer(format!("<{qualifier} as {import}>::{segment}"));
             }
             QualifyCandidate::TraitMethod(db, mcall_expr) => {
                 Self::qualify_trait_method(db, mcall_expr, replacer, import, item);
@@ -155,16 +155,11 @@ fn qualify_fn_call(
                 hir::Access::Exclusive => make::expr_ref(receiver, true),
                 hir::Access::Owned => receiver,
             };
-            replacer(format!(
-                "{}::{}{}{}",
-                import,
-                method_name,
-                generics,
-                match arg_list {
-                    Some(args) => make::arg_list(iter::once(receiver).chain(args)),
-                    None => make::arg_list(iter::once(receiver)),
-                }
-            ));
+            let arg_list = match arg_list {
+                Some(args) => make::arg_list(iter::once(receiver).chain(args)),
+                None => make::arg_list(iter::once(receiver)),
+            };
+            replacer(format!("{import}::{method_name}{generics}{arg_list}"));
         }
         Some(())
     }
@@ -218,15 +213,17 @@ fn group_label(candidate: &ImportCandidate) -> GroupLabel {
         }
     }
     .text();
-    GroupLabel(format!("Qualify {}", name))
+    GroupLabel(format!("Qualify {name}"))
 }
 
 fn label(candidate: &ImportCandidate, import: &LocatedImport) -> String {
+    let import_path = &import.import_path;
+
     match candidate {
         ImportCandidate::Path(candidate) if candidate.qualifier.is_none() => {
-            format!("Qualify as `{}`", import.import_path)
+            format!("Qualify as `{import_path}`")
         }
-        _ => format!("Qualify with `{}`", import.import_path),
+        _ => format!("Qualify with `{import_path}`"),
     }
 }
 
index dbe8cb7bf031faadb71ed8ebae13819624980f55..c9bc25b27a5ed8c0d1c3543d1d2be932cb50c139 100644 (file)
@@ -34,13 +34,10 @@ pub(crate) fn make_raw_string(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt
             let hashes = "#".repeat(required_hashes(&value).max(1));
             if matches!(value, Cow::Borrowed(_)) {
                 // Avoid replacing the whole string to better position the cursor.
-                edit.insert(token.syntax().text_range().start(), format!("r{}", hashes));
+                edit.insert(token.syntax().text_range().start(), format!("r{hashes}"));
                 edit.insert(token.syntax().text_range().end(), hashes);
             } else {
-                edit.replace(
-                    token.syntax().text_range(),
-                    format!("r{}\"{}\"{}", hashes, value, hashes),
-                );
+                edit.replace(token.syntax().text_range(), format!("r{hashes}\"{value}\"{hashes}"));
             }
         },
     )
@@ -83,7 +80,7 @@ pub(crate) fn make_usual_string(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
                 }
             }
 
-            edit.replace(token.syntax().text_range(), format!("\"{}\"", escaped));
+            edit.replace(token.syntax().text_range(), format!("\"{escaped}\""));
         },
     )
 }
index afaa7c933c73951093dea8d12d0c12557c03cc76..3d9cbff177ba9c68bfed291a2c2ca58eea3c1051 100644 (file)
@@ -102,7 +102,7 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<(
             };
             (
                 macro_call.syntax().text_range(),
-                if wrap { format!("({})", expr) } else { expr.to_string() },
+                if wrap { format!("({expr})") } else { expr.to_string() },
             )
         }
         // dbg!(expr0, expr1, ...)
@@ -127,8 +127,8 @@ mod tests {
     fn check(ra_fixture_before: &str, ra_fixture_after: &str) {
         check_assist(
             remove_dbg,
-            &format!("fn main() {{\n{}\n}}", ra_fixture_before),
-            &format!("fn main() {{\n{}\n}}", ra_fixture_after),
+            &format!("fn main() {{\n{ra_fixture_before}\n}}"),
+            &format!("fn main() {{\n{ra_fixture_after}\n}}"),
         );
     }
 
index 9fd5e1886d206ef3dad043c6e29f2a4eb88b1219..f9ba289ee175fe76d554aeb28811b774b5fc34a1 100644 (file)
@@ -124,7 +124,7 @@ fn add_assist(
 ) -> Option<()> {
     let target = attr.syntax().text_range();
     let annotated_name = adt.name()?;
-    let label = format!("Convert to manual `impl {} for {}`", replace_trait_path, annotated_name);
+    let label = format!("Convert to manual `impl {replace_trait_path} for {annotated_name}`");
 
     acc.add(
         AssistId("replace_derive_with_manual_impl", AssistKind::Refactor),
@@ -158,11 +158,8 @@ fn add_assist(
                         }
                     }
 
-                    builder.insert_snippet(
-                        cap,
-                        insert_pos,
-                        format!("\n\n{}", render_snippet(cap, impl_def.syntax(), cursor)),
-                    )
+                    let rendered = render_snippet(cap, impl_def.syntax(), cursor);
+                    builder.insert_snippet(cap, insert_pos, format!("\n\n{rendered}"))
                 }
             };
         },
index 7d91be621013653aca193b1f23fc8a0469eaf376..77382056c18339eb8d29335c5aa50d2cc8d58106 100644 (file)
@@ -62,7 +62,7 @@ pub(crate) fn replace_or_with_or_else(acc: &mut Assists, ctx: &AssistContext<'_>
 
     acc.add(
         AssistId("replace_or_with_or_else", AssistKind::RefactorRewrite),
-        format!("Replace {} with {}", name.text(), replace),
+        format!("Replace {name} with {replace}"),
         call.syntax().text_range(),
         |builder| {
             builder.replace(name.syntax().text_range(), replace);
@@ -138,7 +138,7 @@ pub(crate) fn replace_or_else_with_or(acc: &mut Assists, ctx: &AssistContext<'_>
 
     acc.add(
         AssistId("replace_or_else_with_or", AssistKind::RefactorRewrite),
-        format!("Replace {} with {}", name.text(), replace),
+        format!("Replace {name} with {replace}"),
         call.syntax().text_range(),
         |builder| {
             builder.replace(name.syntax().text_range(), replace);
index 521447c26dfbed01d20ac10592fd127a286f16ec..c177adc7a10d73a78cb034e8388f4e0200d79852 100644 (file)
@@ -79,7 +79,7 @@ pub(crate) fn replace_turbofish_with_explicit_type(
             "Replace turbofish with explicit type",
             TextRange::new(initializer_start, turbofish_range.end()),
             |builder| {
-                builder.insert(ident_range.end(), format!(": {}", returned_type));
+                builder.insert(ident_range.end(), format!(": {returned_type}"));
                 builder.delete(turbofish_range);
             },
         );
index d5cd2d551349d7c225be5e262ce399e2354deafb..04398832253307be610ef1da72c05d5b33fa7d20 100644 (file)
@@ -44,6 +44,12 @@ pub(crate) fn unnecessary_async(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
     if function.body()?.syntax().descendants().find_map(ast::AwaitExpr::cast).is_some() {
         return None;
     }
+    // Do nothing if the method is a member of trait.
+    if let Some(impl_) = function.syntax().ancestors().nth(2).and_then(ast::Impl::cast) {
+        if let Some(_) = impl_.trait_() {
+            return None;
+        }
+    }
 
     // Remove the `async` keyword plus whitespace after it, if any.
     let async_range = {
@@ -254,4 +260,18 @@ fn does_not_apply_on_function_with_a_nested_await_expr() {
     fn does_not_apply_when_not_on_prototype() {
         check_assist_not_applicable(unnecessary_async, "pub async fn f() { $0f2() }")
     }
+
+    #[test]
+    fn does_not_apply_on_async_trait_method() {
+        check_assist_not_applicable(
+            unnecessary_async,
+            r#"
+trait Trait {
+    async fn foo();
+}
+impl Trait for () {
+    $0async fn foo() {}
+}"#,
+        );
+    }
 }
index 25c58d086e977d71f3711fb2c09d65fdd26df653..d09614c51127ed8232c86e8c02b3cc4f57ddd858 100644 (file)
@@ -69,13 +69,13 @@ pub(crate) fn unwrap_tuple(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
                 for (pat, ty, expr) in
                     itertools::izip!(tuple_pat.fields(), tys.fields(), tuple_init.fields())
                 {
-                    zipped_decls.push_str(&format!("{}let {pat}: {ty} = {expr};\n", indents))
+                    zipped_decls.push_str(&format!("{indents}let {pat}: {ty} = {expr};\n"))
                 }
                 edit.replace(parent.text_range(), zipped_decls.trim());
             } else {
                 let mut zipped_decls = String::new();
                 for (pat, expr) in itertools::izip!(tuple_pat.fields(), tuple_init.fields()) {
-                    zipped_decls.push_str(&format!("{}let {pat} = {expr};\n", indents));
+                    zipped_decls.push_str(&format!("{indents}let {pat} = {expr};\n"));
                 }
                 edit.replace(parent.text_range(), zipped_decls.trim());
             }
index 83446387db1cf65332b559105fb75a7a8c7326e3..b6c489eb62eef2c734e9fdf726f5fcd455ef22c0 100644 (file)
@@ -76,11 +76,11 @@ pub(crate) fn wrap_return_type_in_result(acc: &mut Assists, ctx: &AssistContext<
 
             match ctx.config.snippet_cap {
                 Some(cap) => {
-                    let snippet = format!("Result<{}, ${{0:_}}>", type_ref);
+                    let snippet = format!("Result<{type_ref}, ${{0:_}}>");
                     builder.replace_snippet(cap, type_ref.syntax().text_range(), snippet)
                 }
                 None => builder
-                    .replace(type_ref.syntax().text_range(), format!("Result<{}, _>", type_ref)),
+                    .replace(type_ref.syntax().text_range(), format!("Result<{type_ref}, _>")),
             }
         },
     )
index a07318cefad273dbdb4410b12a670f06f86107f9..387cc631428250e9fa82ee9afe72a9a8608849f0 100644 (file)
@@ -120,6 +120,7 @@ mod handlers {
     mod convert_into_to_from;
     mod convert_iter_for_each_to_for;
     mod convert_let_else_to_match;
+    mod convert_match_to_let_else;
     mod convert_tuple_struct_to_named_struct;
     mod convert_named_struct_to_tuple_struct;
     mod convert_to_guarded_return;
@@ -220,6 +221,7 @@ pub(crate) fn all() -> &'static [Handler] {
             convert_iter_for_each_to_for::convert_for_loop_with_for_each,
             convert_let_else_to_match::convert_let_else_to_match,
             convert_named_struct_to_tuple_struct::convert_named_struct_to_tuple_struct,
+            convert_match_to_let_else::convert_match_to_let_else,
             convert_to_guarded_return::convert_to_guarded_return,
             convert_tuple_struct_to_named_struct::convert_tuple_struct_to_named_struct,
             convert_two_arm_bool_match_to_matches_macro::convert_two_arm_bool_match_to_matches_macro,
index f7f2417d0745d7a4088ed75a11f7241875bb5663..92ced27c78aedf801b3c5eee80a066aea043be72 100644 (file)
@@ -30,6 +30,7 @@
         skip_glob_imports: true,
     },
     prefer_no_std: false,
+    assist_emit_must_use: false,
 };
 
 pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) {
index 2c4000efe0fa25a9f0c159d0c5f2f046ab04c9b5..029d169899bb44a9e5ee76f49b1891fabdd3f991 100644 (file)
@@ -407,6 +407,27 @@ fn main() {
     )
 }
 
+#[test]
+fn doctest_convert_match_to_let_else() {
+    check_doc_test(
+        "convert_match_to_let_else",
+        r#####"
+//- minicore: option
+fn foo(opt: Option<()>) {
+    let val = $0match opt {
+        Some(it) => it,
+        None => return,
+    };
+}
+"#####,
+        r#####"
+fn foo(opt: Option<()>) {
+    let Some(val) = opt else { return };
+}
+"#####,
+    )
+}
+
 #[test]
 fn doctest_convert_named_struct_to_tuple_struct() {
     check_doc_test(
index db32e7182c44d76ab78db38123862d8fe9f84257..307e67927056ba9a4eefce68b72bef495c63ac1a 100644 (file)
@@ -189,8 +189,8 @@ pub(crate) fn render_snippet(_cap: SnippetCap, node: &SyntaxNode, cursor: Cursor
     let mut placeholder = cursor.node().to_string();
     escape(&mut placeholder);
     let tab_stop = match cursor {
-        Cursor::Replace(placeholder) => format!("${{0:{}}}", placeholder),
-        Cursor::Before(placeholder) => format!("$0{}", placeholder),
+        Cursor::Replace(placeholder) => format!("${{0:{placeholder}}}"),
+        Cursor::Before(placeholder) => format!("$0{placeholder}"),
     };
 
     let mut buf = node.to_string();
@@ -539,17 +539,17 @@ pub(crate) fn convert_type(&self, db: &dyn HirDatabase) -> String {
             ReferenceConversionType::AsRefSlice => {
                 let type_argument_name =
                     self.ty.type_arguments().next().unwrap().display(db).to_string();
-                format!("&[{}]", type_argument_name)
+                format!("&[{type_argument_name}]")
             }
             ReferenceConversionType::Dereferenced => {
                 let type_argument_name =
                     self.ty.type_arguments().next().unwrap().display(db).to_string();
-                format!("&{}", type_argument_name)
+                format!("&{type_argument_name}")
             }
             ReferenceConversionType::Option => {
                 let type_argument_name =
                     self.ty.type_arguments().next().unwrap().display(db).to_string();
-                format!("Option<&{}>", type_argument_name)
+                format!("Option<&{type_argument_name}>")
             }
             ReferenceConversionType::Result => {
                 let mut type_arguments = self.ty.type_arguments();
@@ -557,19 +557,19 @@ pub(crate) fn convert_type(&self, db: &dyn HirDatabase) -> String {
                     type_arguments.next().unwrap().display(db).to_string();
                 let second_type_argument_name =
                     type_arguments.next().unwrap().display(db).to_string();
-                format!("Result<&{}, &{}>", first_type_argument_name, second_type_argument_name)
+                format!("Result<&{first_type_argument_name}, &{second_type_argument_name}>")
             }
         }
     }
 
     pub(crate) fn getter(&self, field_name: String) -> String {
         match self.conversion {
-            ReferenceConversionType::Copy => format!("self.{}", field_name),
+            ReferenceConversionType::Copy => format!("self.{field_name}"),
             ReferenceConversionType::AsRefStr
             | ReferenceConversionType::AsRefSlice
             | ReferenceConversionType::Dereferenced
             | ReferenceConversionType::Option
-            | ReferenceConversionType::Result => format!("self.{}.as_ref()", field_name),
+            | ReferenceConversionType::Result => format!("self.{field_name}.as_ref()"),
         }
     }
 }
index 7a0c912959a12c53b9b909225accc56e866d3ca5..6c87e66c134d72a28642c8e614d0e372e63073fc 100644 (file)
@@ -41,7 +41,7 @@ fn gen_clone_call(target: ast::Expr) -> ast::Expr {
             let mut arms = vec![];
             for variant in list.variants() {
                 let name = variant.name()?;
-                let variant_name = make::ext::path_from_idents(["Self", &format!("{}", name)])?;
+                let variant_name = make::ext::path_from_idents(["Self", &format!("{name}")])?;
 
                 match variant.field_list() {
                     // => match self { Self::Name { x } => Self::Name { x: x.clone() } }
@@ -70,7 +70,7 @@ fn gen_clone_call(target: ast::Expr) -> ast::Expr {
                         let mut pats = vec![];
                         let mut fields = vec![];
                         for (i, _) in list.fields().enumerate() {
-                            let field_name = format!("arg{}", i);
+                            let field_name = format!("arg{i}");
                             let pat = make::ident_pat(false, false, make::name(&field_name));
                             pats.push(pat.into());
 
@@ -118,7 +118,7 @@ fn gen_clone_call(target: ast::Expr) -> ast::Expr {
                     let mut fields = vec![];
                     for (i, _) in field_list.fields().enumerate() {
                         let f_path = make::expr_path(make::ext::ident_path("self"));
-                        let target = make::expr_field(f_path, &format!("{}", i));
+                        let target = make::expr_field(f_path, &format!("{i}"));
                         fields.push(gen_clone_call(target));
                     }
                     let struct_name = make::expr_path(make::ext::ident_path("Self"));
@@ -151,7 +151,7 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
             let mut arms = vec![];
             for variant in list.variants() {
                 let name = variant.name()?;
-                let variant_name = make::ext::path_from_idents(["Self", &format!("{}", name)])?;
+                let variant_name = make::ext::path_from_idents(["Self", &format!("{name}")])?;
                 let target = make::expr_path(make::ext::ident_path("f"));
 
                 match variant.field_list() {
@@ -159,7 +159,7 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
                         // => f.debug_struct(name)
                         let target = make::expr_path(make::ext::ident_path("f"));
                         let method = make::name_ref("debug_struct");
-                        let struct_name = format!("\"{}\"", name);
+                        let struct_name = format!("\"{name}\"");
                         let args = make::arg_list(Some(make::expr_literal(&struct_name).into()));
                         let mut expr = make::expr_method_call(target, method, args);
 
@@ -173,8 +173,8 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
 
                             // => <expr>.field("field_name", field)
                             let method_name = make::name_ref("field");
-                            let name = make::expr_literal(&(format!("\"{}\"", field_name))).into();
-                            let path = &format!("{}", field_name);
+                            let name = make::expr_literal(&(format!("\"{field_name}\""))).into();
+                            let path = &format!("{field_name}");
                             let path = make::expr_path(make::ext::ident_path(path));
                             let args = make::arg_list(vec![name, path]);
                             expr = make::expr_method_call(expr, method_name, args);
@@ -192,13 +192,13 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
                         // => f.debug_tuple(name)
                         let target = make::expr_path(make::ext::ident_path("f"));
                         let method = make::name_ref("debug_tuple");
-                        let struct_name = format!("\"{}\"", name);
+                        let struct_name = format!("\"{name}\"");
                         let args = make::arg_list(Some(make::expr_literal(&struct_name).into()));
                         let mut expr = make::expr_method_call(target, method, args);
 
                         let mut pats = vec![];
                         for (i, _) in list.fields().enumerate() {
-                            let name = format!("arg{}", i);
+                            let name = format!("arg{i}");
 
                             // create a field pattern for use in `MyStruct(fields..)`
                             let field_name = make::name(&name);
@@ -222,7 +222,7 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
                         arms.push(make::match_arm(Some(pat.into()), None, expr));
                     }
                     None => {
-                        let fmt_string = make::expr_literal(&(format!("\"{}\"", name))).into();
+                        let fmt_string = make::expr_literal(&(format!("\"{name}\""))).into();
                         let args = make::arg_list([target, fmt_string]);
                         let macro_name = make::expr_path(make::ext::ident_path("write"));
                         let macro_call = make::expr_macro_call(macro_name, args);
@@ -244,7 +244,7 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
         }
 
         ast::Adt::Struct(strukt) => {
-            let name = format!("\"{}\"", annotated_name);
+            let name = format!("\"{annotated_name}\"");
             let args = make::arg_list(Some(make::expr_literal(&name).into()));
             let target = make::expr_path(make::ext::ident_path("f"));
 
@@ -258,10 +258,10 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
                     let mut expr = make::expr_method_call(target, method, args);
                     for field in field_list.fields() {
                         let name = field.name()?;
-                        let f_name = make::expr_literal(&(format!("\"{}\"", name))).into();
+                        let f_name = make::expr_literal(&(format!("\"{name}\""))).into();
                         let f_path = make::expr_path(make::ext::ident_path("self"));
                         let f_path = make::expr_ref(f_path, false);
-                        let f_path = make::expr_field(f_path, &format!("{}", name));
+                        let f_path = make::expr_field(f_path, &format!("{name}"));
                         let args = make::arg_list([f_name, f_path]);
                         expr = make::expr_method_call(expr, make::name_ref("field"), args);
                     }
@@ -275,7 +275,7 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
                     for (i, _) in field_list.fields().enumerate() {
                         let f_path = make::expr_path(make::ext::ident_path("self"));
                         let f_path = make::expr_ref(f_path, false);
-                        let f_path = make::expr_field(f_path, &format!("{}", i));
+                        let f_path = make::expr_field(f_path, &format!("{i}"));
                         let method = make::name_ref("field");
                         expr = make::expr_method_call(expr, method, make::arg_list(Some(f_path)));
                     }
@@ -379,7 +379,7 @@ fn gen_hash_call(target: ast::Expr) -> ast::Stmt {
                 let mut stmts = vec![];
                 for (i, _) in field_list.fields().enumerate() {
                     let base = make::expr_path(make::ext::ident_path("self"));
-                    let target = make::expr_field(base, &format!("{}", i));
+                    let target = make::expr_field(base, &format!("{i}"));
                     stmts.push(gen_hash_call(target));
                 }
                 make::block_expr(stmts, None).indent(ast::edit::IndentLevel(1))
@@ -453,10 +453,10 @@ fn gen_tuple_field(field_name: &String) -> ast::Pat {
                         for field in list.fields() {
                             let field_name = field.name()?.to_string();
 
-                            let l_name = &format!("l_{}", field_name);
+                            let l_name = &format!("l_{field_name}");
                             l_fields.push(gen_record_pat_field(&field_name, l_name));
 
-                            let r_name = &format!("r_{}", field_name);
+                            let r_name = &format!("r_{field_name}");
                             r_fields.push(gen_record_pat_field(&field_name, r_name));
 
                             let lhs = make::expr_path(make::ext::ident_path(l_name));
@@ -484,12 +484,12 @@ fn gen_tuple_field(field_name: &String) -> ast::Pat {
                         let mut r_fields = vec![];
 
                         for (i, _) in list.fields().enumerate() {
-                            let field_name = format!("{}", i);
+                            let field_name = format!("{i}");
 
-                            let l_name = format!("l{}", field_name);
+                            let l_name = format!("l{field_name}");
                             l_fields.push(gen_tuple_field(&l_name));
 
-                            let r_name = format!("r{}", field_name);
+                            let r_name = format!("r{field_name}");
                             r_fields.push(gen_tuple_field(&r_name));
 
                             let lhs = make::expr_path(make::ext::ident_path(&l_name));
@@ -548,7 +548,7 @@ fn gen_tuple_field(field_name: &String) -> ast::Pat {
             Some(ast::FieldList::TupleFieldList(field_list)) => {
                 let mut expr = None;
                 for (i, _) in field_list.fields().enumerate() {
-                    let idx = format!("{}", i);
+                    let idx = format!("{i}");
                     let lhs = make::expr_path(make::ext::ident_path("self"));
                     let lhs = make::expr_field(lhs, &idx);
                     let rhs = make::expr_path(make::ext::ident_path("other"));
@@ -628,7 +628,7 @@ fn gen_partial_cmp_call(lhs: ast::Expr, rhs: ast::Expr) -> ast::Expr {
             Some(ast::FieldList::TupleFieldList(field_list)) => {
                 let mut exprs = vec![];
                 for (i, _) in field_list.fields().enumerate() {
-                    let idx = format!("{}", i);
+                    let idx = format!("{i}");
                     let lhs = make::expr_path(make::ext::ident_path("self"));
                     let lhs = make::expr_field(lhs, &idx);
                     let rhs = make::expr_path(make::ext::ident_path("other"));
index 9a891cea2d458491979475f1753b1f3f67b69645..b9bd47f7da504609b4c3b78947bd00bc9774164a 100644 (file)
@@ -69,10 +69,6 @@ pub(crate) fn complete_postfix(
         }
     }
 
-    if !ctx.config.snippets.is_empty() {
-        add_custom_postfix_completions(acc, ctx, &postfix_snippet, &receiver_text);
-    }
-
     let try_enum = TryEnum::from_ty(&ctx.sema, &receiver_ty.strip_references());
     if let Some(try_enum) = &try_enum {
         match try_enum {
@@ -140,6 +136,10 @@ pub(crate) fn complete_postfix(
         None => return,
     };
 
+    if !ctx.config.snippets.is_empty() {
+        add_custom_postfix_completions(acc, ctx, &postfix_snippet, &receiver_text);
+    }
+
     match try_enum {
         Some(try_enum) => match try_enum {
             TryEnum::Result => {
@@ -613,4 +613,25 @@ fn postfix_completion_for_format_like_strings() {
             r#"fn main() { log::error!("{}", 2+2) }"#,
         );
     }
+
+    #[test]
+    fn postfix_custom_snippets_completion_for_references() {
+        check_edit_with_config(
+            CompletionConfig {
+                snippets: vec![Snippet::new(
+                    &[],
+                    &["ok".into()],
+                    &["Ok(${receiver})".into()],
+                    "",
+                    &[],
+                    crate::SnippetScope::Expr,
+                )
+                .unwrap()],
+                ..TEST_CONFIG
+            },
+            "ok",
+            r#"fn main() { &&42.$0 }"#,
+            r#"fn main() { Ok(&&42) }"#,
+        );
+    }
 }
index 82b85f2fa5edd58ed58c59aa172c1599bb7c994d..aa5d7e9beb54f155c9b1753d1ca6283f11f0b99a 100644 (file)
@@ -446,33 +446,47 @@ fn scope_files<'a>(
             })
         }
 
-        // FIXME: There should be optimization potential here
-        // Currently we try to descend everything we find which
-        // means we call `Semantics::descend_into_macros` on
-        // every textual hit. That function is notoriously
-        // expensive even for things that do not get down mapped
-        // into macros.
+        let find_nodes = move |name: &str, node: &syntax::SyntaxNode, offset: TextSize| {
+            node.token_at_offset(offset).find(|it| it.text() == name).map(|token| {
+                // FIXME: There should be optimization potential here
+                // Currently we try to descend everything we find which
+                // means we call `Semantics::descend_into_macros` on
+                // every textual hit. That function is notoriously
+                // expensive even for things that do not get down mapped
+                // into macros.
+                sema.descend_into_macros(token).into_iter().filter_map(|it| it.parent())
+            })
+        };
+
         for (text, file_id, search_range) in scope_files(sema, &search_scope) {
             let tree = Lazy::new(move || sema.parse(file_id).syntax().clone());
 
             // Search for occurrences of the items name
             for offset in match_indices(&text, finder, search_range) {
-                for name in sema.find_nodes_at_offset_with_descend(&tree, offset) {
-                    if match name {
-                        ast::NameLike::NameRef(name_ref) => self.found_name_ref(&name_ref, sink),
-                        ast::NameLike::Name(name) => self.found_name(&name, sink),
-                        ast::NameLike::Lifetime(lifetime) => self.found_lifetime(&lifetime, sink),
-                    } {
-                        return;
+                if let Some(iter) = find_nodes(name, &tree, offset) {
+                    for name in iter.filter_map(ast::NameLike::cast) {
+                        if match name {
+                            ast::NameLike::NameRef(name_ref) => {
+                                self.found_name_ref(&name_ref, sink)
+                            }
+                            ast::NameLike::Name(name) => self.found_name(&name, sink),
+                            ast::NameLike::Lifetime(lifetime) => {
+                                self.found_lifetime(&lifetime, sink)
+                            }
+                        } {
+                            return;
+                        }
                     }
                 }
             }
             // Search for occurrences of the `Self` referring to our type
             if let Some((self_ty, finder)) = &include_self_kw_refs {
                 for offset in match_indices(&text, finder, search_range) {
-                    for name_ref in sema.find_nodes_at_offset_with_descend(&tree, offset) {
-                        if self.found_self_ty_name_ref(self_ty, &name_ref, sink) {
-                            return;
+                    if let Some(iter) = find_nodes("Self", &tree, offset) {
+                        for name_ref in iter.filter_map(ast::NameRef::cast) {
+                            if self.found_self_ty_name_ref(self_ty, &name_ref, sink) {
+                                return;
+                            }
                         }
                     }
                 }
@@ -493,17 +507,21 @@ fn scope_files<'a>(
                     let tree = Lazy::new(move || sema.parse(file_id).syntax().clone());
 
                     for offset in match_indices(&text, finder, search_range) {
-                        for name_ref in sema.find_nodes_at_offset_with_descend(&tree, offset) {
-                            if self.found_name_ref(&name_ref, sink) {
-                                return;
+                        if let Some(iter) = find_nodes("super", &tree, offset) {
+                            for name_ref in iter.filter_map(ast::NameRef::cast) {
+                                if self.found_name_ref(&name_ref, sink) {
+                                    return;
+                                }
                             }
                         }
                     }
                     if let Some(finder) = &is_crate_root {
                         for offset in match_indices(&text, finder, search_range) {
-                            for name_ref in sema.find_nodes_at_offset_with_descend(&tree, offset) {
-                                if self.found_name_ref(&name_ref, sink) {
-                                    return;
+                            if let Some(iter) = find_nodes("crate", &tree, offset) {
+                                for name_ref in iter.filter_map(ast::NameRef::cast) {
+                                    if self.found_name_ref(&name_ref, sink) {
+                                        return;
+                                    }
                                 }
                             }
                         }
@@ -544,9 +562,11 @@ fn scope_files<'a>(
                 let finder = &Finder::new("self");
 
                 for offset in match_indices(&text, finder, search_range) {
-                    for name_ref in sema.find_nodes_at_offset_with_descend(&tree, offset) {
-                        if self.found_self_module_name_ref(&name_ref, sink) {
-                            return;
+                    if let Some(iter) = find_nodes("self", &tree, offset) {
+                        for name_ref in iter.filter_map(ast::NameRef::cast) {
+                            if self.found_self_module_name_ref(&name_ref, sink) {
+                                return;
+                            }
                         }
                     }
                 }
index 852a8fd837616ab3c0a2fb4c1bdf75e99774fe8d..07d117aff10bd8fa9bbdc3dff5ee5aaed8e38153 100644 (file)
@@ -73,8 +73,8 @@ pub fn from_def(db: &RootDatabase, def: Definition, from_crate: Crate) -> Option
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct PackageInformation {
     pub name: String,
-    pub repo: String,
-    pub version: String,
+    pub repo: Option<String>,
+    pub version: Option<String>,
 }
 
 pub(crate) fn crate_for_file(db: &RootDatabase, file_id: FileId) -> Option<Crate> {
@@ -256,18 +256,18 @@ pub(crate) fn def_to_moniker(
             let (name, repo, version) = match krate.origin(db) {
                 CrateOrigin::CratesIo { repo, name } => (
                     name.unwrap_or(krate.display_name(db)?.canonical_name().to_string()),
-                    repo?,
-                    krate.version(db)?,
+                    repo,
+                    krate.version(db),
                 ),
                 CrateOrigin::Lang(lang) => (
                     krate.display_name(db)?.canonical_name().to_string(),
-                    "https://github.com/rust-lang/rust/".to_string(),
-                    match lang {
+                    Some("https://github.com/rust-lang/rust/".to_string()),
+                    Some(match lang {
                         LangCrateOrigin::Other => {
                             "https://github.com/rust-lang/rust/library/".into()
                         }
                         lang => format!("https://github.com/rust-lang/rust/library/{lang}",),
-                    },
+                    }),
                 ),
             };
             PackageInformation { name, repo, version }
@@ -315,7 +315,7 @@ pub fn func() {}
 }
 "#,
             "foo::module::func",
-            r#"PackageInformation { name: "foo", repo: "https://a.b/foo.git", version: "0.1.0" }"#,
+            r#"PackageInformation { name: "foo", repo: Some("https://a.b/foo.git"), version: Some("0.1.0") }"#,
             MonikerKind::Import,
         );
         check_moniker(
@@ -331,7 +331,7 @@ pub fn func$0() {}
 }
 "#,
             "foo::module::func",
-            r#"PackageInformation { name: "foo", repo: "https://a.b/foo.git", version: "0.1.0" }"#,
+            r#"PackageInformation { name: "foo", repo: Some("https://a.b/foo.git"), version: Some("0.1.0") }"#,
             MonikerKind::Export,
         );
     }
@@ -348,7 +348,7 @@ pub fn func$0() {}
 }
 "#,
             "foo::module::MyTrait::func",
-            r#"PackageInformation { name: "foo", repo: "https://a.b/foo.git", version: "0.1.0" }"#,
+            r#"PackageInformation { name: "foo", repo: Some("https://a.b/foo.git"), version: Some("0.1.0") }"#,
             MonikerKind::Export,
         );
     }
@@ -365,7 +365,7 @@ pub trait MyTrait {
 }
 "#,
             "foo::module::MyTrait::MY_CONST",
-            r#"PackageInformation { name: "foo", repo: "https://a.b/foo.git", version: "0.1.0" }"#,
+            r#"PackageInformation { name: "foo", repo: Some("https://a.b/foo.git"), version: Some("0.1.0") }"#,
             MonikerKind::Export,
         );
     }
@@ -382,7 +382,7 @@ pub trait MyTrait {
 }
 "#,
             "foo::module::MyTrait::MyType",
-            r#"PackageInformation { name: "foo", repo: "https://a.b/foo.git", version: "0.1.0" }"#,
+            r#"PackageInformation { name: "foo", repo: Some("https://a.b/foo.git"), version: Some("0.1.0") }"#,
             MonikerKind::Export,
         );
     }
@@ -405,7 +405,7 @@ pub fn func$0() {}
 }
 "#,
             "foo::module::MyStruct::MyTrait::func",
-            r#"PackageInformation { name: "foo", repo: "https://a.b/foo.git", version: "0.1.0" }"#,
+            r#"PackageInformation { name: "foo", repo: Some("https://a.b/foo.git"), version: Some("0.1.0") }"#,
             MonikerKind::Export,
         );
     }
@@ -425,7 +425,7 @@ pub struct St {
 }
 "#,
             "foo::St::a",
-            r#"PackageInformation { name: "foo", repo: "https://a.b/foo.git", version: "0.1.0" }"#,
+            r#"PackageInformation { name: "foo", repo: Some("https://a.b/foo.git"), version: Some("0.1.0") }"#,
             MonikerKind::Import,
         );
     }
index fe44856dcad2a9a0f8abc49d6ca980cbea49df78..b4df0437050f4d4de0be9b6886c1b0b4d66e00b4 100644 (file)
@@ -40,7 +40,9 @@ pub(crate) fn prepare_rename(
             if def.range_for_rename(&sema).is_none() {
                 bail!("No references found at position")
             }
-            let frange = sema.original_range(name_like.syntax());
+            let Some(frange) = sema.original_range_opt(name_like.syntax()) else {
+                bail!("No references found at position");
+            };
 
             always!(
                 frange.range.contains_inclusive(position.offset)
@@ -51,7 +53,7 @@ pub(crate) fn prepare_rename(
         .reduce(|acc, cur| match (acc, cur) {
             // ensure all ranges are the same
             (Ok(acc_inner), Ok(cur_inner)) if acc_inner == cur_inner => Ok(acc_inner),
-            (Err(e), _) => Err(e),
+            (e @ Err(_), _) | (_, e @ Err(_)) => e,
             _ => bail!("inconsistent text range"),
         });
 
@@ -2249,4 +2251,33 @@ fn foo((bar | bar | bar): ()) {
 "#,
         );
     }
+
+    #[test]
+    fn regression_13498() {
+        check(
+            "Testing",
+            r"
+mod foo {
+    pub struct Test$0;
+}
+
+use foo::Test as Tester;
+
+fn main() {
+    let t = Tester;
+}
+",
+            r"
+mod foo {
+    pub struct Testing;
+}
+
+use foo::Testing as Tester;
+
+fn main() {
+    let t = Tester;
+}
+",
+        )
+    }
 }
index fedc1a435827233ac24135b0918167efa4238dc6..7486b20293a664b7fc048dc247332ff7118f8491 100644 (file)
@@ -149,7 +149,7 @@ fn signature_help_for_call(
                 variant.name(db)
             );
         }
-        hir::CallableKind::Closure | hir::CallableKind::FnPtr => (),
+        hir::CallableKind::Closure | hir::CallableKind::FnPtr | hir::CallableKind::Other => (),
     }
 
     res.signature.push('(');
@@ -189,9 +189,10 @@ fn signature_help_for_call(
         hir::CallableKind::Function(func) if callable.return_type().contains_unknown() => {
             render(func.ret_type(db))
         }
-        hir::CallableKind::Function(_) | hir::CallableKind::Closure | hir::CallableKind::FnPtr => {
-            render(callable.return_type())
-        }
+        hir::CallableKind::Function(_)
+        | hir::CallableKind::Closure
+        | hir::CallableKind::FnPtr
+        | hir::CallableKind::Other => render(callable.return_type()),
         hir::CallableKind::TupleStruct(_) | hir::CallableKind::TupleEnumVariant(_) => {}
     }
     Some(res)
@@ -387,10 +388,9 @@ pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) {
     }
 
     fn check(ra_fixture: &str, expect: Expect) {
-        // Implicitly add `Sized` to avoid noisy `T: ?Sized` in the results.
         let fixture = format!(
             r#"
-#[lang = "sized"] trait Sized {{}}
+//- minicore: sized, fn
 {ra_fixture}
             "#
         );
@@ -1331,4 +1331,19 @@ fn foo(self: &Self, other: Self)
             "#]],
         );
     }
+
+    #[test]
+    fn help_for_generic_call() {
+        check(
+            r#"
+fn f<F: FnOnce(u8, u16) -> i32>(f: F) {
+    f($0)
+}
+"#,
+            expect![[r#"
+                (u8, u16) -> i32
+                 ^^  ---
+            "#]],
+        );
+    }
 }
index 5ff347b9bd7227dd886e73bf2b7bec69ce012a30..c74ddabb17770392dbb576059d61231285d7f3bb 100644 (file)
@@ -106,12 +106,12 @@ fn get_package_id(&mut self, package_information: PackageInformation) -> Id {
                 manager: "cargo".to_string(),
                 uri: None,
                 content: None,
-                repository: Some(lsif::Repository {
-                    url: pi.repo,
+                repository: pi.repo.map(|url| lsif::Repository {
+                    url,
                     r#type: "git".to_string(),
                     commit_id: None,
                 }),
-                version: Some(pi.version),
+                version: pi.version,
             }));
         self.package_map.insert(package_information, result_set_id);
         result_set_id
index 16298862b50f39fbaee254c76ccb8190ad4ec017..ca7ba896b67cfc8bbbce7dca755bc520e3998beb 100644 (file)
@@ -231,7 +231,7 @@ fn token_to_symbol(token: &TokenStaticData) -> Option<scip_types::Symbol> {
         package: Some(scip_types::Package {
             manager: "cargo".to_string(),
             name: package_name,
-            version,
+            version: version.unwrap_or_else(|| ".".to_string()),
             ..Default::default()
         })
         .into(),
@@ -415,4 +415,42 @@ pub fn func() {
             "",
         );
     }
+
+    #[test]
+    fn global_symbol_for_pub_struct() {
+        check_symbol(
+            r#"
+    //- /lib.rs crate:main
+    mod foo;
+
+    fn main() {
+        let _bar = foo::Bar { i: 0 };
+    }
+    //- /foo.rs
+    pub struct Bar$0 {
+        pub i: i32,
+    }
+    "#,
+            "rust-analyzer cargo main . foo/Bar#",
+        );
+    }
+
+    #[test]
+    fn global_symbol_for_pub_struct_reference() {
+        check_symbol(
+            r#"
+    //- /lib.rs crate:main
+    mod foo;
+
+    fn main() {
+        let _bar = foo::Bar$0 { i: 0 };
+    }
+    //- /foo.rs
+    pub struct Bar {
+        pub i: i32,
+    }
+    "#,
+            "rust-analyzer cargo main . foo/Bar#",
+        );
+    }
 }
index 1ed8f2bb5f35a639e16d7a4b641677ce94ead90c..4072ae585dbd913d036fbaad37a559db33af3117 100644 (file)
@@ -56,6 +56,9 @@
 // parsing the old name.
 config_data! {
     struct ConfigData {
+        /// Whether to insert #[must_use] when generating `as_` methods
+        /// for enum variants.
+        assist_emitMustUse: bool               = "false",
         /// Placeholder expression to use for missing expressions in assists.
         assist_expressionFillDefault: ExprFillDefaultDef              = "\"todo\"",
 
@@ -1276,6 +1279,7 @@ pub fn assist(&self) -> AssistConfig {
             allowed: None,
             insert_use: self.insert_use_config(),
             prefer_no_std: self.data.imports_prefer_no_std,
+            assist_emit_must_use: self.data.assist_emitMustUse,
         }
     }
 
index 4057a75e7c1e693d053e987ac39bb588ec02b9fa..8c26009add2bb04fbab8203720e32518213270bc 100644 (file)
@@ -334,6 +334,10 @@ pub fn block_expr(
     ast_from_text(&format!("fn f() {buf}"))
 }
 
+pub fn tail_only_block_expr(tail_expr: ast::Expr) -> ast::BlockExpr {
+    ast_from_text(&format!("fn f() {{ {tail_expr} }}"))
+}
+
 /// Ideally this function wouldn't exist since it involves manual indenting.
 /// It differs from `make::block_expr` by also supporting comments.
 ///
@@ -656,6 +660,22 @@ pub fn let_stmt(
     };
     ast_from_text(&format!("fn f() {{ {text} }}"))
 }
+
+pub fn let_else_stmt(
+    pattern: ast::Pat,
+    ty: Option<ast::Type>,
+    expr: ast::Expr,
+    diverging: ast::BlockExpr,
+) -> ast::LetStmt {
+    let mut text = String::new();
+    format_to!(text, "let {pattern}");
+    if let Some(ty) = ty {
+        format_to!(text, ": {ty}");
+    }
+    format_to!(text, " = {expr} else {diverging};");
+    ast_from_text(&format!("fn f() {{ {text} }}"))
+}
+
 pub fn expr_stmt(expr: ast::Expr) -> ast::ExprStmt {
     let semi = if expr.is_block_like() { "" } else { ";" };
     ast_from_text(&format!("fn f() {{ {expr}{semi} (); }}"))
index b9f2b5132353c9c2d30ae16b22cc4b1c98db324f..1eea2346451dd42038a9edcb5bdfe3cd368bb20c 100644 (file)
@@ -5,9 +5,7 @@
 mod block;
 
 use rowan::Direction;
-use rustc_lexer::unescape::{
-    self, unescape_byte, unescape_byte_literal, unescape_char, unescape_literal, Mode,
-};
+use rustc_lexer::unescape::{self, unescape_byte, unescape_char, unescape_literal, Mode};
 
 use crate::{
     algo,
@@ -143,7 +141,7 @@ fn unquote(text: &str, prefix_len: usize, end_delimiter: char) -> Option<&str> {
         ast::LiteralKind::ByteString(s) => {
             if !s.is_raw() {
                 if let Some(without_quotes) = unquote(text, 2, '"') {
-                    unescape_byte_literal(without_quotes, Mode::ByteStr, &mut |range, char| {
+                    unescape_literal(without_quotes, Mode::ByteStr, &mut |range, char| {
                         if let Err(err) = char {
                             push_err(2, (range.start, err));
                         }
index 52a13da31c5d3ea3d25f963ec94e18b09fdbebd2..56a68ef04379036f0dd95701cc1407d3ba318b58 100644 (file)
@@ -338,7 +338,7 @@ The algorithm for building a tree of modules is to start with a crate root
 declarations and recursively process child modules. This is handled by the
 [`module_tree_query`], with two slight variations.
 
-[`module_tree_query`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/module_tree.rs#L116-L123
+[`module_tree_query`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/module_tree.rs#L115-L133
 
 First, rust-analyzer builds a module tree for all crates in a source root
 simultaneously. The main reason for this is historical (`module_tree` predates
@@ -361,7 +361,7 @@ the same, we don't have to re-execute [`module_tree_query`]. In fact, we only
 need to re-execute it when we add/remove new files or when we change mod
 declarations.
 
-[`submodules_query`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/module_tree.rs#L41
+[`submodules_query`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/module_tree.rs#L41
 
 We store the resulting modules in a `Vec`-based indexed arena. The indices in
 the arena becomes module IDs. And this brings us to the next topic:
@@ -389,8 +389,8 @@ integers which can "intern" a location and return an integer ID back. The salsa
 database we use includes a couple of [interners]. How to "garbage collect"
 unused locations is an open question.
 
-[`LocationInterner`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/base_db/src/loc2id.rs#L65-L71
-[interners]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/db.rs#L22-L23
+[`LocationInterner`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_db/src/loc2id.rs#L65-L71
+[interners]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/db.rs#L22-L23
 
 For example, we use `LocationInterner` to assign IDs to definitions of functions,
 structs, enums, etc. The location, [`DefLoc`] contains two bits of information:
@@ -404,7 +404,7 @@ using offsets, text ranges or syntax trees as keys and values for queries. What
 we do instead is we store "index" of the item among all of the items of a file
 (so, a positional based ID, but localized to a single file).
 
-[`DefLoc`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/ids.rs#L127-L139
+[`DefLoc`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/ids.rs#L129-L139
 
 One thing we've glossed over for the time being is support for macros. We have
 only proof of concept handling of macros at the moment, but they are extremely
@@ -437,7 +437,7 @@ terms of `HirFileId`! This does not recur infinitely though: any chain of
 `HirFileId`s bottoms out in `HirFileId::FileId`, that is, some source file
 actually written by the user.
 
-[`HirFileId`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/ids.rs#L18-L125
+[`HirFileId`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/ids.rs#L31-L93
 
 Now that we understand how to identify a definition, in a source or in a
 macro-generated file, we can discuss name resolution a bit.
@@ -451,14 +451,13 @@ each module into a position-independent representation which does not change if
 we modify bodies of the items. After that we [loop] resolving all imports until
 we've reached a fixed point.
 
-[lower]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/nameres/lower.rs#L113-L117
-[loop]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/nameres.rs#L186-L196
-
+[lower]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/nameres/lower.rs#L113-L147
+[loop]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/nameres.rs#L186-L196
 And, given all our preparation with IDs and a position-independent representation,
 it is satisfying to [test] that typing inside function body does not invalidate
 name resolution results.
 
-[test]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/nameres/tests.rs#L376
+[test]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/nameres/tests.rs#L376
 
 An interesting fact about name resolution is that it "erases" all of the
 intermediate paths from the imports: in the end, we know which items are defined
@@ -493,10 +492,10 @@ there's an intermediate [projection query] which returns only the first
 position-independent part of the lowering. The result of this query is stable.
 Naturally, name resolution [uses] this stable projection query.
 
-[imports]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/nameres/lower.rs#L52-L59
-[`SourceMap`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/nameres/lower.rs#L52-L59
-[projection query]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/nameres/lower.rs#L97-L103
-[uses]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/query_definitions.rs#L49
+[imports]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/nameres/lower.rs#L52-L59
+[`SourceMap`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/nameres/lower.rs#L52-L59
+[projection query]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/nameres/lower.rs#L97-L103
+[uses]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/query_definitions.rs#L49
 
 ## Type inference
 
@@ -518,10 +517,10 @@ construct a mapping from `ExprId`s to types.
 
 [@flodiebold]: https://github.com/flodiebold
 [#327]: https://github.com/rust-lang/rust-analyzer/pull/327
-[lower the AST]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/expr.rs
-[positional ID]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/expr.rs#L13-L15
-[a source map]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/expr.rs#L41-L44
-[type inference]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/ty.rs#L1208-L1223
+[lower the AST]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/expr.rs
+[positional ID]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/expr.rs#L13-L15
+[a source map]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/expr.rs#L41-L44
+[type inference]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/ty.rs#L1208-L1223
 
 ## Tying it all together: completion
 
@@ -563,10 +562,11 @@ the type to completion.
 [catch]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/main_loop.rs#L436-L442
 [the handler]: https://salsa.zulipchat.com/#narrow/stream/181542-rfcs.2Fsalsa-query-group/topic/design.20next.20steps
 [ask analysis for completion]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/lib.rs#L439-L444
-[completion implementation]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/completion.rs#L46-L62
-[`CompletionContext`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/completion/completion_context.rs#L14-L37
-["IntelliJ Trick"]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/completion/completion_context.rs#L72-L75
-[find an ancestor `fn` node]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/completion/completion_context.rs#L116-L120
-[semantic model]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/completion/completion_context.rs#L123
-[series of independent completion routines]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/completion.rs#L52-L59
-[`complete_dot`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/completion/complete_dot.rs#L6-L22
+[ask analysis for completion]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_ide_api/src/lib.rs#L439-L444
+[completion implementation]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_ide_api/src/completion.rs#L46-L62
+[`CompletionContext`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_ide_api/src/completion/completion_context.rs#L14-L37
+["IntelliJ Trick"]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_ide_api/src/completion/completion_context.rs#L72-L75
+[find an ancestor `fn` node]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_ide_api/src/completion/completion_context.rs#L116-L120
+[semantic model]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_ide_api/src/completion/completion_context.rs#L123
+[series of independent completion routines]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_ide_api/src/completion.rs#L52-L59
+[`complete_dot`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_ide_api/src/completion/complete_dot.rs#L6-L22
index 502833de72c161716d30f0456e4f2e3e6563d3ae..36794efe42726126311af4cfcdb3e2500ca1c7ec 100644 (file)
@@ -1,3 +1,9 @@
+[[rust-analyzer.assist.emitMustUse]]rust-analyzer.assist.emitMustUse (default: `false`)::
++
+--
+Whether to insert #[must_use] when generating `as_` methods
+for enum variants.
+--
 [[rust-analyzer.assist.expressionFillDefault]]rust-analyzer.assist.expressionFillDefault (default: `"todo"`)::
 +
 --
index c30838e5f5e1e09b10ac34ce19c718d195f67a07..49500e390a50246bb90b4da3a53544610abd7908 100644 (file)
@@ -487,6 +487,12 @@ https://docs.helix-editor.com/[Helix] supports LSP by default.
 However, it won't install `rust-analyzer` automatically.
 You can follow instructions for installing <<rust-analyzer-language-server-binary,`rust-analyzer` binary>>.
 
+=== Crates
+
+There is a package named `ra_ap_rust_analyzer` available on https://crates.io/crates/ra_ap_rust-analyzer[crates.io], for someone who wants to use it programmatically.
+
+For more details, see https://github.com/rust-lang/rust-analyzer/blob/master/.github/workflows/publish.yml[the publish workflow].
+
 == Troubleshooting
 
 Start with looking at the rust-analyzer version.
index a72865d4fe44e1672847cd66548375621bc7db47..0b25564e28d3763240ad5652f5f82aef0e428179 100644 (file)
@@ -23,7 +23,7 @@
                 "esbuild": "^0.14.48",
                 "eslint": "^8.19.0",
                 "eslint-config-prettier": "^8.5.0",
-                "ovsx": "^0.5.1",
+                "ovsx": "^0.5.2",
                 "prettier": "^2.7.1",
                 "tslib": "^2.4.0",
                 "typescript": "^4.7.4",
             }
         },
         "node_modules/ovsx": {
-            "version": "0.5.1",
-            "resolved": "https://registry.npmjs.org/ovsx/-/ovsx-0.5.1.tgz",
-            "integrity": "sha512-3OWq0l7DuVHi2bd2aQe5+QVQlFIqvrcw3/2vGXL404L6Tr+R4QHtzfnYYghv8CCa85xJHjU0RhcaC7pyXkAUbg==",
+            "version": "0.5.2",
+            "resolved": "https://registry.npmjs.org/ovsx/-/ovsx-0.5.2.tgz",
+            "integrity": "sha512-UbLultRCk46WddeA0Cly4hoRhzBJUiLgbIEViXlgOvV54LbsppClDkMLoCevUUBHoiNdMX2NuiSgURAEXgCZdw==",
             "dev": true,
             "dependencies": {
                 "commander": "^6.1.0",
             }
         },
         "ovsx": {
-            "version": "0.5.1",
-            "resolved": "https://registry.npmjs.org/ovsx/-/ovsx-0.5.1.tgz",
-            "integrity": "sha512-3OWq0l7DuVHi2bd2aQe5+QVQlFIqvrcw3/2vGXL404L6Tr+R4QHtzfnYYghv8CCa85xJHjU0RhcaC7pyXkAUbg==",
+            "version": "0.5.2",
+            "resolved": "https://registry.npmjs.org/ovsx/-/ovsx-0.5.2.tgz",
+            "integrity": "sha512-UbLultRCk46WddeA0Cly4hoRhzBJUiLgbIEViXlgOvV54LbsppClDkMLoCevUUBHoiNdMX2NuiSgURAEXgCZdw==",
             "dev": true,
             "requires": {
                 "commander": "^6.1.0",
index 6771cad28a792650729ef68041ab0c22a001b370..1a97a9c0893752f5ddfe357086ca0c8326ac61db 100644 (file)
@@ -49,7 +49,7 @@
         "esbuild": "^0.14.48",
         "eslint": "^8.19.0",
         "eslint-config-prettier": "^8.5.0",
-        "ovsx": "^0.5.1",
+        "ovsx": "^0.5.2",
         "prettier": "^2.7.1",
         "tslib": "^2.4.0",
         "typescript": "^4.7.4",
             {
                 "command": "rust-analyzer.syntaxTree",
                 "title": "Show Syntax Tree",
-                "category": "rust-analyzer"
+                "category": "rust-analyzer (debug command)"
             },
             {
                 "command": "rust-analyzer.viewHir",
                 "title": "View Hir",
-                "category": "rust-analyzer"
+                "category": "rust-analyzer (debug command)"
             },
             {
                 "command": "rust-analyzer.viewFileText",
                 "title": "View File Text (as seen by the server)",
-                "category": "rust-analyzer"
+                "category": "rust-analyzer (debug command)"
             },
             {
                 "command": "rust-analyzer.viewItemTree",
                 "title": "Debug ItemTree",
-                "category": "rust-analyzer"
+                "category": "rust-analyzer (debug command)"
+            },
+            {
+                "command": "rust-analyzer.shuffleCrateGraph",
+                "title": "Shuffle Crate Graph",
+                "category": "rust-analyzer (debug command)"
+            },
+            {
+                "command": "rust-analyzer.memoryUsage",
+                "title": "Memory Usage (Clears Database)",
+                "category": "rust-analyzer (debug command)"
             },
             {
                 "command": "rust-analyzer.viewCrateGraph",
                 "title": "Status",
                 "category": "rust-analyzer"
             },
-            {
-                "command": "rust-analyzer.memoryUsage",
-                "title": "Memory Usage (Clears Database)",
-                "category": "rust-analyzer"
-            },
-            {
-                "command": "rust-analyzer.shuffleCrateGraph",
-                "title": "Shuffle Crate Graph",
-                "category": "rust-analyzer"
-            },
             {
                 "command": "rust-analyzer.reloadWorkspace",
                 "title": "Reload workspace",
                     "type": "boolean"
                 },
                 "$generated-start": {},
+                "rust-analyzer.assist.emitMustUse": {
+                    "markdownDescription": "Whether to insert #[must_use] when generating `as_` methods\nfor enum variants.",
+                    "default": false,
+                    "type": "boolean"
+                },
                 "rust-analyzer.assist.expressionFillDefault": {
                     "markdownDescription": "Placeholder expression to use for missing expressions in assists.",
                     "default": "todo",
index fa0824ac53c0a9c130636512c0271fc3f0e9c0e6..a910e012b73499449e8b9f37077a9030f0fc7a05 100644 (file)
@@ -1 +1,11 @@
 [assign]
+
+[shortcut]
+
+[relabel]
+allow-unauthenticated = [
+    "S-*",
+]
+
+[autolabel."S-waiting-on-review"]
+new_pr = true
index 70d5f94472f6b598829a7256a47e95c642a0d2c6..d40d9a3cb542abab7c22f30ae0a24aa32336f05d 100644 (file)
@@ -149,6 +149,7 @@ async function main(argv) {
         // This is more convenient that setting fields one by one.
         let args = [
             "--variable", "DOC_PATH", opts["doc_folder"], "--enable-fail-on-js-error",
+            "--allow-file-access-from-files",
         ];
         if (opts["debug"]) {
             debug = true;
index 3105882e2d308085a6e0f8ab2269e47594a0d8b2..7750df0fff3afb124e133f245d22e8dbf635ee44 100644 (file)
@@ -399,6 +399,7 @@ fn needs_space_after_range(rhs: &ast::Expr) -> bool {
             }
         }
         ast::ExprKind::Underscore => Some("_".to_owned()),
+        ast::ExprKind::IncludedBytes(..) => unreachable!(),
         ast::ExprKind::Err => None,
     };
 
index cd852855602e867ad5027be306810cdb69adb3cd..c47b3b314dd4b31873405c3875aec1b698881032 100644 (file)
@@ -496,6 +496,7 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr
         | ast::ExprKind::Continue(..)
         | ast::ExprKind::Err
         | ast::ExprKind::Field(..)
+        | ast::ExprKind::IncludedBytes(..)
         | ast::ExprKind::InlineAsm(..)
         | ast::ExprKind::Let(..)
         | ast::ExprKind::Path(..)
index aee36f061c5d166f9edf592149767b2da5c3a028..21c6a96747eefc1d25a793041cbf01e857364251 100644 (file)
@@ -9,8 +9,8 @@
 
 const ENTRY_LIMIT: usize = 1000;
 // FIXME: The following limits should be reduced eventually.
-const ROOT_ENTRY_LIMIT: usize = 941;
-const ISSUES_ENTRY_LIMIT: usize = 2117;
+const ROOT_ENTRY_LIMIT: usize = 939;
+const ISSUES_ENTRY_LIMIT: usize = 2085;
 
 fn check_entries(path: &Path, bad: &mut bool) {
     for dir in Walk::new(&path.join("test/ui")) {
index 202f9cad57a4376b33db31818a38208386cbeb6d..985e065652d620b021cc1224a45fead4601336b2 100644 (file)
@@ -12,6 +12,7 @@ allow-unauthenticated = [
     "T-*",
     "WG-*",
     "const-hack",
+    "llvm-main",
     "needs-fcp",
     "relnotes",
     "requires-nightly",
@@ -181,6 +182,7 @@ trigger_files = [
     "x.ps1",
     "src/bootstrap",
     "src/tools/rust-installer",
+    "src/tools/x",
     "configure",
     "Cargo.toml",
     "Cargo.lock",
@@ -572,6 +574,7 @@ fallback = [
 "/src/llvm-project" =                        ["@cuviper"]
 "/src/rustdoc-json-types" =                  ["rustdoc"]
 "/src/stage0.json" =                         ["bootstrap"]
+"/src/test/ui" =                             ["compiler"]
 "/src/tools/cargo" =                         ["@ehuss", "@joshtriplett"]
 "/src/tools/compiletest" =                   ["bootstrap"]
 "/src/tools/linkchecker" =                   ["@ehuss"]
@@ -581,3 +584,4 @@ fallback = [
 "/src/tools/rustdoc-js" =                    ["rustdoc"]
 "/src/tools/rustdoc-themes" =                ["rustdoc"]
 "/src/tools/tidy" =                          ["bootstrap"]
+"/src/tools/x" =                             ["bootstrap"]